Merge "Add native Thermal Throttling API to libandroid."
diff --git a/Android.bp b/Android.bp
index df71601..4bc2e9d2 100644
--- a/Android.bp
+++ b/Android.bp
@@ -327,7 +327,6 @@
             "rs/java",
             "sax/java",
             "telecomm/java",
-            "wifi/aidl-export",
         ],
     },
 }
@@ -393,7 +392,7 @@
 
     exclude_srcs: [
         // See comment on framework-atb-backward-compatibility module below
-        "core/java/android/content/pm/parsing/library/AndroidTestBaseUpdater.java",
+        "core/java/android/content/pm/AndroidTestBaseUpdater.java",
     ],
 
     sdk_version: "core_platform",
@@ -609,7 +608,7 @@
     installable: true,
     libs: ["app-compat-annotations"],
     srcs: [
-        "core/java/android/content/pm/parsing/library/AndroidTestBaseUpdater.java",
+        "core/java/android/content/pm/AndroidTestBaseUpdater.java",
     ],
 }
 
@@ -1042,22 +1041,6 @@
     },
 }
 
-
-subdirs = [
-    "cmds/*",
-    "core/*",
-    "libs/*",
-    "media/*",
-    "proto",
-    "tools/*",
-    "native/android",
-    "native/graphics/jni",
-]
-
-optional_subdirs = [
-    "core/tests/utiltests/jni",
-]
-
 // TODO(b/77285514): remove this once the last few hidl interfaces have been
 // updated to use hwbinder.stubs.
 java_library {
@@ -1117,13 +1100,6 @@
 }
 
 filegroup {
-    name: "framework-annotation-nonnull-srcs",
-    srcs: [
-        "core/java/android/annotation/NonNull.java",
-    ],
-}
-
-filegroup {
     name: "framework-media-annotation-srcs",
     srcs: [
         ":framework-annotations",
diff --git a/StubLibraries.bp b/StubLibraries.bp
index 4616ced..7f23df7 100644
--- a/StubLibraries.bp
+++ b/StubLibraries.bp
@@ -49,7 +49,6 @@
         ":opt-net-voip-srcs",
         ":core-current-stubs-source",
         ":core_public_api_files",
-        ":ike-api-srcs",
     ],
     // TODO(b/147699819): remove below aidl includes.
     aidl: {
diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java b/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java
index 1cc1c5f..18b1108 100644
--- a/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java
+++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java
@@ -96,10 +96,12 @@
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.nio.charset.StandardCharsets;
+import java.security.SecureRandom;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Objects;
+import java.util.Random;
 import java.util.Set;
 
 /**
@@ -122,8 +124,15 @@
 
     // Contains all ids that are currently in use.
     @GuardedBy("mBlobsLock")
+    private final ArraySet<Long> mActiveBlobIds = new ArraySet<>();
+    // Contains all ids that are currently in use and those that were in use but got deleted in the
+    // current boot session.
+    @GuardedBy("mBlobsLock")
     private final ArraySet<Long> mKnownBlobIds = new ArraySet<>();
 
+    // Random number generator for new session ids.
+    private final Random mRandom = new SecureRandom();
+
     private final Context mContext;
     private final Handler mHandler;
     private final Injector mInjector;
@@ -181,7 +190,16 @@
 
     @GuardedBy("mBlobsLock")
     private long generateNextSessionIdLocked() {
-        return ++mCurrentMaxSessionId;
+        // Logic borrowed from PackageInstallerService.
+        int n = 0;
+        long sessionId;
+        do {
+            sessionId = Math.abs(mRandom.nextLong());
+            if (mKnownBlobIds.indexOf(sessionId) < 0 && sessionId != 0) {
+                return sessionId;
+            }
+        } while (n++ < 32);
+        throw new IllegalStateException("Failed to allocate session ID");
     }
 
     private void registerReceivers() {
@@ -228,15 +246,22 @@
     }
 
     @VisibleForTesting
-    void addKnownIdsForTest(long... knownIds) {
+    void addActiveIdsForTest(long... activeIds) {
         synchronized (mBlobsLock) {
-            for (long id : knownIds) {
-                mKnownBlobIds.add(id);
+            for (long id : activeIds) {
+                addActiveBlobIdLocked(id);
             }
         }
     }
 
     @VisibleForTesting
+    Set<Long> getActiveIdsForTest() {
+        synchronized (mBlobsLock) {
+            return mActiveBlobIds;
+        }
+    }
+
+    @VisibleForTesting
     Set<Long> getKnownIdsForTest() {
         synchronized (mBlobsLock) {
             return mKnownBlobIds;
@@ -246,7 +271,7 @@
     @GuardedBy("mBlobsLock")
     private void addSessionForUserLocked(BlobStoreSession session, int userId) {
         getUserSessionsLocked(userId).put(session.getSessionId(), session);
-        mKnownBlobIds.add(session.getSessionId());
+        addActiveBlobIdLocked(session.getSessionId());
     }
 
     @GuardedBy("mBlobsLock")
@@ -258,7 +283,13 @@
     private void addBlobForUserLocked(BlobMetadata blobMetadata,
             ArrayMap<BlobHandle, BlobMetadata> userBlobs) {
         userBlobs.put(blobMetadata.getBlobHandle(), blobMetadata);
-        mKnownBlobIds.add(blobMetadata.getBlobId());
+        addActiveBlobIdLocked(blobMetadata.getBlobId());
+    }
+
+    @GuardedBy("mBlobsLock")
+    private void addActiveBlobIdLocked(long id) {
+        mActiveBlobIds.add(id);
+        mKnownBlobIds.add(id);
     }
 
     private long createSessionInternal(BlobHandle blobHandle,
@@ -392,7 +423,7 @@
                 synchronized (mBlobsLock) {
                     getUserSessionsLocked(UserHandle.getUserId(session.getOwnerUid()))
                             .remove(session.getSessionId());
-                    mKnownBlobIds.remove(session.getSessionId());
+                    mActiveBlobIds.remove(session.getSessionId());
                     if (LOGV) {
                         Slog.v(TAG, "Session is invalid; deleted " + session);
                     }
@@ -491,6 +522,9 @@
         if (sessionsIndexFile == null) {
             Slog.wtf(TAG, "Error creating sessions index file");
             return;
+        } else if (!sessionsIndexFile.exists()) {
+            Slog.w(TAG, "Sessions index file not available: " + sessionsIndexFile.getBaseFile());
+            return;
         }
 
         mSessions.clear();
@@ -580,6 +614,9 @@
         if (blobsIndexFile == null) {
             Slog.wtf(TAG, "Error creating blobs index file");
             return;
+        } else if (!blobsIndexFile.exists()) {
+            Slog.w(TAG, "Blobs index file not available: " + blobsIndexFile.getBaseFile());
+            return;
         }
 
         mBlobsMap.clear();
@@ -704,7 +741,7 @@
                 if (session.getOwnerUid() == uid
                         && session.getOwnerPackageName().equals(packageName)) {
                     session.getSessionFile().delete();
-                    mKnownBlobIds.remove(session.getSessionId());
+                    mActiveBlobIds.remove(session.getSessionId());
                     indicesToRemove.add(i);
                 }
             }
@@ -724,7 +761,7 @@
                 // Delete the blob if it doesn't have any active leases.
                 if (!blobMetadata.hasLeases()) {
                     blobMetadata.getBlobFile().delete();
-                    mKnownBlobIds.remove(blobMetadata.getBlobId());
+                    mActiveBlobIds.remove(blobMetadata.getBlobId());
                     indicesToRemove.add(i);
                 }
             }
@@ -747,7 +784,7 @@
                 for (int i = 0, count = userSessions.size(); i < count; ++i) {
                     final BlobStoreSession session = userSessions.valueAt(i);
                     session.getSessionFile().delete();
-                    mKnownBlobIds.remove(session.getSessionId());
+                    mActiveBlobIds.remove(session.getSessionId());
                 }
             }
 
@@ -757,7 +794,7 @@
                 for (int i = 0, count = userBlobs.size(); i < count; ++i) {
                     final BlobMetadata blobMetadata = userBlobs.valueAt(i);
                     blobMetadata.getBlobFile().delete();
-                    mKnownBlobIds.remove(blobMetadata.getBlobId());
+                    mActiveBlobIds.remove(blobMetadata.getBlobId());
                 }
             }
             if (LOGV) {
@@ -777,7 +814,7 @@
             for (File file : blobsDir.listFiles()) {
                 try {
                     final long id = Long.parseLong(file.getName());
-                    if (mKnownBlobIds.indexOf(id) < 0) {
+                    if (mActiveBlobIds.indexOf(id) < 0) {
                         filesToDelete.add(file);
                         deletedBlobIds.add(id);
                     }
@@ -812,7 +849,7 @@
 
                 if (shouldRemove) {
                     blobMetadata.getBlobFile().delete();
-                    mKnownBlobIds.remove(blobMetadata.getBlobId());
+                    mActiveBlobIds.remove(blobMetadata.getBlobId());
                     deletedBlobIds.add(blobMetadata.getBlobId());
                 }
                 return shouldRemove;
@@ -821,12 +858,9 @@
         writeBlobsInfoAsync();
 
         // Cleanup any stale sessions.
-        final ArrayList<Integer> indicesToRemove = new ArrayList<>();
         for (int i = 0, userCount = mSessions.size(); i < userCount; ++i) {
             final LongSparseArray<BlobStoreSession> userSessions = mSessions.valueAt(i);
-            indicesToRemove.clear();
-            for (int j = 0, sessionsCount = userSessions.size(); j < sessionsCount; ++j) {
-                final BlobStoreSession blobStoreSession = userSessions.valueAt(j);
+            userSessions.removeIf((sessionId, blobStoreSession) -> {
                 boolean shouldRemove = false;
 
                 // Cleanup sessions which haven't been modified in a while.
@@ -842,14 +876,11 @@
 
                 if (shouldRemove) {
                     blobStoreSession.getSessionFile().delete();
-                    mKnownBlobIds.remove(blobStoreSession.getSessionId());
-                    indicesToRemove.add(j);
+                    mActiveBlobIds.remove(blobStoreSession.getSessionId());
                     deletedBlobIds.add(blobStoreSession.getSessionId());
                 }
-            }
-            for (int j = 0; j < indicesToRemove.size(); ++j) {
-                userSessions.removeAt(indicesToRemove.get(j));
-            }
+                return shouldRemove;
+            });
         }
         if (LOGV) {
             Slog.v(TAG, "Completed idle maintenance; deleted "
@@ -889,7 +920,7 @@
             }
             blobMetadata.getBlobFile().delete();
             userBlobs.remove(blobHandle);
-            mKnownBlobIds.remove(blobMetadata.getBlobId());
+            mActiveBlobIds.remove(blobMetadata.getBlobId());
             writeBlobsInfoAsync();
         }
     }
diff --git a/apex/jobscheduler/framework/java/android/app/job/JobParameters.java b/apex/jobscheduler/framework/java/android/app/job/JobParameters.java
index b96161a..4c98b5f 100644
--- a/apex/jobscheduler/framework/java/android/app/job/JobParameters.java
+++ b/apex/jobscheduler/framework/java/android/app/job/JobParameters.java
@@ -77,11 +77,11 @@
 
     /**
      * @hide
-     * @deprecated use {@link #getReasonCodeDescription(int)}
      */
-    @Deprecated
-    public static String getReasonName(int reason) {
-        switch (reason) {
+    // TODO(142420609): make it @SystemApi for mainline
+    @NonNull
+    public static String getReasonCodeDescription(int reasonCode) {
+        switch (reasonCode) {
             case REASON_CANCELED: return "canceled";
             case REASON_CONSTRAINTS_NOT_SATISFIED: return "constraints";
             case REASON_PREEMPT: return "preempt";
@@ -89,7 +89,7 @@
             case REASON_DEVICE_IDLE: return "device_idle";
             case REASON_DEVICE_THERMAL: return "thermal";
             case REASON_RESTRAINED: return "restrained";
-            default: return "unknown:" + reason;
+            default: return "unknown:" + reasonCode;
         }
     }
 
@@ -100,13 +100,6 @@
         return JOB_STOP_REASON_CODES;
     }
 
-    /** @hide */
-    // @SystemApi TODO make it a system api for mainline
-    @NonNull
-    public static String getReasonCodeDescription(int reasonCode) {
-        return getReasonName(reasonCode);
-    }
-
     @UnsupportedAppUsage
     private final int jobId;
     private final PersistableBundle extras;
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobPackageTracker.java b/apex/jobscheduler/service/java/com/android/server/job/JobPackageTracker.java
index e28e5bd..d050347 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobPackageTracker.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobPackageTracker.java
@@ -359,7 +359,8 @@
                             }
                             pw.print(pe.stopReasons.valueAt(k));
                             pw.print("x ");
-                            pw.print(JobParameters.getReasonName(pe.stopReasons.keyAt(k)));
+                            pw.print(JobParameters
+                                    .getReasonCodeDescription(pe.stopReasons.keyAt(k)));
                         }
                         pw.println();
                     }
@@ -606,8 +607,9 @@
                 if (reason != null) {
                     pw.print(mEventReasons[index]);
                 } else {
-                    pw.print(JobParameters.getReasonName((mEventCmds[index] & EVENT_STOP_REASON_MASK)
-                            >> EVENT_STOP_REASON_SHIFT));
+                    pw.print(JobParameters.getReasonCodeDescription(
+                            (mEventCmds[index] & EVENT_STOP_REASON_MASK)
+                                    >> EVENT_STOP_REASON_SHIFT));
                 }
             }
             pw.println();
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
index ff7944d..c1e529f 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -1963,7 +1963,7 @@
                 if (restriction != null) {
                     final int reason = restriction.getReason();
                     serviceContext.cancelExecutingJobLocked(reason,
-                            "restricted due to " + JobParameters.getReasonName(reason));
+                            "restricted due to " + JobParameters.getReasonCodeDescription(reason));
                 }
             }
         }
@@ -3110,7 +3110,7 @@
                             final JobRestriction restriction = mJobRestrictions.get(i);
                             if (restriction.isJobRestricted(job)) {
                                 final int reason = restriction.getReason();
-                                pw.write(" " + JobParameters.getReasonName(reason) + "[" + reason + "]");
+                                pw.print(" " + JobParameters.getReasonCodeDescription(reason));
                             }
                         }
                     } else {
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
index 789f20b..b63cc19 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
@@ -39,6 +39,7 @@
 import android.util.TimeUtils;
 import android.util.proto.ProtoOutputStream;
 
+import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.FrameworkStatsLog;
 import com.android.server.LocalServices;
 import com.android.server.job.GrantedUriPermissions;
@@ -97,6 +98,15 @@
                     | CONSTRAINT_IDLE;
 
     /**
+     * Standard media URIs that contain the media files that might be important to the user.
+     * @see #mHasMediaBackupExemption
+     */
+    private static final Uri[] MEDIA_URIS_FOR_STANDBY_EXEMPTION = {
+            MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
+            MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
+    };
+
+    /**
      * The constraints that we want to log to statsd.
      *
      * Constraints that can be inferred from other atoms have been excluded to avoid logging too
@@ -441,13 +451,13 @@
         if (latestRunTimeElapsedMillis != NO_LATEST_RUNTIME) {
             requiredConstraints |= CONSTRAINT_DEADLINE;
         }
-        boolean mediaOnly = false;
+        boolean exemptedMediaUrisOnly = false;
         if (job.getTriggerContentUris() != null) {
             requiredConstraints |= CONSTRAINT_CONTENT_TRIGGER;
-            mediaOnly = true;
+            exemptedMediaUrisOnly = true;
             for (JobInfo.TriggerContentUri uri : job.getTriggerContentUris()) {
-                if (!MediaStore.AUTHORITY.equals(uri.getUri().getAuthority())) {
-                    mediaOnly = false;
+                if (!ArrayUtils.contains(MEDIA_URIS_FOR_STANDBY_EXEMPTION, uri.getUri())) {
+                    exemptedMediaUrisOnly = false;
                     break;
                 }
             }
@@ -475,8 +485,8 @@
             job.getRequiredNetwork().networkCapabilities.setSingleUid(this.sourceUid);
         }
         final JobSchedulerInternal jsi = LocalServices.getService(JobSchedulerInternal.class);
-        mHasMediaBackupExemption = !job.hasLateConstraint() && mediaOnly && requiresNetwork
-                && this.sourcePackageName.equals(jsi.getMediaBackupPackage());
+        mHasMediaBackupExemption = !job.hasLateConstraint() && exemptedMediaUrisOnly
+                && requiresNetwork && this.sourcePackageName.equals(jsi.getMediaBackupPackage());
     }
 
     /** Copy constructor: used specifically when cloning JobStatus objects for persistence,
diff --git a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
index bf61eb4..a4ab31d 100644
--- a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
+++ b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
@@ -65,6 +65,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.ApplicationInfo;
+import android.content.pm.CrossProfileAppsInternal;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManagerInternal;
@@ -283,6 +284,12 @@
      * start is the first usage of the app
      */
     long mInitialForegroundServiceStartTimeoutMillis;
+    /**
+     * User usage that would elevate an app's standby bucket will also elevate the standby bucket of
+     * cross profile connected apps. Explicit standby bucket setting via
+     * {@link #setAppStandbyBucket(String, int, int, int, int)} will not be propagated.
+     */
+    boolean mLinkCrossProfileApps;
 
     private volatile boolean mAppIdleEnabled;
     private boolean mIsCharging;
@@ -445,10 +452,12 @@
                     continue;
                 }
                 if (!packageName.equals(providerPkgName)) {
+                    final List<UserHandle> linkedProfiles = getCrossProfileTargets(packageName,
+                            userId);
                     synchronized (mAppIdleLock) {
-                        reportNoninteractiveUsageLocked(packageName, userId, STANDBY_BUCKET_ACTIVE,
-                                REASON_SUB_USAGE_SYNC_ADAPTER, elapsedRealtime,
-                                mSyncAdapterTimeoutMillis);
+                        reportNoninteractiveUsageCrossUserLocked(packageName, userId,
+                                STANDBY_BUCKET_ACTIVE, REASON_SUB_USAGE_SYNC_ADAPTER,
+                                elapsedRealtime, mSyncAdapterTimeoutMillis, linkedProfiles);
                     }
                 }
             } catch (PackageManager.NameNotFoundException e) {
@@ -477,10 +486,10 @@
         }
 
         final long elapsedRealtime = mInjector.elapsedRealtime();
-
+        final List<UserHandle> linkedProfiles = getCrossProfileTargets(packageName, userId);
         synchronized (mAppIdleLock) {
-            reportNoninteractiveUsageLocked(packageName, userId, bucketToPromote,
-                    usageReason, elapsedRealtime, durationMillis);
+            reportNoninteractiveUsageCrossUserLocked(packageName, userId, bucketToPromote,
+                    usageReason, elapsedRealtime, durationMillis, linkedProfiles);
         }
     }
 
@@ -492,10 +501,11 @@
             final int currentBucket =
                     mAppIdleHistory.getAppStandbyBucket(packageName, userId, elapsedRealtime);
             if (currentBucket == STANDBY_BUCKET_NEVER) {
+                final List<UserHandle> linkedProfiles = getCrossProfileTargets(packageName, userId);
                 // Bring the app out of the never bucket
-                reportNoninteractiveUsageLocked(packageName, userId, STANDBY_BUCKET_WORKING_SET,
-                        REASON_SUB_USAGE_UNEXEMPTED_SYNC_SCHEDULED, elapsedRealtime,
-                        mUnexemptedSyncScheduledTimeoutMillis);
+                reportNoninteractiveUsageCrossUserLocked(packageName, userId,
+                        STANDBY_BUCKET_WORKING_SET, REASON_SUB_USAGE_UNEXEMPTED_SYNC_SCHEDULED,
+                        elapsedRealtime, mUnexemptedSyncScheduledTimeoutMillis, linkedProfiles);
             }
         }
     }
@@ -504,14 +514,39 @@
         if (!mAppIdleEnabled) return;
 
         final long elapsedRealtime = mInjector.elapsedRealtime();
-
+        final List<UserHandle> linkedProfiles = getCrossProfileTargets(packageName, userId);
         synchronized (mAppIdleLock) {
-            reportNoninteractiveUsageLocked(packageName, userId, STANDBY_BUCKET_ACTIVE,
+            reportNoninteractiveUsageCrossUserLocked(packageName, userId, STANDBY_BUCKET_ACTIVE,
                     REASON_SUB_USAGE_EXEMPTED_SYNC_START, elapsedRealtime,
-                    mExemptedSyncStartTimeoutMillis);
+                    mExemptedSyncStartTimeoutMillis, linkedProfiles);
         }
     }
 
+    /**
+     * Helper method to report indirect user usage of an app and handle reporting the usage
+     * against cross profile connected apps. <br>
+     * Use {@link #reportNoninteractiveUsageLocked(String, int, int, int, long, long)} if
+     * cross profile connected apps do not need to be handled.
+     */
+    private void reportNoninteractiveUsageCrossUserLocked(String packageName, int userId,
+            int bucket, int subReason, long elapsedRealtime, long nextCheckDelay,
+            List<UserHandle> otherProfiles) {
+        reportNoninteractiveUsageLocked(packageName, userId, bucket, subReason, elapsedRealtime,
+                nextCheckDelay);
+        final int size = otherProfiles.size();
+        for (int profileIndex = 0; profileIndex < size; profileIndex++) {
+            final int otherUserId = otherProfiles.get(profileIndex).getIdentifier();
+            reportNoninteractiveUsageLocked(packageName, otherUserId, bucket, subReason,
+                    elapsedRealtime, nextCheckDelay);
+        }
+    }
+
+    /**
+     * Helper method to report indirect user usage of an app. <br>
+     * Use
+     * {@link #reportNoninteractiveUsageCrossUserLocked(String, int, int, int, long, long, List)}
+     * if cross profile connected apps need to be handled.
+     */
     private void reportNoninteractiveUsageLocked(String packageName, int userId, int bucket,
             int subReason, long elapsedRealtime, long nextCheckDelay) {
         final AppUsageHistory appUsage = mAppIdleHistory.reportUsage(packageName, userId, bucket,
@@ -766,8 +801,16 @@
                 || eventType == UsageEvents.Event.SLICE_PINNED
                 || eventType == UsageEvents.Event.SLICE_PINNED_PRIV
                 || eventType == UsageEvents.Event.FOREGROUND_SERVICE_START)) {
+            final String pkg = event.getPackageName();
+            final List<UserHandle> linkedProfiles = getCrossProfileTargets(pkg, userId);
             synchronized (mAppIdleLock) {
-                reportEventLocked(event.getPackageName(), eventType, elapsedRealtime, userId);
+                reportEventLocked(pkg, eventType, elapsedRealtime, userId);
+
+                final int size = linkedProfiles.size();
+                for (int profileIndex = 0; profileIndex < size; profileIndex++) {
+                    final int linkedUserId = linkedProfiles.get(profileIndex).getIdentifier();
+                    reportEventLocked(pkg, eventType, elapsedRealtime, linkedUserId);
+                }
             }
         }
     }
@@ -826,6 +869,16 @@
         }
     }
 
+    /**
+     * Note: don't call this with the lock held since it makes calls to other system services.
+     */
+    private @NonNull List<UserHandle> getCrossProfileTargets(String pkg, int userId) {
+        synchronized (mAppIdleLock) {
+            if (!mLinkCrossProfileApps) return Collections.emptyList();
+        }
+        return mInjector.getValidCrossProfileTargets(pkg, userId);
+    }
+
     private int usageEventToSubReason(int eventType) {
         switch (eventType) {
             case UsageEvents.Event.ACTIVITY_RESUMED: return REASON_SUB_USAGE_MOVE_TO_FOREGROUND;
@@ -1589,6 +1642,7 @@
         private PackageManagerInternal mPackageManagerInternal;
         private DisplayManager mDisplayManager;
         private PowerManager mPowerManager;
+        private CrossProfileAppsInternal mCrossProfileAppsInternal;
         int mBootPhase;
         /**
          * The minimum amount of time required since the last user interaction before an app can be
@@ -1620,6 +1674,8 @@
                         Context.DISPLAY_SERVICE);
                 mPowerManager = mContext.getSystemService(PowerManager.class);
                 mBatteryManager = mContext.getSystemService(BatteryManager.class);
+                mCrossProfileAppsInternal = LocalServices.getService(
+                        CrossProfileAppsInternal.class);
 
                 final ActivityManager activityManager =
                         (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
@@ -1727,6 +1783,17 @@
         public boolean isDeviceIdleMode() {
             return mPowerManager.isDeviceIdleMode();
         }
+
+        public List<UserHandle> getValidCrossProfileTargets(String pkg, int userId) {
+            final int uid = mPackageManagerInternal.getPackageUidInternal(pkg, 0, userId);
+            if (uid < 0
+                    || !mPackageManagerInternal.getPackage(uid).isCrossProfile()
+                    || !mCrossProfileAppsInternal
+                            .verifyUidHasInteractAcrossProfilePermission(pkg, uid)) {
+                return Collections.emptyList();
+            }
+            return mCrossProfileAppsInternal.getTargetUserProfiles(pkg, userId);
+        }
     }
 
     class AppStandbyHandler extends Handler {
@@ -1857,6 +1924,8 @@
                 "initial_foreground_service_start_duration";
         private static final String KEY_AUTO_RESTRICTED_BUCKET_DELAY_MS =
                 "auto_restricted_bucket_delay_ms";
+        private static final String KEY_CROSS_PROFILE_APPS_SHARE_STANDBY_BUCKETS =
+                "cross_profile_apps_share_standby_buckets";
         public static final long DEFAULT_STRONG_USAGE_TIMEOUT = 1 * ONE_HOUR;
         public static final long DEFAULT_NOTIFICATION_TIMEOUT = 12 * ONE_HOUR;
         public static final long DEFAULT_SYSTEM_UPDATE_TIMEOUT = 2 * ONE_HOUR;
@@ -1868,6 +1937,7 @@
         public static final long DEFAULT_UNEXEMPTED_SYNC_SCHEDULED_TIMEOUT = 10 * ONE_MINUTE;
         public static final long DEFAULT_INITIAL_FOREGROUND_SERVICE_START_TIMEOUT = 30 * ONE_MINUTE;
         public static final long DEFAULT_AUTO_RESTRICTED_BUCKET_DELAY_MS = ONE_DAY;
+        public static final boolean DEFAULT_CROSS_PROFILE_APPS_SHARE_STANDBY_BUCKETS = true;
 
         private final KeyValueListParser mParser = new KeyValueListParser(',');
 
@@ -1973,6 +2043,10 @@
                         mParser.getDurationMillis(KEY_AUTO_RESTRICTED_BUCKET_DELAY_MS,
                                 COMPRESS_TIME
                                         ? ONE_MINUTE : DEFAULT_AUTO_RESTRICTED_BUCKET_DELAY_MS));
+
+                mLinkCrossProfileApps = mParser.getBoolean(
+                        KEY_CROSS_PROFILE_APPS_SHARE_STANDBY_BUCKETS,
+                        DEFAULT_CROSS_PROFILE_APPS_SHARE_STANDBY_BUCKETS);
             }
 
             // Check if app_idle_enabled has changed. Do this after getting the rest of the settings
diff --git a/apex/media/framework/java/android/media/MediaParser.java b/apex/media/framework/java/android/media/MediaParser.java
index 7d18578..11d3a68 100644
--- a/apex/media/framework/java/android/media/MediaParser.java
+++ b/apex/media/framework/java/android/media/MediaParser.java
@@ -56,6 +56,7 @@
 import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
@@ -375,13 +376,13 @@
     }
 
     /**
-     * Thrown if all extractors implementations provided to {@link #create} failed to sniff the
-     * input content.
+     * Thrown if all parser implementations provided to {@link #create} failed to sniff the input
+     * content.
      */
     public static final class UnrecognizedInputFormatException extends IOException {
 
         /**
-         * Creates a new instance which signals that the extractors with the given names failed to
+         * Creates a new instance which signals that the parsers with the given names failed to
          * parse the input.
          */
         @NonNull
@@ -389,7 +390,7 @@
         private static UnrecognizedInputFormatException createForExtractors(
                 @NonNull String... extractorNames) {
             StringBuilder builder = new StringBuilder();
-            builder.append("None of the available extractors ( ");
+            builder.append("None of the available parsers ( ");
             builder.append(extractorNames[0]);
             for (int i = 1; i < extractorNames.length; i++) {
                 builder.append(", ");
@@ -404,17 +405,149 @@
         }
     }
 
+    // Public constants.
+
+    /**
+     * Sets whether constant bitrate seeking should be enabled for exo.AdtsParser. {@code boolean}
+     * expected. Default value is {@code false}.
+     */
+    public static final String PARAMETER_ADTS_ENABLE_CBR_SEEKING =
+            "exo.AdtsParser.enableCbrSeeking";
+    /**
+     * Sets whether constant bitrate seeking should be enabled for exo.AmrParser. {@code boolean}
+     * expected. Default value is {@code false}.
+     */
+    public static final String PARAMETER_AMR_ENABLE_CBR_SEEKING = "exo.AmrParser.enableCbrSeeking";
+    /**
+     * Sets whether the ID3 track should be disabled for exo.FlacParser. {@code boolean} expected.
+     * Default value is {@code false}.
+     */
+    public static final String PARAMETER_FLAC_DISABLE_ID3 = "exo.FlacParser.disableId3";
+    /**
+     * Sets whether exo.FragmentedMp4Parser should ignore edit lists. {@code boolean} expected.
+     * Default value is {@code false}.
+     */
+    public static final String PARAMETER_FMP4_IGNORE_EDIT_LISTS =
+            "exo.FragmentedMp4Parser.ignoreEditLists";
+    /**
+     * Sets whether exo.FragmentedMp4Parser should ignore the tfdt box. {@code boolean} expected.
+     * Default value is {@code false}.
+     */
+    public static final String PARAMETER_FMP4_IGNORE_TFDT_BOX =
+            "exo.FragmentedMp4Parser.ignoreTfdtBox";
+    /**
+     * Sets whether exo.FragmentedMp4Parser should treat all video frames as key frames. {@code
+     * boolean} expected. Default value is {@code false}.
+     */
+    public static final String PARAMETER_FMP4_TREAT_VIDEO_FRAMES_AS_KEYFRAMES =
+            "exo.FragmentedMp4Parser.treatVideoFramesAsKeyframes";
+    /**
+     * Sets whether exo.MatroskaParser should avoid seeking to the cues element. {@code boolean}
+     * expected. Default value is {@code false}.
+     *
+     * <p>If this flag is enabled and the cues element occurs after the first cluster, then the
+     * media is treated as unseekable.
+     */
+    public static final String PARAMETER_MATROSKA_DISABLE_CUES_SEEKING =
+            "exo.MatroskaParser.disableCuesSeeking";
+    /**
+     * Sets whether the ID3 track should be disabled for exo.Mp3Parser. {@code boolean} expected.
+     * Default value is {@code false}.
+     */
+    public static final String PARAMETER_MP3_DISABLE_ID3 = "exo.Mp3Parser.disableId3";
+    /**
+     * Sets whether constant bitrate seeking should be enabled for exo.Mp3Parser. {@code boolean}
+     * expected. Default value is {@code false}.
+     */
+    public static final String PARAMETER_MP3_ENABLE_CBR_SEEKING = "exo.Mp3Parser.enableCbrSeeking";
+    /**
+     * Sets whether exo.Mp3Parser should generate a time-to-byte mapping. {@code boolean} expected.
+     * Default value is {@code false}.
+     *
+     * <p>Enabling this flag may require to scan a significant portion of the file to compute a seek
+     * point. Therefore, it should only be used if:
+     *
+     * <ul>
+     *   <li>the file is small, or
+     *   <li>the bitrate is variable (or the type of bitrate is unknown) and the seeking metadata
+     *       provided in the file is not precise enough (or is not present).
+     * </ul>
+     */
+    public static final String PARAMETER_MP3_ENABLE_INDEX_SEEKING =
+            "exo.Mp3Parser.enableIndexSeeking";
+    /**
+     * Sets whether exo.Mp4Parser should ignore edit lists. {@code boolean} expected. Default value
+     * is {@code false}.
+     */
+    public static final String PARAMETER_MP4_IGNORE_EDIT_LISTS = "exo.Mp4Parser.ignoreEditLists";
+    /**
+     * Sets the operation mode for exo.TsParser. {@code String} expected. Valid values are {@code
+     * "single_pmt"}, {@code "multi_pmt"}, and {@code "hls"}. Default value is {@code "single_pmt"}.
+     *
+     * <p>The operation modes alter the way exo.TsParser behaves so that it can handle certain kinds
+     * of commonly-occurring malformed media.
+     *
+     * <ul>
+     *   <li>{@code "single_pmt"}: Only the first found PMT is parsed. Others are ignored, even if
+     *       more PMTs are declared in the PAT.
+     *   <li>{@code "multi_pmt"}: Behave as described in ISO/IEC 13818-1.
+     *   <li>{@code "hls"}: Enable {@code "single_pmt"} mode, and ignore continuity counters.
+     * </ul>
+     */
+    public static final String PARAMETER_TS_MODE = "exo.TsParser.mode";
+    /**
+     * Sets whether exo.TsParser should treat samples consisting of non-IDR I slices as
+     * synchronization samples (key-frames). {@code boolean} expected. Default value is {@code
+     * false}.
+     */
+    public static final String PARAMETER_TS_ALLOW_NON_IDR_AVC_KEYFRAMES =
+            "exo.TsParser.allowNonIdrAvcKeyframes";
+    /**
+     * Sets whether exo.TsParser should ignore AAC elementary streams. {@code boolean} expected.
+     * Default value is {@code false}.
+     */
+    public static final String PARAMETER_TS_IGNORE_AAC_STREAM = "exo.TsParser.ignoreAacStream";
+    /**
+     * Sets whether exo.TsParser should ignore AVC elementary streams. {@code boolean} expected.
+     * Default value is {@code false}.
+     */
+    public static final String PARAMETER_TS_IGNORE_AVC_STREAM = "exo.TsParser.ignoreAvcStream";
+    /**
+     * Sets whether exo.TsParser should ignore splice information streams. {@code boolean} expected.
+     * Default value is {@code false}.
+     */
+    public static final String PARAMETER_TS_IGNORE_SPLICE_INFO_STREAM =
+            "exo.TsParser.ignoreSpliceInfoStream";
+    /**
+     * Sets whether exo.TsParser should split AVC stream into access units based on slice headers.
+     * {@code boolean} expected. Default value is {@code false}.
+     *
+     * <p>This flag should be left disabled if the stream contains access units delimiters in order
+     * to avoid unnecessary computational costs.
+     */
+    public static final String PARAMETER_TS_DETECT_ACCESS_UNITS =
+            "exo.TsParser.ignoreDetectAccessUnits";
+    /**
+     * Sets whether exo.TsParser should handle HDMV DTS audio streams. {@code boolean} expected.
+     * Default value is {@code false}.
+     *
+     * <p>Enabling this flag will disable the detection of SCTE subtitles.
+     */
+    public static final String PARAMETER_TS_ENABLE_HDMV_DTS_AUDIO_STREAMS =
+            "exo.TsParser.enableHdmvDtsAudioStreams";
+
     // Private constants.
 
     private static final Map<String, ExtractorFactory> EXTRACTOR_FACTORIES_BY_NAME;
+    private static final Map<String, Class> EXPECTED_TYPE_BY_PARAMETER_NAME;
 
     // Instance creation methods.
 
     /**
-     * Creates an instance backed by the extractor with the given {@code name}. The returned
-     * instance will attempt extraction without sniffing the content.
+     * Creates an instance backed by the parser with the given {@code name}. The returned instance
+     * will attempt parsing without sniffing the content.
      *
-     * @param name The name of the extractor that will be associated with the created instance.
+     * @param name The name of the parser that will be associated with the created instance.
      * @param outputConsumer The {@link OutputConsumer} to which track data and samples are pushed.
      * @return A new instance.
      * @throws IllegalArgumentException If an invalid name is provided.
@@ -428,42 +561,43 @@
     }
 
     /**
-     * Creates an instance whose backing extractor will be selected by sniffing the content during
-     * the first {@link #advance} call. Extractor implementations will sniff the content in order of
-     * appearance in {@code extractorNames}.
+     * Creates an instance whose backing parser will be selected by sniffing the content during the
+     * first {@link #advance} call. Parser implementations will sniff the content in order of
+     * appearance in {@code parserNames}.
      *
      * @param outputConsumer The {@link OutputConsumer} to which extracted data is output.
-     * @param extractorNames The names of the extractors to sniff the content with. If empty, a
-     *     default array of names is used.
+     * @param parserNames The names of the parsers to sniff the content with. If empty, a default
+     *     array of names is used.
      * @return A new instance.
      */
     @NonNull
     public static MediaParser create(
-            @NonNull OutputConsumer outputConsumer, @NonNull String... extractorNames) {
-        assertValidNames(extractorNames);
-        if (extractorNames.length == 0) {
-            extractorNames = EXTRACTOR_FACTORIES_BY_NAME.keySet().toArray(new String[0]);
+            @NonNull OutputConsumer outputConsumer, @NonNull String... parserNames) {
+        assertValidNames(parserNames);
+        if (parserNames.length == 0) {
+            parserNames = EXTRACTOR_FACTORIES_BY_NAME.keySet().toArray(new String[0]);
         }
-        return new MediaParser(outputConsumer, /* sniff= */ true, extractorNames);
+        return new MediaParser(outputConsumer, /* sniff= */ true, parserNames);
     }
 
     // Misc static methods.
 
     /**
-     * Returns an immutable list with the names of the extractors that are suitable for container
+     * Returns an immutable list with the names of the parsers that are suitable for container
      * formats with the given {@link MediaFormat}.
      *
      * <p>TODO: List which properties are taken into account. E.g. MimeType.
      */
     @NonNull
-    public static List<String> getExtractorNames(@NonNull MediaFormat mediaFormat) {
+    public static List<String> getParserNames(@NonNull MediaFormat mediaFormat) {
         throw new UnsupportedOperationException();
     }
 
     // Private fields.
 
+    private final Map<String, Object> mParserParameters;
     private final OutputConsumer mOutputConsumer;
-    private final String[] mExtractorNamesPool;
+    private final String[] mParserNamesPool;
     private final PositionHolder mPositionHolder;
     private final InputReadingDataSource mDataSource;
     private final ExtractorInputAdapter mScratchExtractorInputAdapter;
@@ -477,18 +611,63 @@
     // Public methods.
 
     /**
-     * Returns the name of the backing extractor implementation.
+     * Sets parser-specific parameters which allow customizing behavior.
+     *
+     * <p>Must be called before the first call to {@link #advance}.
+     *
+     * @param parameterName The name of the parameter to set. See {@code PARAMETER_*} constants for
+     *     documentation on possible values.
+     * @param value The value to set for the given {@code parameterName}. See {@code PARAMETER_*}
+     *     constants for documentation on the expected types.
+     * @return This instance, for convenience.
+     * @throws IllegalStateException If called after calling {@link #advance} on the same instance.
+     */
+    @NonNull
+    public MediaParser setParameter(@NonNull String parameterName, @NonNull Object value) {
+        if (mExtractor != null) {
+            throw new IllegalStateException(
+                    "setParameters() must be called before the first advance() call.");
+        }
+        Class expectedType = EXPECTED_TYPE_BY_PARAMETER_NAME.get(parameterName);
+        // Ignore parameter names that are not contained in the map, in case the client is passing
+        // a parameter that is being added in a future version of this library.
+        if (expectedType != null && !expectedType.isInstance(value)) {
+            throw new IllegalArgumentException(
+                    parameterName
+                            + " expects a "
+                            + expectedType.getSimpleName()
+                            + " but a "
+                            + value.getClass().getSimpleName()
+                            + " was passed.");
+        }
+        mParserParameters.put(parameterName, value);
+        return this;
+    }
+
+    /**
+     * Returns whether the given {@code parameterName} is supported by this parser.
+     *
+     * @param parameterName The parameter name to check support for. One of the {@code PARAMETER_*}
+     *     constants.
+     * @return Whether the given {@code parameterName} is supported.
+     */
+    public boolean supportsParameter(@NonNull String parameterName) {
+        return EXPECTED_TYPE_BY_PARAMETER_NAME.containsKey(parameterName);
+    }
+
+    /**
+     * Returns the name of the backing parser implementation.
      *
      * <p>If this instance was creating using {@link #createByName}, the provided name is returned.
      * If this instance was created using {@link #create}, this method will return null until the
-     * first call to {@link #advance}, after which the name of the backing extractor implementation
-     * is returned.
+     * first call to {@link #advance}, after which the name of the backing parser implementation is
+     * returned.
      *
-     * @return The name of the backing extractor implementation, or null if the backing extractor
+     * @return The name of the backing parser implementation, or null if the backing parser
      *     implementation has not yet been selected.
      */
     @Nullable
-    public String getExtractorName() {
+    public String getParserName() {
         return mExtractorName;
     }
 
@@ -499,7 +678,7 @@
      * <p>This method will block until some progress has been made.
      *
      * <p>If this instance was created using {@link #create}. the first call to this method will
-     * sniff the content with the extractors with the provided names.
+     * sniff the content with the parsers with the provided names.
      *
      * @param seekableInputReader The {@link SeekableInputReader} from which to obtain the media
      *     container data.
@@ -520,13 +699,15 @@
         }
         mDataSource.mInputReader = seekableInputReader;
 
-        if (mExtractor == null) {
-            for (String extractorName : mExtractorNamesPool) {
-                Extractor extractor =
-                        EXTRACTOR_FACTORIES_BY_NAME.get(extractorName).createInstance();
+        // TODO: Apply parameters when creating extractor instances.
+        if (mExtractorName != null) {
+            mExtractor = EXTRACTOR_FACTORIES_BY_NAME.get(mExtractorName).createInstance();
+        } else if (mExtractor == null) {
+            for (String parserName : mParserNamesPool) {
+                Extractor extractor = EXTRACTOR_FACTORIES_BY_NAME.get(parserName).createInstance();
                 try {
                     if (extractor.sniff(mExtractorInput)) {
-                        mExtractorName = extractorName;
+                        mExtractorName = parserName;
                         mExtractor = extractor;
                         mExtractor.init(new ExtractorOutputAdapter());
                         break;
@@ -540,7 +721,7 @@
                 }
             }
             if (mExtractor == null) {
-                throw UnrecognizedInputFormatException.createForExtractors(mExtractorNamesPool);
+                throw UnrecognizedInputFormatException.createForExtractors(mParserNamesPool);
             }
             return true;
         }
@@ -586,22 +767,22 @@
      * Releases any acquired resources.
      *
      * <p>After calling this method, this instance becomes unusable and no other methods should be
-     * invoked. DESIGN NOTE: Should be removed. There shouldn't be any resource for releasing.
+     * invoked.
      */
     public void release() {
+        // TODO: Dump media metrics here.
         mExtractorInput = null;
         mExtractor = null;
     }
 
     // Private methods.
 
-    private MediaParser(
-            OutputConsumer outputConsumer, boolean sniff, String... extractorNamesPool) {
+    private MediaParser(OutputConsumer outputConsumer, boolean sniff, String... parserNamesPool) {
+        mParserParameters = new HashMap<>();
         mOutputConsumer = outputConsumer;
-        mExtractorNamesPool = extractorNamesPool;
+        mParserNamesPool = parserNamesPool;
         if (!sniff) {
-            mExtractorName = extractorNamesPool[0];
-            mExtractor = EXTRACTOR_FACTORIES_BY_NAME.get(mExtractorName).createInstance();
+            mExtractorName = parserNamesPool[0];
         }
         mPositionHolder = new PositionHolder();
         mDataSource = new InputReadingDataSource();
@@ -921,7 +1102,7 @@
                 throw new IllegalArgumentException(
                         "Invalid extractor name: "
                                 + name
-                                + ". Supported extractors are: "
+                                + ". Supported parsers are: "
                                 + TextUtils.join(", ", EXTRACTOR_FACTORIES_BY_NAME.keySet())
                                 + ".");
             }
@@ -933,20 +1114,42 @@
     static {
         // Using a LinkedHashMap to keep the insertion order when iterating over the keys.
         LinkedHashMap<String, ExtractorFactory> extractorFactoriesByName = new LinkedHashMap<>();
-        extractorFactoriesByName.put("exo.Ac3Extractor", Ac3Extractor::new);
-        extractorFactoriesByName.put("exo.Ac4Extractor", Ac4Extractor::new);
-        extractorFactoriesByName.put("exo.AdtsExtractor", AdtsExtractor::new);
-        extractorFactoriesByName.put("exo.AmrExtractor", AmrExtractor::new);
-        extractorFactoriesByName.put("exo.FlacExtractor", FlacExtractor::new);
-        extractorFactoriesByName.put("exo.FlvExtractor", FlvExtractor::new);
-        extractorFactoriesByName.put("exo.FragmentedMp4Extractor", FragmentedMp4Extractor::new);
-        extractorFactoriesByName.put("exo.MatroskaExtractor", MatroskaExtractor::new);
-        extractorFactoriesByName.put("exo.Mp3Extractor", Mp3Extractor::new);
-        extractorFactoriesByName.put("exo.Mp4Extractor", Mp4Extractor::new);
-        extractorFactoriesByName.put("exo.OggExtractor", OggExtractor::new);
-        extractorFactoriesByName.put("exo.PsExtractor", PsExtractor::new);
-        extractorFactoriesByName.put("exo.TsExtractor", TsExtractor::new);
-        extractorFactoriesByName.put("exo.WavExtractor", WavExtractor::new);
+        extractorFactoriesByName.put("exo.Ac3Parser", Ac3Extractor::new);
+        extractorFactoriesByName.put("exo.Ac4Parser", Ac4Extractor::new);
+        extractorFactoriesByName.put("exo.AdtsParser", AdtsExtractor::new);
+        extractorFactoriesByName.put("exo.AmrParser", AmrExtractor::new);
+        extractorFactoriesByName.put("exo.FlacParser", FlacExtractor::new);
+        extractorFactoriesByName.put("exo.FlvParser", FlvExtractor::new);
+        extractorFactoriesByName.put("exo.FragmentedMp4Parser", FragmentedMp4Extractor::new);
+        extractorFactoriesByName.put("exo.MatroskaParser", MatroskaExtractor::new);
+        extractorFactoriesByName.put("exo.Mp3Parser", Mp3Extractor::new);
+        extractorFactoriesByName.put("exo.Mp4Parser", Mp4Extractor::new);
+        extractorFactoriesByName.put("exo.OggParser", OggExtractor::new);
+        extractorFactoriesByName.put("exo.PsParser", PsExtractor::new);
+        extractorFactoriesByName.put("exo.TsParser", TsExtractor::new);
+        extractorFactoriesByName.put("exo.WavParser", WavExtractor::new);
         EXTRACTOR_FACTORIES_BY_NAME = Collections.unmodifiableMap(extractorFactoriesByName);
+
+        HashMap<String, Class> expectedTypeByParameterName = new HashMap<>();
+        expectedTypeByParameterName.put(PARAMETER_ADTS_ENABLE_CBR_SEEKING, Boolean.class);
+        expectedTypeByParameterName.put(PARAMETER_AMR_ENABLE_CBR_SEEKING, Boolean.class);
+        expectedTypeByParameterName.put(PARAMETER_FLAC_DISABLE_ID3, Boolean.class);
+        expectedTypeByParameterName.put(PARAMETER_FMP4_IGNORE_EDIT_LISTS, Boolean.class);
+        expectedTypeByParameterName.put(PARAMETER_FMP4_IGNORE_TFDT_BOX, Boolean.class);
+        expectedTypeByParameterName.put(
+                PARAMETER_FMP4_TREAT_VIDEO_FRAMES_AS_KEYFRAMES, Boolean.class);
+        expectedTypeByParameterName.put(PARAMETER_MATROSKA_DISABLE_CUES_SEEKING, Boolean.class);
+        expectedTypeByParameterName.put(PARAMETER_MP3_DISABLE_ID3, Boolean.class);
+        expectedTypeByParameterName.put(PARAMETER_MP3_ENABLE_CBR_SEEKING, Boolean.class);
+        expectedTypeByParameterName.put(PARAMETER_MP3_ENABLE_INDEX_SEEKING, Boolean.class);
+        expectedTypeByParameterName.put(PARAMETER_MP4_IGNORE_EDIT_LISTS, Boolean.class);
+        expectedTypeByParameterName.put(PARAMETER_TS_MODE, String.class);
+        expectedTypeByParameterName.put(PARAMETER_TS_ALLOW_NON_IDR_AVC_KEYFRAMES, Boolean.class);
+        expectedTypeByParameterName.put(PARAMETER_TS_IGNORE_AAC_STREAM, Boolean.class);
+        expectedTypeByParameterName.put(PARAMETER_TS_IGNORE_AVC_STREAM, Boolean.class);
+        expectedTypeByParameterName.put(PARAMETER_TS_IGNORE_SPLICE_INFO_STREAM, Boolean.class);
+        expectedTypeByParameterName.put(PARAMETER_TS_DETECT_ACCESS_UNITS, Boolean.class);
+        expectedTypeByParameterName.put(PARAMETER_TS_ENABLE_HDMV_DTS_AUDIO_STREAMS, Boolean.class);
+        EXPECTED_TYPE_BY_PARAMETER_NAME = Collections.unmodifiableMap(expectedTypeByParameterName);
     }
 }
diff --git a/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistence.java b/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistence.java
index 6c7f82a..0d163cf 100644
--- a/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistence.java
+++ b/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistence.java
@@ -40,7 +40,7 @@
      * @return the runtime permissions read
      */
     @Nullable
-    RuntimePermissionsState read(@NonNull UserHandle user);
+    RuntimePermissionsState readAsUser(@NonNull UserHandle user);
 
     /**
      * Write the runtime permissions to persistence.
@@ -50,7 +50,7 @@
      * @param runtimePermissions the runtime permissions to write
      * @param user the user to write for
      */
-    void write(@NonNull RuntimePermissionsState runtimePermissions, @NonNull UserHandle user);
+    void writeAsUser(@NonNull RuntimePermissionsState runtimePermissions, @NonNull UserHandle user);
 
     /**
      * Delete the runtime permissions from persistence.
@@ -59,7 +59,7 @@
      *
      * @param user the user to delete for
      */
-    void delete(@NonNull UserHandle user);
+    void deleteAsUser(@NonNull UserHandle user);
 
     /**
      * Create a new instance of {@link RuntimePermissionsPersistence} implementation.
diff --git a/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistenceImpl.java b/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistenceImpl.java
index 90b1c4b..205ffc2 100644
--- a/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistenceImpl.java
+++ b/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistenceImpl.java
@@ -67,7 +67,7 @@
 
     @Nullable
     @Override
-    public RuntimePermissionsState read(@NonNull UserHandle user) {
+    public RuntimePermissionsState readAsUser(@NonNull UserHandle user) {
         File file = getFile(user);
         try (FileInputStream inputStream = new AtomicFile(file).openRead()) {
             XmlPullParser parser = Xml.newPullParser();
@@ -172,7 +172,7 @@
     }
 
     @Override
-    public void write(@NonNull RuntimePermissionsState runtimePermissions,
+    public void writeAsUser(@NonNull RuntimePermissionsState runtimePermissions,
             @NonNull UserHandle user) {
         File file = getFile(user);
         AtomicFile atomicFile = new AtomicFile(file);
@@ -252,7 +252,7 @@
     }
 
     @Override
-    public void delete(@NonNull UserHandle user) {
+    public void deleteAsUser(@NonNull UserHandle user) {
         getFile(user).delete();
     }
 
diff --git a/apex/permission/service/java/com/android/role/persistence/RolesPersistence.java b/apex/permission/service/java/com/android/role/persistence/RolesPersistence.java
index 2908a38..64d6545 100644
--- a/apex/permission/service/java/com/android/role/persistence/RolesPersistence.java
+++ b/apex/permission/service/java/com/android/role/persistence/RolesPersistence.java
@@ -40,7 +40,7 @@
      * @return the roles read
      */
     @Nullable
-    RolesState read(@NonNull UserHandle user);
+    RolesState readAsUser(@NonNull UserHandle user);
 
     /**
      * Write the roles to persistence.
@@ -50,7 +50,7 @@
      * @param roles the roles to write
      * @param user the user to write for
      */
-    void write(@NonNull RolesState roles, @NonNull UserHandle user);
+    void writeAsUser(@NonNull RolesState roles, @NonNull UserHandle user);
 
     /**
      * Delete the roles from persistence.
@@ -59,7 +59,7 @@
      *
      * @param user the user to delete for
      */
-    void delete(@NonNull UserHandle user);
+    void deleteAsUser(@NonNull UserHandle user);
 
     /**
      * Create a new instance of {@link RolesPersistence} implementation.
diff --git a/apex/permission/service/java/com/android/role/persistence/RolesPersistenceImpl.java b/apex/permission/service/java/com/android/role/persistence/RolesPersistenceImpl.java
index 06fad77..3031c82 100644
--- a/apex/permission/service/java/com/android/role/persistence/RolesPersistenceImpl.java
+++ b/apex/permission/service/java/com/android/role/persistence/RolesPersistenceImpl.java
@@ -65,7 +65,7 @@
 
     @Nullable
     @Override
-    public RolesState read(@NonNull UserHandle user) {
+    public RolesState readAsUser(@NonNull UserHandle user) {
         File file = getFile(user);
         try (FileInputStream inputStream = new AtomicFile(file).openRead()) {
             XmlPullParser parser = Xml.newPullParser();
@@ -146,8 +146,7 @@
     }
 
     @Override
-    public void write(@NonNull RolesState roles,
-            @NonNull UserHandle user) {
+    public void writeAsUser(@NonNull RolesState roles, @NonNull UserHandle user) {
         File file = getFile(user);
         AtomicFile atomicFile = new AtomicFile(file);
         FileOutputStream outputStream = null;
@@ -206,7 +205,7 @@
     }
 
     @Override
-    public void delete(@NonNull UserHandle user) {
+    public void deleteAsUser(@NonNull UserHandle user) {
         getFile(user).delete();
     }
 
diff --git a/apex/sdkextensions/Android.bp b/apex/sdkextensions/Android.bp
index 4c5c2b2..25765af 100644
--- a/apex/sdkextensions/Android.bp
+++ b/apex/sdkextensions/Android.bp
@@ -28,7 +28,6 @@
     name: "com.android.sdkext-defaults",
     java_libs: [ "framework-sdkextensions" ],
     prebuilts: [
-        "com.android.sdkext.ldconfig",
         "derive_sdk.rc",
     ],
     key: "com.android.sdkext.key",
@@ -51,13 +50,6 @@
     certificate: "com.android.sdkext",
 }
 
-prebuilt_etc {
-    name: "com.android.sdkext.ldconfig",
-    src: "ld.config.txt",
-    filename: "ld.config.txt",
-    installable: false,
-}
-
 python_binary_host {
     name: "gen_sdkinfo",
     srcs: [
diff --git a/apex/sdkextensions/ld.config.txt b/apex/sdkextensions/ld.config.txt
deleted file mode 100644
index dcc69b8..0000000
--- a/apex/sdkextensions/ld.config.txt
+++ /dev/null
@@ -1,31 +0,0 @@
-# Copyright (C) 2019 The Android Open Source Project
-#
-# Bionic loader config file for the sdkextensions apex.
-
-dir.sdkextensions = /apex/com.android.sdkext/bin/
-
-[sdkextensions]
-additional.namespaces = platform
-
-namespace.default.isolated = true
-namespace.default.links = platform
-namespace.default.link.platform.allow_all_shared_libs = true
-
-###############################################################################
-# "platform" namespace: used for NDK libraries
-###############################################################################
-namespace.platform.isolated = true
-namespace.platform.search.paths = /system/${LIB}
-namespace.platform.asan.search.paths = /data/asan/system/${LIB}
-
-# /system/lib/libc.so, etc are symlinks to /apex/com.android.lib/lib/bionic/libc.so, etc.
-# Add /apex/... path to the permitted paths because linker uses realpath(3)
-# to check the accessibility of the lib. We could add this to search.paths
-# instead but that makes the resolution of bionic libs be dependent on
-# the order of /system/lib and /apex/... in search.paths. If /apex/...
-# is after /system/lib, then /apex/... is never tried because libc.so
-# is always found in /system/lib but fails to pass the accessibility test
-# because of its realpath.  It's better to not depend on the ordering if
-# possible.
-namespace.platform.permitted.paths = /apex/com.android.runtime/${LIB}/bionic
-namespace.platform.asan.permitted.paths = /apex/com.android.runtime/${LIB}/bionic
diff --git a/apex/statsd/Android.bp b/apex/statsd/Android.bp
index 0e93110..2f3e2ac 100644
--- a/apex/statsd/Android.bp
+++ b/apex/statsd/Android.bp
@@ -21,14 +21,16 @@
 apex_defaults {
     native_shared_libs: [
         "libstats_jni",
+        "libstatspull",
+        "libstatssocket",
     ],
-    // binaries: ["vold"],
+    binaries: ["statsd"],
     java_libs: [
         "framework-statsd",
         "service-statsd",
     ],
     compile_multilib: "both",
-    // prebuilts: ["my_prebuilt"],
+    prebuilts: ["com.android.os.statsd.init.rc"],
     name: "com.android.os.statsd-defaults",
     key: "com.android.os.statsd.key",
     certificate: ":com.android.os.statsd.certificate",
@@ -47,6 +49,12 @@
     certificate: "com.android.os.statsd",
 }
 
+prebuilt_etc {
+    name: "com.android.os.statsd.init.rc",
+    src: "statsd.rc",
+    filename: "init.rc",
+    installable: false,
+}
 
 // JNI library for StatsLog.write
 cc_library_shared {
diff --git a/apex/statsd/framework/java/android/app/StatsManager.java b/apex/statsd/framework/java/android/app/StatsManager.java
index 526d17f..e637187 100644
--- a/apex/statsd/framework/java/android/app/StatsManager.java
+++ b/apex/statsd/framework/java/android/app/StatsManager.java
@@ -159,6 +159,9 @@
                 throw new StatsUnavailableException("could not connect", e);
             } catch (SecurityException e) {
                 throw new StatsUnavailableException(e.getMessage(), e);
+            } catch (IllegalStateException e) {
+                Log.e(TAG, "Failed to addConfig in statsmanager");
+                throw new StatsUnavailableException(e.getMessage(), e);
             }
         }
     }
@@ -195,6 +198,9 @@
                 throw new StatsUnavailableException("could not connect", e);
             } catch (SecurityException e) {
                 throw new StatsUnavailableException(e.getMessage(), e);
+            } catch (IllegalStateException e) {
+                Log.e(TAG, "Failed to removeConfig in statsmanager");
+                throw new StatsUnavailableException(e.getMessage(), e);
             }
         }
     }
@@ -391,6 +397,9 @@
                 throw new StatsUnavailableException("could not connect", e);
             } catch (SecurityException e) {
                 throw new StatsUnavailableException(e.getMessage(), e);
+            } catch (IllegalStateException e) {
+                Log.e(TAG, "Failed to getReports in statsmanager");
+                throw new StatsUnavailableException(e.getMessage(), e);
             }
         }
     }
@@ -428,6 +437,9 @@
                 throw new StatsUnavailableException("could not connect", e);
             } catch (SecurityException e) {
                 throw new StatsUnavailableException(e.getMessage(), e);
+            } catch (IllegalStateException e) {
+                Log.e(TAG, "Failed to getStatsMetadata in statsmanager");
+                throw new StatsUnavailableException(e.getMessage(), e);
             }
         }
     }
@@ -469,6 +481,9 @@
                                     + "registered experiment IDs");
                 }
                 throw new StatsUnavailableException("could not connect", e);
+            } catch (IllegalStateException e) {
+                Log.e(TAG, "Failed to getRegisteredExperimentIds in statsmanager");
+                throw new StatsUnavailableException(e.getMessage(), e);
             }
         }
     }
diff --git a/cmds/statsd/statsd.rc b/apex/statsd/statsd.rc
similarity index 67%
rename from cmds/statsd/statsd.rc
rename to apex/statsd/statsd.rc
index a98ecd5..605da2a 100644
--- a/cmds/statsd/statsd.rc
+++ b/apex/statsd/statsd.rc
@@ -12,19 +12,9 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-service statsd /system/bin/statsd
+service statsd /apex/com.android.os.statsd/bin/statsd
     class main
     socket statsdw dgram+passcred 0222 statsd statsd
     user statsd
     group statsd log
     writepid /dev/cpuset/system-background/tasks
-
-on property:ro.statsd.enable=false
-    stop statsd
-
-on post-fs-data
-    # Create directory for statsd
-    mkdir /data/misc/stats-data/ 0770 statsd system
-    mkdir /data/misc/stats-service/ 0770 statsd system
-    mkdir /data/misc/stats-active-metric/ 0770 statsd system
-    mkdir /data/misc/train-info/ 0770 statsd system
diff --git a/api/current.txt b/api/current.txt
index 702744d..0a7bac5 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -32,6 +32,7 @@
     field public static final String BIND_CARRIER_SERVICES = "android.permission.BIND_CARRIER_SERVICES";
     field @Deprecated public static final String BIND_CHOOSER_TARGET_SERVICE = "android.permission.BIND_CHOOSER_TARGET_SERVICE";
     field public static final String BIND_CONDITION_PROVIDER_SERVICE = "android.permission.BIND_CONDITION_PROVIDER_SERVICE";
+    field public static final String BIND_CONTROLS = "android.permission.BIND_CONTROLS";
     field public static final String BIND_DEVICE_ADMIN = "android.permission.BIND_DEVICE_ADMIN";
     field public static final String BIND_DREAM_SERVICE = "android.permission.BIND_DREAM_SERVICE";
     field public static final String BIND_INCALL_SERVICE = "android.permission.BIND_INCALL_SERVICE";
@@ -2983,7 +2984,6 @@
     method public int describeContents();
     method public static String feedbackTypeToString(int);
     method public static String flagToString(int);
-    method public int getAnimatedImageRes();
     method @Deprecated public boolean getCanRetrieveWindowContent();
     method public int getCapabilities();
     method @Deprecated public String getDescription();
@@ -2992,6 +2992,7 @@
     method public int getNonInteractiveUiTimeoutMillis();
     method public android.content.pm.ResolveInfo getResolveInfo();
     method public String getSettingsActivityName();
+    method @Nullable public android.graphics.drawable.Drawable loadAnimatedImage(@NonNull android.content.Context);
     method public String loadDescription(android.content.pm.PackageManager);
     method @Nullable public String loadHtmlDescription(@NonNull android.content.pm.PackageManager);
     method public CharSequence loadSummary(android.content.pm.PackageManager);
@@ -6969,7 +6970,6 @@
     method public boolean removeOverrideApn(@NonNull android.content.ComponentName, int);
     method public boolean removeUser(@NonNull android.content.ComponentName, @NonNull android.os.UserHandle);
     method public boolean requestBugreport(@NonNull android.content.ComponentName);
-    method public void requestSetLocationProviderAllowed(@NonNull android.content.ComponentName, @NonNull String, boolean);
     method @Deprecated public boolean resetPassword(String, int);
     method public boolean resetPasswordWithToken(@NonNull android.content.ComponentName, String, byte[], int);
     method @Nullable public java.util.List<android.app.admin.NetworkEvent> retrieveNetworkLogs(@Nullable android.content.ComponentName, long);
@@ -12328,6 +12328,7 @@
     method public int describeContents();
     method public void dump(android.util.Printer, String);
     method public final int getIconResource();
+    method public boolean isCrossProfileIntentForwarderActivity();
     method public android.graphics.drawable.Drawable loadIcon(android.content.pm.PackageManager);
     method public CharSequence loadLabel(android.content.pm.PackageManager);
     method public void writeToParcel(android.os.Parcel, int);
@@ -12466,6 +12467,7 @@
     method @NonNull public java.util.List<android.content.pm.ShortcutInfo> getShortcuts(int);
     method public boolean isRateLimitingActive();
     method public boolean isRequestPinShortcutSupported();
+    method public void pushDynamicShortcut(@NonNull android.content.pm.ShortcutInfo);
     method public void removeAllDynamicShortcuts();
     method public void removeDynamicShortcuts(@NonNull java.util.List<java.lang.String>);
     method public void removeLongLivedShortcuts(@NonNull java.util.List<java.lang.String>);
@@ -23175,7 +23177,7 @@
     method public void onConfigureWindow(android.view.Window, boolean, boolean);
     method public android.view.View onCreateCandidatesView();
     method public android.view.View onCreateExtractTextView();
-    method @Nullable public android.view.inputmethod.InlineSuggestionsRequest onCreateInlineSuggestionsRequest();
+    method @Nullable public android.view.inputmethod.InlineSuggestionsRequest onCreateInlineSuggestionsRequest(@NonNull android.os.Bundle);
     method public android.inputmethodservice.AbstractInputMethodService.AbstractInputMethodImpl onCreateInputMethodInterface();
     method public android.inputmethodservice.AbstractInputMethodService.AbstractInputMethodSessionImpl onCreateInputMethodSessionInterface();
     method public android.view.View onCreateInputView();
@@ -24786,7 +24788,7 @@
   }
 
   public abstract class DrmInitData {
-    method public abstract android.media.DrmInitData.SchemeInitData get(java.util.UUID);
+    method @Deprecated public abstract android.media.DrmInitData.SchemeInitData get(java.util.UUID);
     method @NonNull public android.media.DrmInitData.SchemeInitData getSchemeInitDataAt(int);
     method public int getSchemeInitDataCount();
   }
@@ -25305,6 +25307,10 @@
     method public void recycle();
   }
 
+  public class MediaCodec.IncompatibleWithBlockModelException extends java.lang.RuntimeException {
+    ctor public MediaCodec.IncompatibleWithBlockModelException();
+  }
+
   public static final class MediaCodec.LinearBlock {
     method protected void finalize();
     method public static boolean isCodecCopyFreeCompatible(@NonNull String[]);
@@ -25332,23 +25338,24 @@
   }
 
   public static final class MediaCodec.OutputFrame {
-    method public void getChangedKeys(@NonNull java.util.Set<java.lang.String>);
     method public int getFlags();
     method @NonNull public android.media.MediaFormat getFormat();
     method @Nullable public android.media.MediaCodec.GraphicBlock getGraphicBlock();
     method @Nullable public android.media.MediaCodec.LinearBlock getLinearBlock();
     method public long getPresentationTimeUs();
+    method public void retrieveChangedKeys(@NonNull java.util.Set<java.lang.String>);
   }
 
   public final class MediaCodec.QueueRequest {
     method public void queue();
     method @NonNull public android.media.MediaCodec.QueueRequest setByteBufferParameter(@NonNull String, @NonNull java.nio.ByteBuffer);
-    method @NonNull public android.media.MediaCodec.QueueRequest setEncryptedLinearBlock(@NonNull android.media.MediaCodec.LinearBlock, int, @NonNull android.media.MediaCodec.CryptoInfo, long, int);
+    method @NonNull public android.media.MediaCodec.QueueRequest setFlags(int);
     method @NonNull public android.media.MediaCodec.QueueRequest setFloatParameter(@NonNull String, float);
-    method @NonNull public android.media.MediaCodec.QueueRequest setGraphicBlock(@NonNull android.media.MediaCodec.GraphicBlock, long, int);
+    method @NonNull public android.media.MediaCodec.QueueRequest setGraphicBlock(@NonNull android.media.MediaCodec.GraphicBlock);
     method @NonNull public android.media.MediaCodec.QueueRequest setIntegerParameter(@NonNull String, int);
-    method @NonNull public android.media.MediaCodec.QueueRequest setLinearBlock(@NonNull android.media.MediaCodec.LinearBlock, int, int, long, int);
+    method @NonNull public android.media.MediaCodec.QueueRequest setLinearBlock(@NonNull android.media.MediaCodec.LinearBlock, int, int, @Nullable android.media.MediaCodec.CryptoInfo);
     method @NonNull public android.media.MediaCodec.QueueRequest setLongParameter(@NonNull String, long);
+    method @NonNull public android.media.MediaCodec.QueueRequest setPresentationTimeUs(long);
     method @NonNull public android.media.MediaCodec.QueueRequest setStringParameter(@NonNull String, @NonNull String);
   }
 
@@ -26402,10 +26409,30 @@
     method public boolean advance(@NonNull android.media.MediaParser.SeekableInputReader) throws java.io.IOException, java.lang.InterruptedException;
     method @NonNull public static android.media.MediaParser create(@NonNull android.media.MediaParser.OutputConsumer, @NonNull java.lang.String...);
     method @NonNull public static android.media.MediaParser createByName(@NonNull String, @NonNull android.media.MediaParser.OutputConsumer);
-    method @Nullable public String getExtractorName();
-    method @NonNull public static java.util.List<java.lang.String> getExtractorNames(@NonNull android.media.MediaFormat);
+    method @Nullable public String getParserName();
+    method @NonNull public static java.util.List<java.lang.String> getParserNames(@NonNull android.media.MediaFormat);
     method public void release();
     method public void seek(@NonNull android.media.MediaParser.SeekPoint);
+    method @NonNull public android.media.MediaParser setParameter(@NonNull String, @NonNull Object);
+    method public boolean supportsParameter(@NonNull String);
+    field public static final String PARAMETER_ADTS_ENABLE_CBR_SEEKING = "exo.AdtsParser.enableCbrSeeking";
+    field public static final String PARAMETER_AMR_ENABLE_CBR_SEEKING = "exo.AmrParser.enableCbrSeeking";
+    field public static final String PARAMETER_FLAC_DISABLE_ID3 = "exo.FlacParser.disableId3";
+    field public static final String PARAMETER_FMP4_IGNORE_EDIT_LISTS = "exo.FragmentedMp4Parser.ignoreEditLists";
+    field public static final String PARAMETER_FMP4_IGNORE_TFDT_BOX = "exo.FragmentedMp4Parser.ignoreTfdtBox";
+    field public static final String PARAMETER_FMP4_TREAT_VIDEO_FRAMES_AS_KEYFRAMES = "exo.FragmentedMp4Parser.treatVideoFramesAsKeyframes";
+    field public static final String PARAMETER_MATROSKA_DISABLE_CUES_SEEKING = "exo.MatroskaParser.disableCuesSeeking";
+    field public static final String PARAMETER_MP3_DISABLE_ID3 = "exo.Mp3Parser.disableId3";
+    field public static final String PARAMETER_MP3_ENABLE_CBR_SEEKING = "exo.Mp3Parser.enableCbrSeeking";
+    field public static final String PARAMETER_MP3_ENABLE_INDEX_SEEKING = "exo.Mp3Parser.enableIndexSeeking";
+    field public static final String PARAMETER_MP4_IGNORE_EDIT_LISTS = "exo.Mp4Parser.ignoreEditLists";
+    field public static final String PARAMETER_TS_ALLOW_NON_IDR_AVC_KEYFRAMES = "exo.TsParser.allowNonIdrAvcKeyframes";
+    field public static final String PARAMETER_TS_DETECT_ACCESS_UNITS = "exo.TsParser.ignoreDetectAccessUnits";
+    field public static final String PARAMETER_TS_ENABLE_HDMV_DTS_AUDIO_STREAMS = "exo.TsParser.enableHdmvDtsAudioStreams";
+    field public static final String PARAMETER_TS_IGNORE_AAC_STREAM = "exo.TsParser.ignoreAacStream";
+    field public static final String PARAMETER_TS_IGNORE_AVC_STREAM = "exo.TsParser.ignoreAvcStream";
+    field public static final String PARAMETER_TS_IGNORE_SPLICE_INFO_STREAM = "exo.TsParser.ignoreSpliceInfoStream";
+    field public static final String PARAMETER_TS_MODE = "exo.TsParser.mode";
   }
 
   public static interface MediaParser.InputReader {
@@ -26872,21 +26899,27 @@
     ctor public MediaRoute2ProviderService();
     method @NonNull public final java.util.List<android.media.RoutingSessionInfo> getAllSessionInfo();
     method @Nullable public final android.media.RoutingSessionInfo getSessionInfo(@NonNull String);
+    method public final void notifyRequestFailed(long, int);
     method public final void notifyRoutes(@NonNull java.util.Collection<android.media.MediaRoute2Info>);
     method public final void notifySessionCreated(@NonNull android.media.RoutingSessionInfo, long);
     method public final void notifySessionCreationFailed(long);
     method public final void notifySessionReleased(@NonNull String);
     method public final void notifySessionUpdated(@NonNull android.media.RoutingSessionInfo);
     method @CallSuper @Nullable public android.os.IBinder onBind(@NonNull android.content.Intent);
-    method public abstract void onCreateSession(@NonNull String, @NonNull String, long, @Nullable android.os.Bundle);
-    method public abstract void onDeselectRoute(@NonNull String, @NonNull String);
+    method public abstract void onCreateSession(long, @NonNull String, @NonNull String, @Nullable android.os.Bundle);
+    method public abstract void onDeselectRoute(long, @NonNull String, @NonNull String);
     method public void onDiscoveryPreferenceChanged(@NonNull android.media.RouteDiscoveryPreference);
-    method public abstract void onReleaseSession(@NonNull String);
-    method public abstract void onSelectRoute(@NonNull String, @NonNull String);
-    method public abstract void onSetRouteVolume(@NonNull String, int);
-    method public abstract void onSetSessionVolume(@NonNull String, int);
-    method public abstract void onTransferToRoute(@NonNull String, @NonNull String);
-    field public static final long REQUEST_ID_UNKNOWN = 0L; // 0x0L
+    method public abstract void onReleaseSession(long, @NonNull String);
+    method public abstract void onSelectRoute(long, @NonNull String, @NonNull String);
+    method public abstract void onSetRouteVolume(long, @NonNull String, int);
+    method public abstract void onSetSessionVolume(long, @NonNull String, int);
+    method public abstract void onTransferToRoute(long, @NonNull String, @NonNull String);
+    field public static final int REASON_INVALID_COMMAND = 4; // 0x4
+    field public static final int REASON_NETWORK_ERROR = 2; // 0x2
+    field public static final int REASON_REJECTED = 1; // 0x1
+    field public static final int REASON_ROUTE_NOT_AVAILABLE = 3; // 0x3
+    field public static final int REASON_UNKNOWN_ERROR = 0; // 0x0
+    field public static final long REQUEST_ID_NONE = 0L; // 0x0L
     field public static final String SERVICE_INTERFACE = "android.media.MediaRoute2ProviderService";
   }
 
@@ -43399,6 +43432,7 @@
     method @NonNull public abstract java.util.concurrent.Flow.Publisher<android.service.controls.Control> publisherFor(@NonNull java.util.List<java.lang.String>);
     method @Nullable public java.util.concurrent.Flow.Publisher<android.service.controls.Control> publisherForAllAvailable();
     method @Nullable public java.util.concurrent.Flow.Publisher<android.service.controls.Control> publisherForSuggested();
+    method public static void requestAddControl(@NonNull android.content.Context, @NonNull android.content.ComponentName, @NonNull android.service.controls.Control);
     field public static final String SERVICE_CONTROLS = "android.service.controls.ControlsProviderService";
     field @NonNull public static final String TAG = "ControlsProviderService";
   }
@@ -45645,7 +45679,7 @@
     method public final android.telecom.CallAudioState getCallAudioState();
     method public final String getCallerDisplayName();
     method public final int getCallerDisplayNamePresentation();
-    method public int getCallerNumberVerificationStatus();
+    method public final int getCallerNumberVerificationStatus();
     method public final android.telecom.Conference getConference();
     method public final java.util.List<android.telecom.Conferenceable> getConferenceables();
     method public final int getConnectionCapabilities();
@@ -45698,7 +45732,7 @@
     method public final void setAudioModeIsVoip(boolean);
     method public final void setAudioRoute(int);
     method public final void setCallerDisplayName(String, int);
-    method public void setCallerNumberVerificationStatus(int);
+    method public final void setCallerNumberVerificationStatus(int);
     method public final void setConferenceableConnections(java.util.List<android.telecom.Connection>);
     method public final void setConferenceables(java.util.List<android.telecom.Conferenceable>);
     method public final void setConnectionCapabilities(int);
@@ -46550,8 +46584,8 @@
     field public static final String KEY_ALLOW_ADD_CALL_DURING_VIDEO_CALL_BOOL = "allow_add_call_during_video_call";
     field public static final String KEY_ALLOW_EMERGENCY_NUMBERS_IN_CALL_LOG_BOOL = "allow_emergency_numbers_in_call_log_bool";
     field public static final String KEY_ALLOW_EMERGENCY_VIDEO_CALLS_BOOL = "allow_emergency_video_calls_bool";
-    field public static final String KEY_ALLOW_HOLDING_VIDEO_CALL_BOOL = "allow_holding_video_call";
     field public static final String KEY_ALLOW_HOLD_CALL_DURING_EMERGENCY_BOOL = "allow_hold_call_during_emergency_bool";
+    field public static final String KEY_ALLOW_HOLD_VIDEO_CALL_BOOL = "allow_hold_video_call_bool";
     field public static final String KEY_ALLOW_LOCAL_DTMF_TONES_BOOL = "allow_local_dtmf_tones_bool";
     field public static final String KEY_ALLOW_MERGE_WIFI_CALLS_WHEN_VOWIFI_OFF_BOOL = "allow_merge_wifi_calls_when_vowifi_off_bool";
     field public static final String KEY_ALLOW_NON_EMERGENCY_CALLS_IN_ECM_BOOL = "allow_non_emergency_calls_in_ecm_bool";
@@ -47065,6 +47099,350 @@
     field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ClosedSubscriberGroupInfo> CREATOR;
   }
 
+  public final class DataFailCause {
+    field public static final int ACCESS_ATTEMPT_ALREADY_IN_PROGRESS = 2219; // 0x8ab
+    field public static final int ACCESS_BLOCK = 2087; // 0x827
+    field public static final int ACCESS_BLOCK_ALL = 2088; // 0x828
+    field public static final int ACCESS_CLASS_DSAC_REJECTION = 2108; // 0x83c
+    field public static final int ACCESS_CONTROL_LIST_CHECK_FAILURE = 2128; // 0x850
+    field public static final int ACTIVATION_REJECTED_BCM_VIOLATION = 48; // 0x30
+    field public static final int ACTIVATION_REJECT_GGSN = 30; // 0x1e
+    field public static final int ACTIVATION_REJECT_UNSPECIFIED = 31; // 0x1f
+    field public static final int ACTIVE_PDP_CONTEXT_MAX_NUMBER_REACHED = 65; // 0x41
+    field public static final int APN_DISABLED = 2045; // 0x7fd
+    field public static final int APN_DISALLOWED_ON_ROAMING = 2059; // 0x80b
+    field public static final int APN_MISMATCH = 2054; // 0x806
+    field public static final int APN_PARAMETERS_CHANGED = 2060; // 0x80c
+    field public static final int APN_PENDING_HANDOVER = 2041; // 0x7f9
+    field public static final int APN_TYPE_CONFLICT = 112; // 0x70
+    field public static final int AUTH_FAILURE_ON_EMERGENCY_CALL = 122; // 0x7a
+    field public static final int BEARER_HANDLING_NOT_SUPPORTED = 60; // 0x3c
+    field public static final int CALL_DISALLOWED_IN_ROAMING = 2068; // 0x814
+    field public static final int CALL_PREEMPT_BY_EMERGENCY_APN = 127; // 0x7f
+    field public static final int CANNOT_ENCODE_OTA_MESSAGE = 2159; // 0x86f
+    field public static final int CDMA_ALERT_STOP = 2077; // 0x81d
+    field public static final int CDMA_INCOMING_CALL = 2076; // 0x81c
+    field public static final int CDMA_INTERCEPT = 2073; // 0x819
+    field public static final int CDMA_LOCK = 2072; // 0x818
+    field public static final int CDMA_RELEASE_DUE_TO_SO_REJECTION = 2075; // 0x81b
+    field public static final int CDMA_REORDER = 2074; // 0x81a
+    field public static final int CDMA_RETRY_ORDER = 2086; // 0x826
+    field public static final int CHANNEL_ACQUISITION_FAILURE = 2078; // 0x81e
+    field public static final int CLOSE_IN_PROGRESS = 2030; // 0x7ee
+    field public static final int COLLISION_WITH_NETWORK_INITIATED_REQUEST = 56; // 0x38
+    field public static final int COMPANION_IFACE_IN_USE = 118; // 0x76
+    field public static final int CONCURRENT_SERVICES_INCOMPATIBLE = 2083; // 0x823
+    field public static final int CONCURRENT_SERVICES_NOT_ALLOWED = 2091; // 0x82b
+    field public static final int CONCURRENT_SERVICE_NOT_SUPPORTED_BY_BASE_STATION = 2080; // 0x820
+    field public static final int CONDITIONAL_IE_ERROR = 100; // 0x64
+    field public static final int CONGESTION = 2106; // 0x83a
+    field public static final int CONNECTION_RELEASED = 2113; // 0x841
+    field public static final int CS_DOMAIN_NOT_AVAILABLE = 2181; // 0x885
+    field public static final int CS_FALLBACK_CALL_ESTABLISHMENT_NOT_ALLOWED = 2188; // 0x88c
+    field public static final int DATA_PLAN_EXPIRED = 2198; // 0x896
+    field public static final int DATA_ROAMING_SETTINGS_DISABLED = 2064; // 0x810
+    field public static final int DATA_SETTINGS_DISABLED = 2063; // 0x80f
+    field public static final int DBM_OR_SMS_IN_PROGRESS = 2211; // 0x8a3
+    field public static final int DDS_SWITCHED = 2065; // 0x811
+    field public static final int DDS_SWITCH_IN_PROGRESS = 2067; // 0x813
+    field public static final int DRB_RELEASED_BY_RRC = 2112; // 0x840
+    field public static final int DS_EXPLICIT_DEACTIVATION = 2125; // 0x84d
+    field public static final int DUAL_SWITCH = 2227; // 0x8b3
+    field public static final int DUN_CALL_DISALLOWED = 2056; // 0x808
+    field public static final int DUPLICATE_BEARER_ID = 2118; // 0x846
+    field public static final int EHRPD_TO_HRPD_FALLBACK = 2049; // 0x801
+    field public static final int EMBMS_NOT_ENABLED = 2193; // 0x891
+    field public static final int EMBMS_REGULAR_DEACTIVATION = 2195; // 0x893
+    field public static final int EMERGENCY_IFACE_ONLY = 116; // 0x74
+    field public static final int EMERGENCY_MODE = 2221; // 0x8ad
+    field public static final int EMM_ACCESS_BARRED = 115; // 0x73
+    field public static final int EMM_ACCESS_BARRED_INFINITE_RETRY = 121; // 0x79
+    field public static final int EMM_ATTACH_FAILED = 2115; // 0x843
+    field public static final int EMM_ATTACH_STARTED = 2116; // 0x844
+    field public static final int EMM_DETACHED = 2114; // 0x842
+    field public static final int EMM_T3417_EXPIRED = 2130; // 0x852
+    field public static final int EMM_T3417_EXT_EXPIRED = 2131; // 0x853
+    field public static final int EPS_SERVICES_AND_NON_EPS_SERVICES_NOT_ALLOWED = 2178; // 0x882
+    field public static final int EPS_SERVICES_NOT_ALLOWED_IN_PLMN = 2179; // 0x883
+    field public static final int ERROR_UNSPECIFIED = 65535; // 0xffff
+    field public static final int ESM_BAD_OTA_MESSAGE = 2122; // 0x84a
+    field public static final int ESM_BEARER_DEACTIVATED_TO_SYNC_WITH_NETWORK = 2120; // 0x848
+    field public static final int ESM_COLLISION_SCENARIOS = 2119; // 0x847
+    field public static final int ESM_CONTEXT_TRANSFERRED_DUE_TO_IRAT = 2124; // 0x84c
+    field public static final int ESM_DOWNLOAD_SERVER_REJECTED_THE_CALL = 2123; // 0x84b
+    field public static final int ESM_FAILURE = 2182; // 0x886
+    field public static final int ESM_INFO_NOT_RECEIVED = 53; // 0x35
+    field public static final int ESM_LOCAL_CAUSE_NONE = 2126; // 0x84e
+    field public static final int ESM_NW_ACTIVATED_DED_BEARER_WITH_ID_OF_DEF_BEARER = 2121; // 0x849
+    field public static final int ESM_PROCEDURE_TIME_OUT = 2155; // 0x86b
+    field public static final int ESM_UNKNOWN_EPS_BEARER_CONTEXT = 2111; // 0x83f
+    field public static final int EVDO_CONNECTION_DENY_BY_BILLING_OR_AUTHENTICATION_FAILURE = 2201; // 0x899
+    field public static final int EVDO_CONNECTION_DENY_BY_GENERAL_OR_NETWORK_BUSY = 2200; // 0x898
+    field public static final int EVDO_HDR_CHANGED = 2202; // 0x89a
+    field public static final int EVDO_HDR_CONNECTION_SETUP_TIMEOUT = 2206; // 0x89e
+    field public static final int EVDO_HDR_EXITED = 2203; // 0x89b
+    field public static final int EVDO_HDR_NO_SESSION = 2204; // 0x89c
+    field public static final int EVDO_USING_GPS_FIX_INSTEAD_OF_HDR_CALL = 2205; // 0x89d
+    field public static final int FADE = 2217; // 0x8a9
+    field public static final int FAILED_TO_ACQUIRE_COLOCATED_HDR = 2207; // 0x89f
+    field public static final int FEATURE_NOT_SUPP = 40; // 0x28
+    field public static final int FILTER_SEMANTIC_ERROR = 44; // 0x2c
+    field public static final int FILTER_SYTAX_ERROR = 45; // 0x2d
+    field public static final int FORBIDDEN_APN_NAME = 2066; // 0x812
+    field public static final int GPRS_REGISTRATION_FAIL = -2; // 0xfffffffe
+    field public static final int GPRS_SERVICES_AND_NON_GPRS_SERVICES_NOT_ALLOWED = 2097; // 0x831
+    field public static final int GPRS_SERVICES_NOT_ALLOWED = 2098; // 0x832
+    field public static final int GPRS_SERVICES_NOT_ALLOWED_IN_THIS_PLMN = 2103; // 0x837
+    field public static final int HANDOFF_PREFERENCE_CHANGED = 2251; // 0x8cb
+    field public static final int HDR_ACCESS_FAILURE = 2213; // 0x8a5
+    field public static final int HDR_FADE = 2212; // 0x8a4
+    field public static final int HDR_NO_LOCK_GRANTED = 2210; // 0x8a2
+    field public static final int IFACE_AND_POL_FAMILY_MISMATCH = 120; // 0x78
+    field public static final int IFACE_MISMATCH = 117; // 0x75
+    field public static final int ILLEGAL_ME = 2096; // 0x830
+    field public static final int ILLEGAL_MS = 2095; // 0x82f
+    field public static final int IMEI_NOT_ACCEPTED = 2177; // 0x881
+    field public static final int IMPLICITLY_DETACHED = 2100; // 0x834
+    field public static final int IMSI_UNKNOWN_IN_HOME_SUBSCRIBER_SERVER = 2176; // 0x880
+    field public static final int INCOMING_CALL_REJECTED = 2092; // 0x82c
+    field public static final int INSUFFICIENT_RESOURCES = 26; // 0x1a
+    field public static final int INTERFACE_IN_USE = 2058; // 0x80a
+    field public static final int INTERNAL_CALL_PREEMPT_BY_HIGH_PRIO_APN = 114; // 0x72
+    field public static final int INTERNAL_EPC_NONEPC_TRANSITION = 2057; // 0x809
+    field public static final int INVALID_CONNECTION_ID = 2156; // 0x86c
+    field public static final int INVALID_DNS_ADDR = 123; // 0x7b
+    field public static final int INVALID_EMM_STATE = 2190; // 0x88e
+    field public static final int INVALID_MANDATORY_INFO = 96; // 0x60
+    field public static final int INVALID_MODE = 2223; // 0x8af
+    field public static final int INVALID_PCSCF_ADDR = 113; // 0x71
+    field public static final int INVALID_PCSCF_OR_DNS_ADDRESS = 124; // 0x7c
+    field public static final int INVALID_PRIMARY_NSAPI = 2158; // 0x86e
+    field public static final int INVALID_SIM_STATE = 2224; // 0x8b0
+    field public static final int INVALID_TRANSACTION_ID = 81; // 0x51
+    field public static final int IPV6_ADDRESS_TRANSFER_FAILED = 2047; // 0x7ff
+    field public static final int IPV6_PREFIX_UNAVAILABLE = 2250; // 0x8ca
+    field public static final int IP_ADDRESS_MISMATCH = 119; // 0x77
+    field public static final int IP_VERSION_MISMATCH = 2055; // 0x807
+    field public static final int IRAT_HANDOVER_FAILED = 2194; // 0x892
+    field public static final int IS707B_MAX_ACCESS_PROBES = 2089; // 0x829
+    field public static final int LIMITED_TO_IPV4 = 2234; // 0x8ba
+    field public static final int LIMITED_TO_IPV6 = 2235; // 0x8bb
+    field public static final int LLC_SNDCP = 25; // 0x19
+    field public static final int LOCAL_END = 2215; // 0x8a7
+    field public static final int LOCATION_AREA_NOT_ALLOWED = 2102; // 0x836
+    field public static final int LOST_CONNECTION = 65540; // 0x10004
+    field public static final int LOWER_LAYER_REGISTRATION_FAILURE = 2197; // 0x895
+    field public static final int LOW_POWER_MODE_OR_POWERING_DOWN = 2044; // 0x7fc
+    field public static final int LTE_NAS_SERVICE_REQUEST_FAILED = 2117; // 0x845
+    field public static final int LTE_THROTTLING_NOT_REQUIRED = 2127; // 0x84f
+    field public static final int MAC_FAILURE = 2183; // 0x887
+    field public static final int MAXIMIUM_NSAPIS_EXCEEDED = 2157; // 0x86d
+    field public static final int MAXINUM_SIZE_OF_L2_MESSAGE_EXCEEDED = 2166; // 0x876
+    field public static final int MAX_ACCESS_PROBE = 2079; // 0x81f
+    field public static final int MAX_IPV4_CONNECTIONS = 2052; // 0x804
+    field public static final int MAX_IPV6_CONNECTIONS = 2053; // 0x805
+    field public static final int MAX_PPP_INACTIVITY_TIMER_EXPIRED = 2046; // 0x7fe
+    field public static final int MESSAGE_INCORRECT_SEMANTIC = 95; // 0x5f
+    field public static final int MESSAGE_TYPE_UNSUPPORTED = 97; // 0x61
+    field public static final int MIP_CONFIG_FAILURE = 2050; // 0x802
+    field public static final int MIP_FA_ADMIN_PROHIBITED = 2001; // 0x7d1
+    field public static final int MIP_FA_DELIVERY_STYLE_NOT_SUPPORTED = 2012; // 0x7dc
+    field public static final int MIP_FA_ENCAPSULATION_UNAVAILABLE = 2008; // 0x7d8
+    field public static final int MIP_FA_HOME_AGENT_AUTHENTICATION_FAILURE = 2004; // 0x7d4
+    field public static final int MIP_FA_INSUFFICIENT_RESOURCES = 2002; // 0x7d2
+    field public static final int MIP_FA_MALFORMED_REPLY = 2007; // 0x7d7
+    field public static final int MIP_FA_MALFORMED_REQUEST = 2006; // 0x7d6
+    field public static final int MIP_FA_MISSING_CHALLENGE = 2017; // 0x7e1
+    field public static final int MIP_FA_MISSING_HOME_ADDRESS = 2015; // 0x7df
+    field public static final int MIP_FA_MISSING_HOME_AGENT = 2014; // 0x7de
+    field public static final int MIP_FA_MISSING_NAI = 2013; // 0x7dd
+    field public static final int MIP_FA_MOBILE_NODE_AUTHENTICATION_FAILURE = 2003; // 0x7d3
+    field public static final int MIP_FA_REASON_UNSPECIFIED = 2000; // 0x7d0
+    field public static final int MIP_FA_REQUESTED_LIFETIME_TOO_LONG = 2005; // 0x7d5
+    field public static final int MIP_FA_REVERSE_TUNNEL_IS_MANDATORY = 2011; // 0x7db
+    field public static final int MIP_FA_REVERSE_TUNNEL_UNAVAILABLE = 2010; // 0x7da
+    field public static final int MIP_FA_STALE_CHALLENGE = 2018; // 0x7e2
+    field public static final int MIP_FA_UNKNOWN_CHALLENGE = 2016; // 0x7e0
+    field public static final int MIP_FA_VJ_HEADER_COMPRESSION_UNAVAILABLE = 2009; // 0x7d9
+    field public static final int MIP_HA_ADMIN_PROHIBITED = 2020; // 0x7e4
+    field public static final int MIP_HA_ENCAPSULATION_UNAVAILABLE = 2029; // 0x7ed
+    field public static final int MIP_HA_FOREIGN_AGENT_AUTHENTICATION_FAILURE = 2023; // 0x7e7
+    field public static final int MIP_HA_INSUFFICIENT_RESOURCES = 2021; // 0x7e5
+    field public static final int MIP_HA_MALFORMED_REQUEST = 2025; // 0x7e9
+    field public static final int MIP_HA_MOBILE_NODE_AUTHENTICATION_FAILURE = 2022; // 0x7e6
+    field public static final int MIP_HA_REASON_UNSPECIFIED = 2019; // 0x7e3
+    field public static final int MIP_HA_REGISTRATION_ID_MISMATCH = 2024; // 0x7e8
+    field public static final int MIP_HA_REVERSE_TUNNEL_IS_MANDATORY = 2028; // 0x7ec
+    field public static final int MIP_HA_REVERSE_TUNNEL_UNAVAILABLE = 2027; // 0x7eb
+    field public static final int MIP_HA_UNKNOWN_HOME_AGENT_ADDRESS = 2026; // 0x7ea
+    field public static final int MISSING_UNKNOWN_APN = 27; // 0x1b
+    field public static final int MODEM_APP_PREEMPTED = 2032; // 0x7f0
+    field public static final int MODEM_RESTART = 2037; // 0x7f5
+    field public static final int MSC_TEMPORARILY_NOT_REACHABLE = 2180; // 0x884
+    field public static final int MSG_AND_PROTOCOL_STATE_UNCOMPATIBLE = 101; // 0x65
+    field public static final int MSG_TYPE_NONCOMPATIBLE_STATE = 98; // 0x62
+    field public static final int MS_IDENTITY_CANNOT_BE_DERIVED_BY_THE_NETWORK = 2099; // 0x833
+    field public static final int MULTIPLE_PDP_CALL_NOT_ALLOWED = 2192; // 0x890
+    field public static final int MULTI_CONN_TO_SAME_PDN_NOT_ALLOWED = 55; // 0x37
+    field public static final int NAS_LAYER_FAILURE = 2191; // 0x88f
+    field public static final int NAS_REQUEST_REJECTED_BY_NETWORK = 2167; // 0x877
+    field public static final int NAS_SIGNALLING = 14; // 0xe
+    field public static final int NETWORK_FAILURE = 38; // 0x26
+    field public static final int NETWORK_INITIATED_DETACH_NO_AUTO_REATTACH = 2154; // 0x86a
+    field public static final int NETWORK_INITIATED_DETACH_WITH_AUTO_REATTACH = 2153; // 0x869
+    field public static final int NETWORK_INITIATED_TERMINATION = 2031; // 0x7ef
+    field public static final int NONE = 0; // 0x0
+    field public static final int NON_IP_NOT_SUPPORTED = 2069; // 0x815
+    field public static final int NORMAL_RELEASE = 2218; // 0x8aa
+    field public static final int NO_CDMA_SERVICE = 2084; // 0x824
+    field public static final int NO_COLLOCATED_HDR = 2225; // 0x8b1
+    field public static final int NO_EPS_BEARER_CONTEXT_ACTIVATED = 2189; // 0x88d
+    field public static final int NO_GPRS_CONTEXT = 2094; // 0x82e
+    field public static final int NO_HYBRID_HDR_SERVICE = 2209; // 0x8a1
+    field public static final int NO_PDP_CONTEXT_ACTIVATED = 2107; // 0x83b
+    field public static final int NO_RESPONSE_FROM_BASE_STATION = 2081; // 0x821
+    field public static final int NO_SERVICE = 2216; // 0x8a8
+    field public static final int NO_SERVICE_ON_GATEWAY = 2093; // 0x82d
+    field public static final int NSAPI_IN_USE = 35; // 0x23
+    field public static final int NULL_APN_DISALLOWED = 2061; // 0x80d
+    field public static final int OEM_DCFAILCAUSE_1 = 4097; // 0x1001
+    field public static final int OEM_DCFAILCAUSE_10 = 4106; // 0x100a
+    field public static final int OEM_DCFAILCAUSE_11 = 4107; // 0x100b
+    field public static final int OEM_DCFAILCAUSE_12 = 4108; // 0x100c
+    field public static final int OEM_DCFAILCAUSE_13 = 4109; // 0x100d
+    field public static final int OEM_DCFAILCAUSE_14 = 4110; // 0x100e
+    field public static final int OEM_DCFAILCAUSE_15 = 4111; // 0x100f
+    field public static final int OEM_DCFAILCAUSE_2 = 4098; // 0x1002
+    field public static final int OEM_DCFAILCAUSE_3 = 4099; // 0x1003
+    field public static final int OEM_DCFAILCAUSE_4 = 4100; // 0x1004
+    field public static final int OEM_DCFAILCAUSE_5 = 4101; // 0x1005
+    field public static final int OEM_DCFAILCAUSE_6 = 4102; // 0x1006
+    field public static final int OEM_DCFAILCAUSE_7 = 4103; // 0x1007
+    field public static final int OEM_DCFAILCAUSE_8 = 4104; // 0x1008
+    field public static final int OEM_DCFAILCAUSE_9 = 4105; // 0x1009
+    field public static final int ONLY_IPV4V6_ALLOWED = 57; // 0x39
+    field public static final int ONLY_IPV4_ALLOWED = 50; // 0x32
+    field public static final int ONLY_IPV6_ALLOWED = 51; // 0x33
+    field public static final int ONLY_NON_IP_ALLOWED = 58; // 0x3a
+    field public static final int ONLY_SINGLE_BEARER_ALLOWED = 52; // 0x34
+    field public static final int OPERATOR_BARRED = 8; // 0x8
+    field public static final int OTASP_COMMIT_IN_PROGRESS = 2208; // 0x8a0
+    field public static final int PDN_CONN_DOES_NOT_EXIST = 54; // 0x36
+    field public static final int PDN_INACTIVITY_TIMER_EXPIRED = 2051; // 0x803
+    field public static final int PDN_IPV4_CALL_DISALLOWED = 2033; // 0x7f1
+    field public static final int PDN_IPV4_CALL_THROTTLED = 2034; // 0x7f2
+    field public static final int PDN_IPV6_CALL_DISALLOWED = 2035; // 0x7f3
+    field public static final int PDN_IPV6_CALL_THROTTLED = 2036; // 0x7f4
+    field public static final int PDN_NON_IP_CALL_DISALLOWED = 2071; // 0x817
+    field public static final int PDN_NON_IP_CALL_THROTTLED = 2070; // 0x816
+    field public static final int PDP_ACTIVATE_MAX_RETRY_FAILED = 2109; // 0x83d
+    field public static final int PDP_DUPLICATE = 2104; // 0x838
+    field public static final int PDP_ESTABLISH_TIMEOUT_EXPIRED = 2161; // 0x871
+    field public static final int PDP_INACTIVE_TIMEOUT_EXPIRED = 2163; // 0x873
+    field public static final int PDP_LOWERLAYER_ERROR = 2164; // 0x874
+    field public static final int PDP_MODIFY_COLLISION = 2165; // 0x875
+    field public static final int PDP_MODIFY_TIMEOUT_EXPIRED = 2162; // 0x872
+    field public static final int PDP_PPP_NOT_SUPPORTED = 2038; // 0x7f6
+    field public static final int PDP_WITHOUT_ACTIVE_TFT = 46; // 0x2e
+    field public static final int PHONE_IN_USE = 2222; // 0x8ae
+    field public static final int PHYSICAL_LINK_CLOSE_IN_PROGRESS = 2040; // 0x7f8
+    field public static final int PLMN_NOT_ALLOWED = 2101; // 0x835
+    field public static final int PPP_AUTH_FAILURE = 2229; // 0x8b5
+    field public static final int PPP_CHAP_FAILURE = 2232; // 0x8b8
+    field public static final int PPP_CLOSE_IN_PROGRESS = 2233; // 0x8b9
+    field public static final int PPP_OPTION_MISMATCH = 2230; // 0x8b6
+    field public static final int PPP_PAP_FAILURE = 2231; // 0x8b7
+    field public static final int PPP_TIMEOUT = 2228; // 0x8b4
+    field public static final int PREF_RADIO_TECH_CHANGED = -4; // 0xfffffffc
+    field public static final int PROFILE_BEARER_INCOMPATIBLE = 2042; // 0x7fa
+    field public static final int PROTOCOL_ERRORS = 111; // 0x6f
+    field public static final int QOS_NOT_ACCEPTED = 37; // 0x25
+    field public static final int RADIO_ACCESS_BEARER_FAILURE = 2110; // 0x83e
+    field public static final int RADIO_ACCESS_BEARER_SETUP_FAILURE = 2160; // 0x870
+    field public static final int RADIO_NOT_AVAILABLE = 65537; // 0x10001
+    field public static final int RADIO_POWER_OFF = -5; // 0xfffffffb
+    field public static final int REDIRECTION_OR_HANDOFF_IN_PROGRESS = 2220; // 0x8ac
+    field public static final int REGISTRATION_FAIL = -1; // 0xffffffff
+    field public static final int REGULAR_DEACTIVATION = 36; // 0x24
+    field public static final int REJECTED_BY_BASE_STATION = 2082; // 0x822
+    field public static final int RRC_CONNECTION_ABORTED_AFTER_HANDOVER = 2173; // 0x87d
+    field public static final int RRC_CONNECTION_ABORTED_AFTER_IRAT_CELL_CHANGE = 2174; // 0x87e
+    field public static final int RRC_CONNECTION_ABORTED_DUE_TO_IRAT_CHANGE = 2171; // 0x87b
+    field public static final int RRC_CONNECTION_ABORTED_DURING_IRAT_CELL_CHANGE = 2175; // 0x87f
+    field public static final int RRC_CONNECTION_ABORT_REQUEST = 2151; // 0x867
+    field public static final int RRC_CONNECTION_ACCESS_BARRED = 2139; // 0x85b
+    field public static final int RRC_CONNECTION_ACCESS_STRATUM_FAILURE = 2137; // 0x859
+    field public static final int RRC_CONNECTION_ANOTHER_PROCEDURE_IN_PROGRESS = 2138; // 0x85a
+    field public static final int RRC_CONNECTION_CELL_NOT_CAMPED = 2144; // 0x860
+    field public static final int RRC_CONNECTION_CELL_RESELECTION = 2140; // 0x85c
+    field public static final int RRC_CONNECTION_CONFIG_FAILURE = 2141; // 0x85d
+    field public static final int RRC_CONNECTION_INVALID_REQUEST = 2168; // 0x878
+    field public static final int RRC_CONNECTION_LINK_FAILURE = 2143; // 0x85f
+    field public static final int RRC_CONNECTION_NORMAL_RELEASE = 2147; // 0x863
+    field public static final int RRC_CONNECTION_OUT_OF_SERVICE_DURING_CELL_REGISTER = 2150; // 0x866
+    field public static final int RRC_CONNECTION_RADIO_LINK_FAILURE = 2148; // 0x864
+    field public static final int RRC_CONNECTION_REESTABLISHMENT_FAILURE = 2149; // 0x865
+    field public static final int RRC_CONNECTION_REJECT_BY_NETWORK = 2146; // 0x862
+    field public static final int RRC_CONNECTION_RELEASED_SECURITY_NOT_ACTIVE = 2172; // 0x87c
+    field public static final int RRC_CONNECTION_RF_UNAVAILABLE = 2170; // 0x87a
+    field public static final int RRC_CONNECTION_SYSTEM_INFORMATION_BLOCK_READ_ERROR = 2152; // 0x868
+    field public static final int RRC_CONNECTION_SYSTEM_INTERVAL_FAILURE = 2145; // 0x861
+    field public static final int RRC_CONNECTION_TIMER_EXPIRED = 2142; // 0x85e
+    field public static final int RRC_CONNECTION_TRACKING_AREA_ID_CHANGED = 2169; // 0x879
+    field public static final int RRC_UPLINK_CONNECTION_RELEASE = 2134; // 0x856
+    field public static final int RRC_UPLINK_DATA_TRANSMISSION_FAILURE = 2132; // 0x854
+    field public static final int RRC_UPLINK_DELIVERY_FAILED_DUE_TO_HANDOVER = 2133; // 0x855
+    field public static final int RRC_UPLINK_ERROR_REQUEST_FROM_NAS = 2136; // 0x858
+    field public static final int RRC_UPLINK_RADIO_LINK_FAILURE = 2135; // 0x857
+    field public static final int RUIM_NOT_PRESENT = 2085; // 0x825
+    field public static final int SECURITY_MODE_REJECTED = 2186; // 0x88a
+    field public static final int SERVICE_NOT_ALLOWED_ON_PLMN = 2129; // 0x851
+    field public static final int SERVICE_OPTION_NOT_SUBSCRIBED = 33; // 0x21
+    field public static final int SERVICE_OPTION_NOT_SUPPORTED = 32; // 0x20
+    field public static final int SERVICE_OPTION_OUT_OF_ORDER = 34; // 0x22
+    field public static final int SIGNAL_LOST = -3; // 0xfffffffd
+    field public static final int SIM_CARD_CHANGED = 2043; // 0x7fb
+    field public static final int SYNCHRONIZATION_FAILURE = 2184; // 0x888
+    field public static final int TEST_LOOPBACK_REGULAR_DEACTIVATION = 2196; // 0x894
+    field public static final int TETHERED_CALL_ACTIVE = -6; // 0xfffffffa
+    field public static final int TFT_SEMANTIC_ERROR = 41; // 0x29
+    field public static final int TFT_SYTAX_ERROR = 42; // 0x2a
+    field public static final int THERMAL_EMERGENCY = 2090; // 0x82a
+    field public static final int THERMAL_MITIGATION = 2062; // 0x80e
+    field public static final int TRAT_SWAP_FAILED = 2048; // 0x800
+    field public static final int UE_INITIATED_DETACH_OR_DISCONNECT = 128; // 0x80
+    field public static final int UE_IS_ENTERING_POWERSAVE_MODE = 2226; // 0x8b2
+    field public static final int UE_RAT_CHANGE = 2105; // 0x839
+    field public static final int UE_SECURITY_CAPABILITIES_MISMATCH = 2185; // 0x889
+    field public static final int UMTS_HANDOVER_TO_IWLAN = 2199; // 0x897
+    field public static final int UMTS_REACTIVATION_REQ = 39; // 0x27
+    field public static final int UNACCEPTABLE_NETWORK_PARAMETER = 65538; // 0x10002
+    field public static final int UNACCEPTABLE_NON_EPS_AUTHENTICATION = 2187; // 0x88b
+    field public static final int UNKNOWN = 65536; // 0x10000
+    field public static final int UNKNOWN_INFO_ELEMENT = 99; // 0x63
+    field public static final int UNKNOWN_PDP_ADDRESS_TYPE = 28; // 0x1c
+    field public static final int UNKNOWN_PDP_CONTEXT = 43; // 0x2b
+    field public static final int UNPREFERRED_RAT = 2039; // 0x7f7
+    field public static final int UNSUPPORTED_1X_PREV = 2214; // 0x8a6
+    field public static final int UNSUPPORTED_APN_IN_CURRENT_PLMN = 66; // 0x42
+    field public static final int UNSUPPORTED_QCI_VALUE = 59; // 0x3b
+    field public static final int USER_AUTHENTICATION = 29; // 0x1d
+    field public static final int VSNCP_ADMINISTRATIVELY_PROHIBITED = 2245; // 0x8c5
+    field public static final int VSNCP_APN_UNAUTHORIZED = 2238; // 0x8be
+    field public static final int VSNCP_GEN_ERROR = 2237; // 0x8bd
+    field public static final int VSNCP_INSUFFICIENT_PARAMETERS = 2243; // 0x8c3
+    field public static final int VSNCP_NO_PDN_GATEWAY_ADDRESS = 2240; // 0x8c0
+    field public static final int VSNCP_PDN_EXISTS_FOR_THIS_APN = 2248; // 0x8c8
+    field public static final int VSNCP_PDN_GATEWAY_REJECT = 2242; // 0x8c2
+    field public static final int VSNCP_PDN_GATEWAY_UNREACHABLE = 2241; // 0x8c1
+    field public static final int VSNCP_PDN_ID_IN_USE = 2246; // 0x8c6
+    field public static final int VSNCP_PDN_LIMIT_EXCEEDED = 2239; // 0x8bf
+    field public static final int VSNCP_RECONNECT_NOT_ALLOWED = 2249; // 0x8c9
+    field public static final int VSNCP_RESOURCE_UNAVAILABLE = 2244; // 0x8c4
+    field public static final int VSNCP_SUBSCRIBER_LIMITATION = 2247; // 0x8c7
+    field public static final int VSNCP_TIMEOUT = 2236; // 0x8bc
+  }
+
   public final class DisplayInfo implements android.os.Parcelable {
     method public int describeContents();
     method public int getNetworkType();
@@ -47227,32 +47605,8 @@
 
   public final class PhoneCapability implements android.os.Parcelable {
     method public int describeContents();
-    method @NonNull public java.util.List<java.lang.Integer> getBands(int);
-    method @NonNull public java.util.List<java.util.List<java.lang.Long>> getConcurrentFeaturesSupport();
-    method @NonNull public java.util.List<java.lang.String> getLogicalModemUuids();
-    method public int getMaxActiveDedicatedBearers();
-    method public int getMaxActiveInternetData();
-    method public int getMaxActivePsVoice();
-    method public long getPsDataConnectionLingerTimeMillis();
-    method @NonNull public java.util.List<android.telephony.SimSlotCapability> getSimSlotCapabilities();
-    method public long getSupportedRats();
-    method public int getUeCategory(boolean, int);
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.telephony.PhoneCapability> CREATOR;
-    field public static final long MODEM_FEATURE_3GPP2_REG = 1L; // 0x1L
-    field public static final long MODEM_FEATURE_3GPP_REG = 2L; // 0x2L
-    field public static final long MODEM_FEATURE_CDMA2000_EHRPD_REG = 4L; // 0x4L
-    field public static final long MODEM_FEATURE_CSIM = 8192L; // 0x2000L
-    field public static final long MODEM_FEATURE_CS_VOICE_SESSION = 512L; // 0x200L
-    field public static final long MODEM_FEATURE_DEDICATED_BEARER = 2048L; // 0x800L
-    field public static final long MODEM_FEATURE_EUTRAN_REG = 32L; // 0x20L
-    field public static final long MODEM_FEATURE_EUTRA_NR_DUAL_CONNECTIVITY_REG = 128L; // 0x80L
-    field public static final long MODEM_FEATURE_GERAN_REG = 8L; // 0x8L
-    field public static final long MODEM_FEATURE_INTERACTIVE_DATA_SESSION = 1024L; // 0x400L
-    field public static final long MODEM_FEATURE_NETWORK_SCAN = 4096L; // 0x1000L
-    field public static final long MODEM_FEATURE_NGRAN_REG = 64L; // 0x40L
-    field public static final long MODEM_FEATURE_PS_VOICE_REG = 256L; // 0x100L
-    field public static final long MODEM_FEATURE_UTRAN_REG = 16L; // 0x10L
   }
 
   public class PhoneNumberFormattingTextWatcher implements android.text.TextWatcher {
@@ -47442,18 +47796,6 @@
     field public static final int INVALID = 2147483647; // 0x7fffffff
   }
 
-  public final class SimSlotCapability implements android.os.Parcelable {
-    method public int describeContents();
-    method public int getPhysicalSlotIndex();
-    method public int getSlotType();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.telephony.SimSlotCapability> CREATOR;
-    field public static final int SLOT_TYPE_EUICC = 3; // 0x3
-    field public static final int SLOT_TYPE_IUICC = 2; // 0x2
-    field public static final int SLOT_TYPE_SOFT_SIM = 4; // 0x4
-    field public static final int SLOT_TYPE_UICC = 1; // 0x1
-  }
-
   public final class SmsManager {
     method public String createAppSpecificSmsToken(android.app.PendingIntent);
     method @Nullable public String createAppSpecificSmsTokenWithPackageInfo(@Nullable String, @NonNull android.app.PendingIntent);
@@ -47810,7 +48152,6 @@
     method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public int getNetworkSelectionMode();
     method public String getNetworkSpecifier();
     method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public int getNetworkType();
-    method @Nullable @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public android.telephony.PhoneCapability getPhoneCapability();
     method @Deprecated public int getPhoneCount();
     method public int getPhoneType();
     method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PHONE_STATE}) public int getPreferredOpportunisticDataSubscription();
@@ -56419,7 +56760,7 @@
     method public int describeContents();
     method @NonNull public android.util.Size getMaxSize();
     method @NonNull public android.util.Size getMinSize();
-    method @Nullable public String getStyle();
+    method @Nullable public android.os.Bundle getStyle();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.view.inline.InlinePresentationSpec> CREATOR;
   }
@@ -56427,7 +56768,7 @@
   public static final class InlinePresentationSpec.Builder {
     ctor public InlinePresentationSpec.Builder(@NonNull android.util.Size, @NonNull android.util.Size);
     method @NonNull public android.view.inline.InlinePresentationSpec build();
-    method @NonNull public android.view.inline.InlinePresentationSpec.Builder setStyle(@Nullable String);
+    method @NonNull public android.view.inline.InlinePresentationSpec.Builder setStyle(@Nullable android.os.Bundle);
   }
 
 }
diff --git a/api/module-lib-current.txt b/api/module-lib-current.txt
index 7b66f73..6863221 100644
--- a/api/module-lib-current.txt
+++ b/api/module-lib-current.txt
@@ -30,7 +30,6 @@
   }
 
   public class TetheringConstants {
-    ctor public TetheringConstants();
     field public static final String EXTRA_ADD_TETHER_TYPE = "extraAddTetherType";
     field public static final String EXTRA_PROVISION_CALLBACK = "extraProvisionCallback";
     field public static final String EXTRA_REM_TETHER_TYPE = "extraRemTetherType";
diff --git a/api/module-lib-lint-baseline.txt b/api/module-lib-lint-baseline.txt
index 6e59596..56f7a02 100644
--- a/api/module-lib-lint-baseline.txt
+++ b/api/module-lib-lint-baseline.txt
@@ -27,7 +27,3 @@
     Public class android.location.GnssAntennaInfo.PhaseCenterVariationCorrections extends private class android.location.GnssAntennaInfo.SphericalCorrections
 PrivateSuperclass: android.location.GnssAntennaInfo.SignalGainCorrections:
     Public class android.location.GnssAntennaInfo.SignalGainCorrections extends private class android.location.GnssAntennaInfo.SphericalCorrections
-
-
-StaticUtils: android.net.TetheringConstants:
-    Fully-static utility classes must not have constructor
diff --git a/api/system-current.txt b/api/system-current.txt
index 202a939..2d5655a 100755
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -137,7 +137,6 @@
     field public static final String MODIFY_PARENTAL_CONTROLS = "android.permission.MODIFY_PARENTAL_CONTROLS";
     field public static final String MODIFY_QUIET_MODE = "android.permission.MODIFY_QUIET_MODE";
     field public static final String MODIFY_SETTINGS_OVERRIDEABLE_BY_RESTORE = "android.permission.MODIFY_SETTINGS_OVERRIDEABLE_BY_RESTORE";
-    field public static final String MONITOR_DEVICE_CONFIG_ACCESS = "android.permission.MONITOR_DEVICE_CONFIG_ACCESS";
     field public static final String MOVE_PACKAGE = "android.permission.MOVE_PACKAGE";
     field public static final String NETWORK_AIRPLANE_MODE = "android.permission.NETWORK_AIRPLANE_MODE";
     field public static final String NETWORK_CARRIER_PROVISIONING = "android.permission.NETWORK_CARRIER_PROVISIONING";
@@ -631,10 +630,10 @@
     method public android.content.Intent createConfirmFactoryResetCredentialIntent(CharSequence, CharSequence, CharSequence);
     method @RequiresPermission("android.permission.SET_INITIAL_LOCK") public int getMinLockLength(boolean, int);
     method @RequiresPermission(android.Manifest.permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS) public boolean getPrivateNotificationsAllowed();
+    method @RequiresPermission("android.permission.SET_INITIAL_LOCK") public boolean isValidLockPasswordComplexity(int, @NonNull byte[], int);
     method @RequiresPermission(android.Manifest.permission.SHOW_KEYGUARD_MESSAGE) public void requestDismissKeyguard(@NonNull android.app.Activity, @Nullable CharSequence, @Nullable android.app.KeyguardManager.KeyguardDismissCallback);
     method @RequiresPermission("android.permission.SET_INITIAL_LOCK") public boolean setLock(int, @NonNull byte[], int);
     method @RequiresPermission(android.Manifest.permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS) public void setPrivateNotificationsAllowed(boolean);
-    method @RequiresPermission("android.permission.SET_INITIAL_LOCK") public boolean validateLockPasswordComplexity(boolean, @NonNull byte[], int);
   }
 
   public class Notification implements android.os.Parcelable {
@@ -1959,6 +1958,11 @@
     method @NonNull public static android.content.integrity.IntegrityFormula packageNameEquals(@NonNull String);
   }
 
+  public static final class IntegrityFormula.SourceStamp {
+    method @NonNull public static android.content.integrity.IntegrityFormula notTrusted();
+    method @NonNull public static android.content.integrity.IntegrityFormula stampCertificateHashEquals(@NonNull String);
+  }
+
   public final class Rule implements android.os.Parcelable {
     ctor public Rule(@NonNull android.content.integrity.IntegrityFormula, int);
     method public int describeContents();
@@ -3776,8 +3780,14 @@
     method @RequiresPermission(android.Manifest.permission.MANAGE_USB) public void setCurrentFunctions(long);
     field @RequiresPermission(android.Manifest.permission.MANAGE_USB) public static final String ACTION_USB_PORT_CHANGED = "android.hardware.usb.action.USB_PORT_CHANGED";
     field public static final String ACTION_USB_STATE = "android.hardware.usb.action.USB_STATE";
+    field public static final long FUNCTION_ACCESSORY = 2L; // 0x2L
+    field public static final long FUNCTION_ADB = 1L; // 0x1L
+    field public static final long FUNCTION_AUDIO_SOURCE = 64L; // 0x40L
+    field public static final long FUNCTION_MIDI = 8L; // 0x8L
+    field public static final long FUNCTION_MTP = 4L; // 0x4L
     field public static final long FUNCTION_NCM = 1024L; // 0x400L
     field public static final long FUNCTION_NONE = 0L; // 0x0L
+    field public static final long FUNCTION_PTP = 16L; // 0x10L
     field public static final long FUNCTION_RNDIS = 32L; // 0x20L
     field public static final String USB_CONFIGURED = "configured";
     field public static final String USB_CONNECTED = "connected";
@@ -6737,337 +6747,6 @@
 
 }
 
-package android.net.eap {
-
-  public final class EapSessionConfig {
-  }
-
-  public static final class EapSessionConfig.Builder {
-    ctor public EapSessionConfig.Builder();
-    method @NonNull public android.net.eap.EapSessionConfig build();
-    method @NonNull public android.net.eap.EapSessionConfig.Builder setEapAkaConfig(int, int);
-    method @NonNull public android.net.eap.EapSessionConfig.Builder setEapAkaPrimeConfig(int, int, @NonNull String, boolean);
-    method @NonNull public android.net.eap.EapSessionConfig.Builder setEapIdentity(@NonNull byte[]);
-    method @NonNull public android.net.eap.EapSessionConfig.Builder setEapMsChapV2Config(@NonNull String, @NonNull String);
-    method @NonNull public android.net.eap.EapSessionConfig.Builder setEapSimConfig(int, int);
-  }
-
-  public static class EapSessionConfig.EapAkaConfig extends android.net.eap.EapSessionConfig.EapUiccConfig {
-  }
-
-  public static class EapSessionConfig.EapAkaPrimeConfig extends android.net.eap.EapSessionConfig.EapAkaConfig {
-    method public boolean allowsMismatchedNetworkNames();
-    method @NonNull public String getNetworkName();
-  }
-
-  public abstract static class EapSessionConfig.EapMethodConfig {
-    method public int getMethodType();
-  }
-
-  public static class EapSessionConfig.EapMsChapV2Config extends android.net.eap.EapSessionConfig.EapMethodConfig {
-    method @NonNull public String getPassword();
-    method @NonNull public String getUsername();
-  }
-
-  public static class EapSessionConfig.EapSimConfig extends android.net.eap.EapSessionConfig.EapUiccConfig {
-  }
-
-  public abstract static class EapSessionConfig.EapUiccConfig extends android.net.eap.EapSessionConfig.EapMethodConfig {
-    method public int getAppType();
-    method public int getSubId();
-  }
-
-}
-
-package android.net.ipsec.ike {
-
-  public final class ChildSaProposal extends android.net.ipsec.ike.SaProposal {
-  }
-
-  public static final class ChildSaProposal.Builder {
-    ctor public ChildSaProposal.Builder();
-    method @NonNull public android.net.ipsec.ike.ChildSaProposal.Builder addDhGroup(int);
-    method @NonNull public android.net.ipsec.ike.ChildSaProposal.Builder addEncryptionAlgorithm(int, int);
-    method @NonNull public android.net.ipsec.ike.ChildSaProposal.Builder addIntegrityAlgorithm(int);
-    method @NonNull public android.net.ipsec.ike.ChildSaProposal build();
-  }
-
-  public interface ChildSessionCallback {
-    method public void onClosed();
-    method public void onClosedExceptionally(@NonNull android.net.ipsec.ike.exceptions.IkeException);
-    method public void onIpSecTransformCreated(@NonNull android.net.IpSecTransform, int);
-    method public void onIpSecTransformDeleted(@NonNull android.net.IpSecTransform, int);
-    method public void onOpened(@NonNull android.net.ipsec.ike.ChildSessionConfiguration);
-  }
-
-  public final class ChildSessionConfiguration {
-    method @NonNull public java.util.List<android.net.ipsec.ike.IkeTrafficSelector> getInboundTrafficSelectors();
-    method @NonNull public java.util.List<android.net.LinkAddress> getInternalAddresses();
-    method @NonNull public java.util.List<java.net.InetAddress> getInternalDhcpServers();
-    method @NonNull public java.util.List<java.net.InetAddress> getInternalDnsServers();
-    method @NonNull public java.util.List<android.net.IpPrefix> getInternalSubnets();
-    method @NonNull public java.util.List<android.net.ipsec.ike.IkeTrafficSelector> getOutboundTrafficSelectors();
-  }
-
-  public abstract class ChildSessionParams {
-    method public long getHardLifetime();
-    method @NonNull public java.util.List<android.net.ipsec.ike.IkeTrafficSelector> getLocalTrafficSelectors();
-    method @NonNull public java.util.List<android.net.ipsec.ike.IkeTrafficSelector> getRemoteTrafficSelectors();
-    method @NonNull public java.util.List<android.net.ipsec.ike.ChildSaProposal> getSaProposals();
-    method public long getSoftLifetime();
-  }
-
-  public class IkeFqdnIdentification extends android.net.ipsec.ike.IkeIdentification {
-    ctor public IkeFqdnIdentification(@NonNull String);
-    field @NonNull public final String fqdn;
-  }
-
-  public abstract class IkeIdentification {
-  }
-
-  public final class IkeIpv4AddrIdentification extends android.net.ipsec.ike.IkeIdentification {
-    ctor public IkeIpv4AddrIdentification(@NonNull java.net.Inet4Address);
-    field @NonNull public final java.net.Inet4Address ipv4Address;
-  }
-
-  public class IkeIpv6AddrIdentification extends android.net.ipsec.ike.IkeIdentification {
-    ctor public IkeIpv6AddrIdentification(@NonNull java.net.Inet6Address);
-    field @NonNull public final java.net.Inet6Address ipv6Address;
-  }
-
-  public final class IkeKeyIdIdentification extends android.net.ipsec.ike.IkeIdentification {
-    ctor public IkeKeyIdIdentification(@NonNull byte[]);
-    field @NonNull public final byte[] keyId;
-  }
-
-  public final class IkeRfc822AddrIdentification extends android.net.ipsec.ike.IkeIdentification {
-    ctor public IkeRfc822AddrIdentification(@NonNull String);
-    field @NonNull public final String rfc822Name;
-  }
-
-  public final class IkeSaProposal extends android.net.ipsec.ike.SaProposal {
-    method @NonNull public java.util.List<java.lang.Integer> getPseudorandomFunctions();
-  }
-
-  public static final class IkeSaProposal.Builder {
-    ctor public IkeSaProposal.Builder();
-    method @NonNull public android.net.ipsec.ike.IkeSaProposal.Builder addDhGroup(int);
-    method @NonNull public android.net.ipsec.ike.IkeSaProposal.Builder addEncryptionAlgorithm(int, int);
-    method @NonNull public android.net.ipsec.ike.IkeSaProposal.Builder addIntegrityAlgorithm(int);
-    method @NonNull public android.net.ipsec.ike.IkeSaProposal.Builder addPseudorandomFunction(int);
-    method @NonNull public android.net.ipsec.ike.IkeSaProposal build();
-  }
-
-  public final class IkeSession implements java.lang.AutoCloseable {
-    ctor public IkeSession(@NonNull android.content.Context, @NonNull android.net.ipsec.ike.IkeSessionParams, @NonNull android.net.ipsec.ike.ChildSessionParams, @NonNull java.util.concurrent.Executor, @NonNull android.net.ipsec.ike.IkeSessionCallback, @NonNull android.net.ipsec.ike.ChildSessionCallback);
-    method public void close();
-    method public void closeChildSession(@NonNull android.net.ipsec.ike.ChildSessionCallback);
-    method public void kill();
-    method public void openChildSession(@NonNull android.net.ipsec.ike.ChildSessionParams, @NonNull android.net.ipsec.ike.ChildSessionCallback);
-  }
-
-  public interface IkeSessionCallback {
-    method public void onClosed();
-    method public void onClosedExceptionally(@NonNull android.net.ipsec.ike.exceptions.IkeException);
-    method public void onError(@NonNull android.net.ipsec.ike.exceptions.IkeProtocolException);
-    method public void onOpened(@NonNull android.net.ipsec.ike.IkeSessionConfiguration);
-  }
-
-  public final class IkeSessionConfiguration {
-    method @NonNull public java.util.List<java.net.InetAddress> getPcscfServers();
-    method @NonNull public String getRemoteApplicationVersion();
-    method @NonNull public java.util.List<byte[]> getRemoteVendorIDs();
-    method public boolean isIkeExtensionEnabled(int);
-    field public static final int EXTENSION_TYPE_FRAGMENTATION = 1; // 0x1
-    field public static final int EXTENSION_TYPE_MOBIKE = 2; // 0x2
-  }
-
-  public final class IkeSessionParams {
-    method @NonNull public java.util.List<android.net.ipsec.ike.IkeSessionParams.IkeConfigRequest> getConfigurationRequests();
-    method public long getHardLifetime();
-    method @NonNull public android.net.ipsec.ike.IkeSessionParams.IkeAuthConfig getLocalAuthConfig();
-    method @NonNull public android.net.ipsec.ike.IkeIdentification getLocalIdentification();
-    method @NonNull public android.net.ipsec.ike.IkeSessionParams.IkeAuthConfig getRemoteAuthConfig();
-    method @NonNull public android.net.ipsec.ike.IkeIdentification getRemoteIdentification();
-    method @NonNull public java.util.List<android.net.ipsec.ike.IkeSaProposal> getSaProposals();
-    method @NonNull public java.net.InetAddress getServerAddress();
-    method public long getSoftLifetime();
-    method @NonNull public android.net.IpSecManager.UdpEncapsulationSocket getUdpEncapsulationSocket();
-  }
-
-  public static final class IkeSessionParams.Builder {
-    ctor public IkeSessionParams.Builder();
-    method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder addPcscfServerRequest(@NonNull java.net.InetAddress);
-    method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder addPcscfServerRequest(int);
-    method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder addSaProposal(@NonNull android.net.ipsec.ike.IkeSaProposal);
-    method @NonNull public android.net.ipsec.ike.IkeSessionParams build();
-    method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setAuthDigitalSignature(@Nullable java.security.cert.X509Certificate, @NonNull java.security.cert.X509Certificate, @NonNull java.security.PrivateKey);
-    method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setAuthDigitalSignature(@Nullable java.security.cert.X509Certificate, @NonNull java.security.cert.X509Certificate, @NonNull java.util.List<java.security.cert.X509Certificate>, @NonNull java.security.PrivateKey);
-    method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setAuthEap(@Nullable java.security.cert.X509Certificate, @NonNull android.net.eap.EapSessionConfig);
-    method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setAuthPsk(@NonNull byte[]);
-    method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setLifetime(long, long);
-    method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setLocalIdentification(@NonNull android.net.ipsec.ike.IkeIdentification);
-    method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setRemoteIdentification(@NonNull android.net.ipsec.ike.IkeIdentification);
-    method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setServerAddress(@NonNull java.net.InetAddress);
-    method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setUdpEncapsulationSocket(@NonNull android.net.IpSecManager.UdpEncapsulationSocket);
-  }
-
-  public static interface IkeSessionParams.ConfigRequestIpv4PcscfServer extends android.net.ipsec.ike.IkeSessionParams.IkeConfigRequest {
-    method @Nullable public java.net.Inet4Address getAddress();
-  }
-
-  public static interface IkeSessionParams.ConfigRequestIpv6PcscfServer extends android.net.ipsec.ike.IkeSessionParams.IkeConfigRequest {
-    method @Nullable public java.net.Inet6Address getAddress();
-  }
-
-  public abstract static class IkeSessionParams.IkeAuthConfig {
-  }
-
-  public static class IkeSessionParams.IkeAuthDigitalSignLocalConfig extends android.net.ipsec.ike.IkeSessionParams.IkeAuthConfig {
-    method @NonNull public java.security.cert.X509Certificate getClientEndCertificate();
-    method @NonNull public java.util.List<java.security.cert.X509Certificate> getIntermediateCertificates();
-    method @NonNull public java.security.PrivateKey getPrivateKey();
-  }
-
-  public static class IkeSessionParams.IkeAuthDigitalSignRemoteConfig extends android.net.ipsec.ike.IkeSessionParams.IkeAuthConfig {
-    method @Nullable public java.security.cert.X509Certificate getRemoteCaCert();
-  }
-
-  public static class IkeSessionParams.IkeAuthEapConfig extends android.net.ipsec.ike.IkeSessionParams.IkeAuthConfig {
-    method @NonNull public android.net.eap.EapSessionConfig getEapConfig();
-  }
-
-  public static class IkeSessionParams.IkeAuthPskConfig extends android.net.ipsec.ike.IkeSessionParams.IkeAuthConfig {
-    method @NonNull public byte[] getPsk();
-  }
-
-  public static interface IkeSessionParams.IkeConfigRequest {
-  }
-
-  public final class IkeTrafficSelector {
-    ctor public IkeTrafficSelector(int, int, @NonNull java.net.InetAddress, @NonNull java.net.InetAddress);
-    field public final int endPort;
-    field @NonNull public final java.net.InetAddress endingAddress;
-    field public final int startPort;
-    field @NonNull public final java.net.InetAddress startingAddress;
-  }
-
-  public abstract class SaProposal {
-    method @NonNull public java.util.List<java.lang.Integer> getDhGroups();
-    method @NonNull public java.util.List<android.util.Pair<java.lang.Integer,java.lang.Integer>> getEncryptionAlgorithms();
-    method @NonNull public java.util.List<java.lang.Integer> getIntegrityAlgorithms();
-    field public static final int DH_GROUP_1024_BIT_MODP = 2; // 0x2
-    field public static final int DH_GROUP_2048_BIT_MODP = 14; // 0xe
-    field public static final int DH_GROUP_NONE = 0; // 0x0
-    field public static final int ENCRYPTION_ALGORITHM_3DES = 3; // 0x3
-    field public static final int ENCRYPTION_ALGORITHM_AES_CBC = 12; // 0xc
-    field public static final int ENCRYPTION_ALGORITHM_AES_GCM_12 = 19; // 0x13
-    field public static final int ENCRYPTION_ALGORITHM_AES_GCM_16 = 20; // 0x14
-    field public static final int ENCRYPTION_ALGORITHM_AES_GCM_8 = 18; // 0x12
-    field public static final int INTEGRITY_ALGORITHM_AES_XCBC_96 = 5; // 0x5
-    field public static final int INTEGRITY_ALGORITHM_HMAC_SHA1_96 = 2; // 0x2
-    field public static final int INTEGRITY_ALGORITHM_HMAC_SHA2_256_128 = 12; // 0xc
-    field public static final int INTEGRITY_ALGORITHM_HMAC_SHA2_384_192 = 13; // 0xd
-    field public static final int INTEGRITY_ALGORITHM_HMAC_SHA2_512_256 = 14; // 0xe
-    field public static final int INTEGRITY_ALGORITHM_NONE = 0; // 0x0
-    field public static final int KEY_LEN_AES_128 = 128; // 0x80
-    field public static final int KEY_LEN_AES_192 = 192; // 0xc0
-    field public static final int KEY_LEN_AES_256 = 256; // 0x100
-    field public static final int KEY_LEN_UNUSED = 0; // 0x0
-    field public static final int PSEUDORANDOM_FUNCTION_AES128_XCBC = 4; // 0x4
-    field public static final int PSEUDORANDOM_FUNCTION_HMAC_SHA1 = 2; // 0x2
-  }
-
-  public final class TransportModeChildSessionParams extends android.net.ipsec.ike.ChildSessionParams {
-  }
-
-  public static final class TransportModeChildSessionParams.Builder {
-    ctor public TransportModeChildSessionParams.Builder();
-    method @NonNull public android.net.ipsec.ike.TransportModeChildSessionParams.Builder addInboundTrafficSelectors(@NonNull android.net.ipsec.ike.IkeTrafficSelector);
-    method @NonNull public android.net.ipsec.ike.TransportModeChildSessionParams.Builder addOutboundTrafficSelectors(@NonNull android.net.ipsec.ike.IkeTrafficSelector);
-    method @NonNull public android.net.ipsec.ike.TransportModeChildSessionParams.Builder addSaProposal(@NonNull android.net.ipsec.ike.ChildSaProposal);
-    method @NonNull public android.net.ipsec.ike.TransportModeChildSessionParams build();
-    method @NonNull public android.net.ipsec.ike.TransportModeChildSessionParams.Builder setLifetime(long, long);
-  }
-
-  public final class TunnelModeChildSessionParams extends android.net.ipsec.ike.ChildSessionParams {
-    method @NonNull public java.util.List<android.net.ipsec.ike.TunnelModeChildSessionParams.TunnelModeChildConfigRequest> getConfigurationRequests();
-  }
-
-  public static final class TunnelModeChildSessionParams.Builder {
-    ctor public TunnelModeChildSessionParams.Builder();
-    method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams.Builder addInboundTrafficSelectors(@NonNull android.net.ipsec.ike.IkeTrafficSelector);
-    method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams.Builder addInternalAddressRequest(int);
-    method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams.Builder addInternalAddressRequest(@NonNull java.net.Inet4Address);
-    method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams.Builder addInternalAddressRequest(@NonNull java.net.Inet6Address, int);
-    method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams.Builder addInternalDhcpServerRequest(int);
-    method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams.Builder addInternalDnsServerRequest(int);
-    method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams.Builder addOutboundTrafficSelectors(@NonNull android.net.ipsec.ike.IkeTrafficSelector);
-    method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams.Builder addSaProposal(@NonNull android.net.ipsec.ike.ChildSaProposal);
-    method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams build();
-    method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams.Builder setLifetime(long, long);
-  }
-
-  public static interface TunnelModeChildSessionParams.ConfigRequestIpv4Address extends android.net.ipsec.ike.TunnelModeChildSessionParams.TunnelModeChildConfigRequest {
-    method @Nullable public java.net.Inet4Address getAddress();
-  }
-
-  public static interface TunnelModeChildSessionParams.ConfigRequestIpv4DhcpServer extends android.net.ipsec.ike.TunnelModeChildSessionParams.TunnelModeChildConfigRequest {
-    method @Nullable public java.net.Inet4Address getAddress();
-  }
-
-  public static interface TunnelModeChildSessionParams.ConfigRequestIpv4DnsServer extends android.net.ipsec.ike.TunnelModeChildSessionParams.TunnelModeChildConfigRequest {
-    method @Nullable public java.net.Inet4Address getAddress();
-  }
-
-  public static interface TunnelModeChildSessionParams.ConfigRequestIpv4Netmask extends android.net.ipsec.ike.TunnelModeChildSessionParams.TunnelModeChildConfigRequest {
-  }
-
-  public static interface TunnelModeChildSessionParams.ConfigRequestIpv6Address extends android.net.ipsec.ike.TunnelModeChildSessionParams.TunnelModeChildConfigRequest {
-    method @Nullable public java.net.Inet6Address getAddress();
-    method public int getPrefixLength();
-  }
-
-  public static interface TunnelModeChildSessionParams.ConfigRequestIpv6DnsServer extends android.net.ipsec.ike.TunnelModeChildSessionParams.TunnelModeChildConfigRequest {
-    method @Nullable public java.net.Inet6Address getAddress();
-  }
-
-  public static interface TunnelModeChildSessionParams.TunnelModeChildConfigRequest {
-  }
-
-}
-
-package android.net.ipsec.ike.exceptions {
-
-  public abstract class IkeException extends java.lang.Exception {
-  }
-
-  public final class IkeInternalException extends android.net.ipsec.ike.exceptions.IkeException {
-  }
-
-  public abstract class IkeProtocolException extends android.net.ipsec.ike.exceptions.IkeException {
-    method @Nullable public byte[] getErrorData();
-    method public int getErrorType();
-    field public static final int ERROR_TYPE_AUTHENTICATION_FAILED = 24; // 0x18
-    field public static final int ERROR_TYPE_CHILD_SA_NOT_FOUND = 44; // 0x2c
-    field public static final int ERROR_TYPE_FAILED_CP_REQUIRED = 37; // 0x25
-    field public static final int ERROR_TYPE_INTERNAL_ADDRESS_FAILURE = 36; // 0x24
-    field public static final int ERROR_TYPE_INVALID_IKE_SPI = 4; // 0x4
-    field public static final int ERROR_TYPE_INVALID_KE_PAYLOAD = 17; // 0x11
-    field public static final int ERROR_TYPE_INVALID_MAJOR_VERSION = 5; // 0x5
-    field public static final int ERROR_TYPE_INVALID_MESSAGE_ID = 9; // 0x9
-    field public static final int ERROR_TYPE_INVALID_SELECTORS = 39; // 0x27
-    field public static final int ERROR_TYPE_INVALID_SYNTAX = 7; // 0x7
-    field public static final int ERROR_TYPE_NO_ADDITIONAL_SAS = 35; // 0x23
-    field public static final int ERROR_TYPE_NO_PROPOSAL_CHOSEN = 14; // 0xe
-    field public static final int ERROR_TYPE_SINGLE_PAIR_REQUIRED = 34; // 0x22
-    field public static final int ERROR_TYPE_TEMPORARY_FAILURE = 43; // 0x2b
-    field public static final int ERROR_TYPE_TS_UNACCEPTABLE = 38; // 0x26
-    field public static final int ERROR_TYPE_UNSUPPORTED_CRITICAL_PAYLOAD = 1; // 0x1
-  }
-
-}
-
 package android.net.metrics {
 
   public final class ApfProgramEvent implements android.net.metrics.IpConnectivityLog.Event {
@@ -9078,7 +8757,9 @@
 
   public class UserManager {
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public void clearSeedAccountData();
-    method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public android.os.UserHandle createProfile(@NonNull String, @NonNull String, @Nullable String[]) throws android.os.UserManager.UserOperationException;
+    method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public android.os.UserHandle createProfile(@NonNull String, @NonNull String, @NonNull java.util.Set<java.lang.String>) throws android.os.UserManager.UserOperationException;
+    method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}, conditional=true) public java.util.List<android.os.UserHandle> getAllProfiles();
+    method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}, conditional=true) public java.util.List<android.os.UserHandle> getEnabledProfiles();
     method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public android.os.UserHandle getProfileParent(@NonNull android.os.UserHandle);
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public String getSeedAccountName();
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public android.os.PersistableBundle getSeedAccountOptions();
@@ -9086,7 +8767,6 @@
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public long[] getSerialNumbersOfUsers(boolean);
     method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public java.util.List<android.os.UserHandle> getUserHandles(boolean);
     method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.GET_ACCOUNTS_PRIVILEGED}) public android.graphics.Bitmap getUserIcon();
-    method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}, conditional=true) public java.util.List<android.os.UserHandle> getUserProfiles(boolean);
     method @Deprecated @android.os.UserManager.UserRestrictionSource @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public int getUserRestrictionSource(String, android.os.UserHandle);
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public java.util.List<android.os.UserManager.EnforcingUser> getUserRestrictionSources(String, android.os.UserHandle);
     method @RequiresPermission(allOf={android.Manifest.permission.READ_PHONE_STATE, android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional=true) public int getUserSwitchability();
@@ -10212,6 +9892,7 @@
   public abstract class InlineSuggestionRenderService extends android.app.Service {
     ctor public InlineSuggestionRenderService();
     method @Nullable public final android.os.IBinder onBind(@NonNull android.content.Intent);
+    method @Nullable public android.os.Bundle onGetInlineSuggestionsRendererInfo();
     method @Nullable public android.view.View onRenderSuggestion(@NonNull android.service.autofill.InlinePresentation, int, int);
     field public static final String SERVICE_INTERFACE = "android.service.autofill.InlineSuggestionRenderService";
   }
@@ -11389,347 +11070,7 @@
   }
 
   public final class DataFailCause {
-    field public static final int ACCESS_ATTEMPT_ALREADY_IN_PROGRESS = 2219; // 0x8ab
-    field public static final int ACCESS_BLOCK = 2087; // 0x827
-    field public static final int ACCESS_BLOCK_ALL = 2088; // 0x828
-    field public static final int ACCESS_CLASS_DSAC_REJECTION = 2108; // 0x83c
-    field public static final int ACCESS_CONTROL_LIST_CHECK_FAILURE = 2128; // 0x850
-    field public static final int ACTIVATION_REJECTED_BCM_VIOLATION = 48; // 0x30
-    field public static final int ACTIVATION_REJECT_GGSN = 30; // 0x1e
-    field public static final int ACTIVATION_REJECT_UNSPECIFIED = 31; // 0x1f
-    field public static final int ACTIVE_PDP_CONTEXT_MAX_NUMBER_REACHED = 65; // 0x41
-    field public static final int APN_DISABLED = 2045; // 0x7fd
-    field public static final int APN_DISALLOWED_ON_ROAMING = 2059; // 0x80b
-    field public static final int APN_MISMATCH = 2054; // 0x806
-    field public static final int APN_PARAMETERS_CHANGED = 2060; // 0x80c
-    field public static final int APN_PENDING_HANDOVER = 2041; // 0x7f9
-    field public static final int APN_TYPE_CONFLICT = 112; // 0x70
-    field public static final int AUTH_FAILURE_ON_EMERGENCY_CALL = 122; // 0x7a
-    field public static final int BEARER_HANDLING_NOT_SUPPORTED = 60; // 0x3c
-    field public static final int CALL_DISALLOWED_IN_ROAMING = 2068; // 0x814
-    field public static final int CALL_PREEMPT_BY_EMERGENCY_APN = 127; // 0x7f
-    field public static final int CANNOT_ENCODE_OTA_MESSAGE = 2159; // 0x86f
-    field public static final int CDMA_ALERT_STOP = 2077; // 0x81d
-    field public static final int CDMA_INCOMING_CALL = 2076; // 0x81c
-    field public static final int CDMA_INTERCEPT = 2073; // 0x819
-    field public static final int CDMA_LOCK = 2072; // 0x818
-    field public static final int CDMA_RELEASE_DUE_TO_SO_REJECTION = 2075; // 0x81b
-    field public static final int CDMA_REORDER = 2074; // 0x81a
-    field public static final int CDMA_RETRY_ORDER = 2086; // 0x826
-    field public static final int CHANNEL_ACQUISITION_FAILURE = 2078; // 0x81e
-    field public static final int CLOSE_IN_PROGRESS = 2030; // 0x7ee
-    field public static final int COLLISION_WITH_NETWORK_INITIATED_REQUEST = 56; // 0x38
-    field public static final int COMPANION_IFACE_IN_USE = 118; // 0x76
-    field public static final int CONCURRENT_SERVICES_INCOMPATIBLE = 2083; // 0x823
-    field public static final int CONCURRENT_SERVICES_NOT_ALLOWED = 2091; // 0x82b
-    field public static final int CONCURRENT_SERVICE_NOT_SUPPORTED_BY_BASE_STATION = 2080; // 0x820
-    field public static final int CONDITIONAL_IE_ERROR = 100; // 0x64
-    field public static final int CONGESTION = 2106; // 0x83a
-    field public static final int CONNECTION_RELEASED = 2113; // 0x841
-    field public static final int CS_DOMAIN_NOT_AVAILABLE = 2181; // 0x885
-    field public static final int CS_FALLBACK_CALL_ESTABLISHMENT_NOT_ALLOWED = 2188; // 0x88c
-    field public static final int DATA_PLAN_EXPIRED = 2198; // 0x896
-    field public static final int DATA_ROAMING_SETTINGS_DISABLED = 2064; // 0x810
-    field public static final int DATA_SETTINGS_DISABLED = 2063; // 0x80f
-    field public static final int DBM_OR_SMS_IN_PROGRESS = 2211; // 0x8a3
-    field public static final int DDS_SWITCHED = 2065; // 0x811
-    field public static final int DDS_SWITCH_IN_PROGRESS = 2067; // 0x813
-    field public static final int DRB_RELEASED_BY_RRC = 2112; // 0x840
-    field public static final int DS_EXPLICIT_DEACTIVATION = 2125; // 0x84d
-    field public static final int DUAL_SWITCH = 2227; // 0x8b3
-    field public static final int DUN_CALL_DISALLOWED = 2056; // 0x808
-    field public static final int DUPLICATE_BEARER_ID = 2118; // 0x846
-    field public static final int EHRPD_TO_HRPD_FALLBACK = 2049; // 0x801
-    field public static final int EMBMS_NOT_ENABLED = 2193; // 0x891
-    field public static final int EMBMS_REGULAR_DEACTIVATION = 2195; // 0x893
-    field public static final int EMERGENCY_IFACE_ONLY = 116; // 0x74
-    field public static final int EMERGENCY_MODE = 2221; // 0x8ad
-    field public static final int EMM_ACCESS_BARRED = 115; // 0x73
-    field public static final int EMM_ACCESS_BARRED_INFINITE_RETRY = 121; // 0x79
-    field public static final int EMM_ATTACH_FAILED = 2115; // 0x843
-    field public static final int EMM_ATTACH_STARTED = 2116; // 0x844
-    field public static final int EMM_DETACHED = 2114; // 0x842
-    field public static final int EMM_T3417_EXPIRED = 2130; // 0x852
-    field public static final int EMM_T3417_EXT_EXPIRED = 2131; // 0x853
-    field public static final int EPS_SERVICES_AND_NON_EPS_SERVICES_NOT_ALLOWED = 2178; // 0x882
-    field public static final int EPS_SERVICES_NOT_ALLOWED_IN_PLMN = 2179; // 0x883
-    field public static final int ERROR_UNSPECIFIED = 65535; // 0xffff
-    field public static final int ESM_BAD_OTA_MESSAGE = 2122; // 0x84a
-    field public static final int ESM_BEARER_DEACTIVATED_TO_SYNC_WITH_NETWORK = 2120; // 0x848
-    field public static final int ESM_COLLISION_SCENARIOS = 2119; // 0x847
-    field public static final int ESM_CONTEXT_TRANSFERRED_DUE_TO_IRAT = 2124; // 0x84c
-    field public static final int ESM_DOWNLOAD_SERVER_REJECTED_THE_CALL = 2123; // 0x84b
-    field public static final int ESM_FAILURE = 2182; // 0x886
-    field public static final int ESM_INFO_NOT_RECEIVED = 53; // 0x35
-    field public static final int ESM_LOCAL_CAUSE_NONE = 2126; // 0x84e
-    field public static final int ESM_NW_ACTIVATED_DED_BEARER_WITH_ID_OF_DEF_BEARER = 2121; // 0x849
-    field public static final int ESM_PROCEDURE_TIME_OUT = 2155; // 0x86b
-    field public static final int ESM_UNKNOWN_EPS_BEARER_CONTEXT = 2111; // 0x83f
-    field public static final int EVDO_CONNECTION_DENY_BY_BILLING_OR_AUTHENTICATION_FAILURE = 2201; // 0x899
-    field public static final int EVDO_CONNECTION_DENY_BY_GENERAL_OR_NETWORK_BUSY = 2200; // 0x898
-    field public static final int EVDO_HDR_CHANGED = 2202; // 0x89a
-    field public static final int EVDO_HDR_CONNECTION_SETUP_TIMEOUT = 2206; // 0x89e
-    field public static final int EVDO_HDR_EXITED = 2203; // 0x89b
-    field public static final int EVDO_HDR_NO_SESSION = 2204; // 0x89c
-    field public static final int EVDO_USING_GPS_FIX_INSTEAD_OF_HDR_CALL = 2205; // 0x89d
-    field public static final int FADE = 2217; // 0x8a9
-    field public static final int FAILED_TO_ACQUIRE_COLOCATED_HDR = 2207; // 0x89f
-    field public static final int FEATURE_NOT_SUPP = 40; // 0x28
-    field public static final int FILTER_SEMANTIC_ERROR = 44; // 0x2c
-    field public static final int FILTER_SYTAX_ERROR = 45; // 0x2d
-    field public static final int FORBIDDEN_APN_NAME = 2066; // 0x812
-    field public static final int GPRS_REGISTRATION_FAIL = -2; // 0xfffffffe
-    field public static final int GPRS_SERVICES_AND_NON_GPRS_SERVICES_NOT_ALLOWED = 2097; // 0x831
-    field public static final int GPRS_SERVICES_NOT_ALLOWED = 2098; // 0x832
-    field public static final int GPRS_SERVICES_NOT_ALLOWED_IN_THIS_PLMN = 2103; // 0x837
-    field public static final int HANDOFF_PREFERENCE_CHANGED = 2251; // 0x8cb
-    field public static final int HDR_ACCESS_FAILURE = 2213; // 0x8a5
-    field public static final int HDR_FADE = 2212; // 0x8a4
-    field public static final int HDR_NO_LOCK_GRANTED = 2210; // 0x8a2
-    field public static final int IFACE_AND_POL_FAMILY_MISMATCH = 120; // 0x78
-    field public static final int IFACE_MISMATCH = 117; // 0x75
-    field public static final int ILLEGAL_ME = 2096; // 0x830
-    field public static final int ILLEGAL_MS = 2095; // 0x82f
-    field public static final int IMEI_NOT_ACCEPTED = 2177; // 0x881
-    field public static final int IMPLICITLY_DETACHED = 2100; // 0x834
-    field public static final int IMSI_UNKNOWN_IN_HOME_SUBSCRIBER_SERVER = 2176; // 0x880
-    field public static final int INCOMING_CALL_REJECTED = 2092; // 0x82c
-    field public static final int INSUFFICIENT_RESOURCES = 26; // 0x1a
-    field public static final int INTERFACE_IN_USE = 2058; // 0x80a
-    field public static final int INTERNAL_CALL_PREEMPT_BY_HIGH_PRIO_APN = 114; // 0x72
-    field public static final int INTERNAL_EPC_NONEPC_TRANSITION = 2057; // 0x809
-    field public static final int INVALID_CONNECTION_ID = 2156; // 0x86c
-    field public static final int INVALID_DNS_ADDR = 123; // 0x7b
-    field public static final int INVALID_EMM_STATE = 2190; // 0x88e
-    field public static final int INVALID_MANDATORY_INFO = 96; // 0x60
-    field public static final int INVALID_MODE = 2223; // 0x8af
-    field public static final int INVALID_PCSCF_ADDR = 113; // 0x71
-    field public static final int INVALID_PCSCF_OR_DNS_ADDRESS = 124; // 0x7c
-    field public static final int INVALID_PRIMARY_NSAPI = 2158; // 0x86e
-    field public static final int INVALID_SIM_STATE = 2224; // 0x8b0
-    field public static final int INVALID_TRANSACTION_ID = 81; // 0x51
-    field public static final int IPV6_ADDRESS_TRANSFER_FAILED = 2047; // 0x7ff
-    field public static final int IPV6_PREFIX_UNAVAILABLE = 2250; // 0x8ca
-    field public static final int IP_ADDRESS_MISMATCH = 119; // 0x77
-    field public static final int IP_VERSION_MISMATCH = 2055; // 0x807
-    field public static final int IRAT_HANDOVER_FAILED = 2194; // 0x892
-    field public static final int IS707B_MAX_ACCESS_PROBES = 2089; // 0x829
-    field public static final int LIMITED_TO_IPV4 = 2234; // 0x8ba
-    field public static final int LIMITED_TO_IPV6 = 2235; // 0x8bb
-    field public static final int LLC_SNDCP = 25; // 0x19
-    field public static final int LOCAL_END = 2215; // 0x8a7
-    field public static final int LOCATION_AREA_NOT_ALLOWED = 2102; // 0x836
-    field public static final int LOST_CONNECTION = 65540; // 0x10004
-    field public static final int LOWER_LAYER_REGISTRATION_FAILURE = 2197; // 0x895
-    field public static final int LOW_POWER_MODE_OR_POWERING_DOWN = 2044; // 0x7fc
-    field public static final int LTE_NAS_SERVICE_REQUEST_FAILED = 2117; // 0x845
-    field public static final int LTE_THROTTLING_NOT_REQUIRED = 2127; // 0x84f
-    field public static final int MAC_FAILURE = 2183; // 0x887
-    field public static final int MAXIMIUM_NSAPIS_EXCEEDED = 2157; // 0x86d
-    field public static final int MAXINUM_SIZE_OF_L2_MESSAGE_EXCEEDED = 2166; // 0x876
-    field public static final int MAX_ACCESS_PROBE = 2079; // 0x81f
-    field public static final int MAX_IPV4_CONNECTIONS = 2052; // 0x804
-    field public static final int MAX_IPV6_CONNECTIONS = 2053; // 0x805
-    field public static final int MAX_PPP_INACTIVITY_TIMER_EXPIRED = 2046; // 0x7fe
-    field public static final int MESSAGE_INCORRECT_SEMANTIC = 95; // 0x5f
-    field public static final int MESSAGE_TYPE_UNSUPPORTED = 97; // 0x61
-    field public static final int MIP_CONFIG_FAILURE = 2050; // 0x802
-    field public static final int MIP_FA_ADMIN_PROHIBITED = 2001; // 0x7d1
-    field public static final int MIP_FA_DELIVERY_STYLE_NOT_SUPPORTED = 2012; // 0x7dc
-    field public static final int MIP_FA_ENCAPSULATION_UNAVAILABLE = 2008; // 0x7d8
-    field public static final int MIP_FA_HOME_AGENT_AUTHENTICATION_FAILURE = 2004; // 0x7d4
-    field public static final int MIP_FA_INSUFFICIENT_RESOURCES = 2002; // 0x7d2
-    field public static final int MIP_FA_MALFORMED_REPLY = 2007; // 0x7d7
-    field public static final int MIP_FA_MALFORMED_REQUEST = 2006; // 0x7d6
-    field public static final int MIP_FA_MISSING_CHALLENGE = 2017; // 0x7e1
-    field public static final int MIP_FA_MISSING_HOME_ADDRESS = 2015; // 0x7df
-    field public static final int MIP_FA_MISSING_HOME_AGENT = 2014; // 0x7de
-    field public static final int MIP_FA_MISSING_NAI = 2013; // 0x7dd
-    field public static final int MIP_FA_MOBILE_NODE_AUTHENTICATION_FAILURE = 2003; // 0x7d3
-    field public static final int MIP_FA_REASON_UNSPECIFIED = 2000; // 0x7d0
-    field public static final int MIP_FA_REQUESTED_LIFETIME_TOO_LONG = 2005; // 0x7d5
-    field public static final int MIP_FA_REVERSE_TUNNEL_IS_MANDATORY = 2011; // 0x7db
-    field public static final int MIP_FA_REVERSE_TUNNEL_UNAVAILABLE = 2010; // 0x7da
-    field public static final int MIP_FA_STALE_CHALLENGE = 2018; // 0x7e2
-    field public static final int MIP_FA_UNKNOWN_CHALLENGE = 2016; // 0x7e0
-    field public static final int MIP_FA_VJ_HEADER_COMPRESSION_UNAVAILABLE = 2009; // 0x7d9
-    field public static final int MIP_HA_ADMIN_PROHIBITED = 2020; // 0x7e4
-    field public static final int MIP_HA_ENCAPSULATION_UNAVAILABLE = 2029; // 0x7ed
-    field public static final int MIP_HA_FOREIGN_AGENT_AUTHENTICATION_FAILURE = 2023; // 0x7e7
-    field public static final int MIP_HA_INSUFFICIENT_RESOURCES = 2021; // 0x7e5
-    field public static final int MIP_HA_MALFORMED_REQUEST = 2025; // 0x7e9
-    field public static final int MIP_HA_MOBILE_NODE_AUTHENTICATION_FAILURE = 2022; // 0x7e6
-    field public static final int MIP_HA_REASON_UNSPECIFIED = 2019; // 0x7e3
-    field public static final int MIP_HA_REGISTRATION_ID_MISMATCH = 2024; // 0x7e8
-    field public static final int MIP_HA_REVERSE_TUNNEL_IS_MANDATORY = 2028; // 0x7ec
-    field public static final int MIP_HA_REVERSE_TUNNEL_UNAVAILABLE = 2027; // 0x7eb
-    field public static final int MIP_HA_UNKNOWN_HOME_AGENT_ADDRESS = 2026; // 0x7ea
-    field public static final int MISSING_UNKNOWN_APN = 27; // 0x1b
-    field public static final int MODEM_APP_PREEMPTED = 2032; // 0x7f0
-    field public static final int MODEM_RESTART = 2037; // 0x7f5
-    field public static final int MSC_TEMPORARILY_NOT_REACHABLE = 2180; // 0x884
-    field public static final int MSG_AND_PROTOCOL_STATE_UNCOMPATIBLE = 101; // 0x65
-    field public static final int MSG_TYPE_NONCOMPATIBLE_STATE = 98; // 0x62
-    field public static final int MS_IDENTITY_CANNOT_BE_DERIVED_BY_THE_NETWORK = 2099; // 0x833
-    field public static final int MULTIPLE_PDP_CALL_NOT_ALLOWED = 2192; // 0x890
-    field public static final int MULTI_CONN_TO_SAME_PDN_NOT_ALLOWED = 55; // 0x37
-    field public static final int NAS_LAYER_FAILURE = 2191; // 0x88f
-    field public static final int NAS_REQUEST_REJECTED_BY_NETWORK = 2167; // 0x877
-    field public static final int NAS_SIGNALLING = 14; // 0xe
-    field public static final int NETWORK_FAILURE = 38; // 0x26
-    field public static final int NETWORK_INITIATED_DETACH_NO_AUTO_REATTACH = 2154; // 0x86a
-    field public static final int NETWORK_INITIATED_DETACH_WITH_AUTO_REATTACH = 2153; // 0x869
-    field public static final int NETWORK_INITIATED_TERMINATION = 2031; // 0x7ef
-    field public static final int NONE = 0; // 0x0
-    field public static final int NON_IP_NOT_SUPPORTED = 2069; // 0x815
-    field public static final int NORMAL_RELEASE = 2218; // 0x8aa
-    field public static final int NO_CDMA_SERVICE = 2084; // 0x824
-    field public static final int NO_COLLOCATED_HDR = 2225; // 0x8b1
-    field public static final int NO_EPS_BEARER_CONTEXT_ACTIVATED = 2189; // 0x88d
-    field public static final int NO_GPRS_CONTEXT = 2094; // 0x82e
-    field public static final int NO_HYBRID_HDR_SERVICE = 2209; // 0x8a1
-    field public static final int NO_PDP_CONTEXT_ACTIVATED = 2107; // 0x83b
-    field public static final int NO_RESPONSE_FROM_BASE_STATION = 2081; // 0x821
-    field public static final int NO_SERVICE = 2216; // 0x8a8
-    field public static final int NO_SERVICE_ON_GATEWAY = 2093; // 0x82d
-    field public static final int NSAPI_IN_USE = 35; // 0x23
-    field public static final int NULL_APN_DISALLOWED = 2061; // 0x80d
-    field public static final int OEM_DCFAILCAUSE_1 = 4097; // 0x1001
-    field public static final int OEM_DCFAILCAUSE_10 = 4106; // 0x100a
-    field public static final int OEM_DCFAILCAUSE_11 = 4107; // 0x100b
-    field public static final int OEM_DCFAILCAUSE_12 = 4108; // 0x100c
-    field public static final int OEM_DCFAILCAUSE_13 = 4109; // 0x100d
-    field public static final int OEM_DCFAILCAUSE_14 = 4110; // 0x100e
-    field public static final int OEM_DCFAILCAUSE_15 = 4111; // 0x100f
-    field public static final int OEM_DCFAILCAUSE_2 = 4098; // 0x1002
-    field public static final int OEM_DCFAILCAUSE_3 = 4099; // 0x1003
-    field public static final int OEM_DCFAILCAUSE_4 = 4100; // 0x1004
-    field public static final int OEM_DCFAILCAUSE_5 = 4101; // 0x1005
-    field public static final int OEM_DCFAILCAUSE_6 = 4102; // 0x1006
-    field public static final int OEM_DCFAILCAUSE_7 = 4103; // 0x1007
-    field public static final int OEM_DCFAILCAUSE_8 = 4104; // 0x1008
-    field public static final int OEM_DCFAILCAUSE_9 = 4105; // 0x1009
-    field public static final int ONLY_IPV4V6_ALLOWED = 57; // 0x39
-    field public static final int ONLY_IPV4_ALLOWED = 50; // 0x32
-    field public static final int ONLY_IPV6_ALLOWED = 51; // 0x33
-    field public static final int ONLY_NON_IP_ALLOWED = 58; // 0x3a
-    field public static final int ONLY_SINGLE_BEARER_ALLOWED = 52; // 0x34
-    field public static final int OPERATOR_BARRED = 8; // 0x8
-    field public static final int OTASP_COMMIT_IN_PROGRESS = 2208; // 0x8a0
-    field public static final int PDN_CONN_DOES_NOT_EXIST = 54; // 0x36
-    field public static final int PDN_INACTIVITY_TIMER_EXPIRED = 2051; // 0x803
-    field public static final int PDN_IPV4_CALL_DISALLOWED = 2033; // 0x7f1
-    field public static final int PDN_IPV4_CALL_THROTTLED = 2034; // 0x7f2
-    field public static final int PDN_IPV6_CALL_DISALLOWED = 2035; // 0x7f3
-    field public static final int PDN_IPV6_CALL_THROTTLED = 2036; // 0x7f4
-    field public static final int PDN_NON_IP_CALL_DISALLOWED = 2071; // 0x817
-    field public static final int PDN_NON_IP_CALL_THROTTLED = 2070; // 0x816
-    field public static final int PDP_ACTIVATE_MAX_RETRY_FAILED = 2109; // 0x83d
-    field public static final int PDP_DUPLICATE = 2104; // 0x838
-    field public static final int PDP_ESTABLISH_TIMEOUT_EXPIRED = 2161; // 0x871
-    field public static final int PDP_INACTIVE_TIMEOUT_EXPIRED = 2163; // 0x873
-    field public static final int PDP_LOWERLAYER_ERROR = 2164; // 0x874
-    field public static final int PDP_MODIFY_COLLISION = 2165; // 0x875
-    field public static final int PDP_MODIFY_TIMEOUT_EXPIRED = 2162; // 0x872
-    field public static final int PDP_PPP_NOT_SUPPORTED = 2038; // 0x7f6
-    field public static final int PDP_WITHOUT_ACTIVE_TFT = 46; // 0x2e
-    field public static final int PHONE_IN_USE = 2222; // 0x8ae
-    field public static final int PHYSICAL_LINK_CLOSE_IN_PROGRESS = 2040; // 0x7f8
-    field public static final int PLMN_NOT_ALLOWED = 2101; // 0x835
-    field public static final int PPP_AUTH_FAILURE = 2229; // 0x8b5
-    field public static final int PPP_CHAP_FAILURE = 2232; // 0x8b8
-    field public static final int PPP_CLOSE_IN_PROGRESS = 2233; // 0x8b9
-    field public static final int PPP_OPTION_MISMATCH = 2230; // 0x8b6
-    field public static final int PPP_PAP_FAILURE = 2231; // 0x8b7
-    field public static final int PPP_TIMEOUT = 2228; // 0x8b4
-    field public static final int PREF_RADIO_TECH_CHANGED = -4; // 0xfffffffc
-    field public static final int PROFILE_BEARER_INCOMPATIBLE = 2042; // 0x7fa
-    field public static final int PROTOCOL_ERRORS = 111; // 0x6f
-    field public static final int QOS_NOT_ACCEPTED = 37; // 0x25
-    field public static final int RADIO_ACCESS_BEARER_FAILURE = 2110; // 0x83e
-    field public static final int RADIO_ACCESS_BEARER_SETUP_FAILURE = 2160; // 0x870
-    field public static final int RADIO_NOT_AVAILABLE = 65537; // 0x10001
-    field public static final int RADIO_POWER_OFF = -5; // 0xfffffffb
-    field public static final int REDIRECTION_OR_HANDOFF_IN_PROGRESS = 2220; // 0x8ac
-    field public static final int REGISTRATION_FAIL = -1; // 0xffffffff
-    field public static final int REGULAR_DEACTIVATION = 36; // 0x24
-    field public static final int REJECTED_BY_BASE_STATION = 2082; // 0x822
-    field public static final int RRC_CONNECTION_ABORTED_AFTER_HANDOVER = 2173; // 0x87d
-    field public static final int RRC_CONNECTION_ABORTED_AFTER_IRAT_CELL_CHANGE = 2174; // 0x87e
-    field public static final int RRC_CONNECTION_ABORTED_DUE_TO_IRAT_CHANGE = 2171; // 0x87b
-    field public static final int RRC_CONNECTION_ABORTED_DURING_IRAT_CELL_CHANGE = 2175; // 0x87f
-    field public static final int RRC_CONNECTION_ABORT_REQUEST = 2151; // 0x867
-    field public static final int RRC_CONNECTION_ACCESS_BARRED = 2139; // 0x85b
-    field public static final int RRC_CONNECTION_ACCESS_STRATUM_FAILURE = 2137; // 0x859
-    field public static final int RRC_CONNECTION_ANOTHER_PROCEDURE_IN_PROGRESS = 2138; // 0x85a
-    field public static final int RRC_CONNECTION_CELL_NOT_CAMPED = 2144; // 0x860
-    field public static final int RRC_CONNECTION_CELL_RESELECTION = 2140; // 0x85c
-    field public static final int RRC_CONNECTION_CONFIG_FAILURE = 2141; // 0x85d
-    field public static final int RRC_CONNECTION_INVALID_REQUEST = 2168; // 0x878
-    field public static final int RRC_CONNECTION_LINK_FAILURE = 2143; // 0x85f
-    field public static final int RRC_CONNECTION_NORMAL_RELEASE = 2147; // 0x863
-    field public static final int RRC_CONNECTION_OUT_OF_SERVICE_DURING_CELL_REGISTER = 2150; // 0x866
-    field public static final int RRC_CONNECTION_RADIO_LINK_FAILURE = 2148; // 0x864
-    field public static final int RRC_CONNECTION_REESTABLISHMENT_FAILURE = 2149; // 0x865
-    field public static final int RRC_CONNECTION_REJECT_BY_NETWORK = 2146; // 0x862
-    field public static final int RRC_CONNECTION_RELEASED_SECURITY_NOT_ACTIVE = 2172; // 0x87c
-    field public static final int RRC_CONNECTION_RF_UNAVAILABLE = 2170; // 0x87a
-    field public static final int RRC_CONNECTION_SYSTEM_INFORMATION_BLOCK_READ_ERROR = 2152; // 0x868
-    field public static final int RRC_CONNECTION_SYSTEM_INTERVAL_FAILURE = 2145; // 0x861
-    field public static final int RRC_CONNECTION_TIMER_EXPIRED = 2142; // 0x85e
-    field public static final int RRC_CONNECTION_TRACKING_AREA_ID_CHANGED = 2169; // 0x879
-    field public static final int RRC_UPLINK_CONNECTION_RELEASE = 2134; // 0x856
-    field public static final int RRC_UPLINK_DATA_TRANSMISSION_FAILURE = 2132; // 0x854
-    field public static final int RRC_UPLINK_DELIVERY_FAILED_DUE_TO_HANDOVER = 2133; // 0x855
-    field public static final int RRC_UPLINK_ERROR_REQUEST_FROM_NAS = 2136; // 0x858
-    field public static final int RRC_UPLINK_RADIO_LINK_FAILURE = 2135; // 0x857
-    field public static final int RUIM_NOT_PRESENT = 2085; // 0x825
-    field public static final int SECURITY_MODE_REJECTED = 2186; // 0x88a
-    field public static final int SERVICE_NOT_ALLOWED_ON_PLMN = 2129; // 0x851
-    field public static final int SERVICE_OPTION_NOT_SUBSCRIBED = 33; // 0x21
-    field public static final int SERVICE_OPTION_NOT_SUPPORTED = 32; // 0x20
-    field public static final int SERVICE_OPTION_OUT_OF_ORDER = 34; // 0x22
-    field public static final int SIGNAL_LOST = -3; // 0xfffffffd
-    field public static final int SIM_CARD_CHANGED = 2043; // 0x7fb
-    field public static final int SYNCHRONIZATION_FAILURE = 2184; // 0x888
-    field public static final int TEST_LOOPBACK_REGULAR_DEACTIVATION = 2196; // 0x894
-    field public static final int TETHERED_CALL_ACTIVE = -6; // 0xfffffffa
-    field public static final int TFT_SEMANTIC_ERROR = 41; // 0x29
-    field public static final int TFT_SYTAX_ERROR = 42; // 0x2a
-    field public static final int THERMAL_EMERGENCY = 2090; // 0x82a
-    field public static final int THERMAL_MITIGATION = 2062; // 0x80e
-    field public static final int TRAT_SWAP_FAILED = 2048; // 0x800
-    field public static final int UE_INITIATED_DETACH_OR_DISCONNECT = 128; // 0x80
-    field public static final int UE_IS_ENTERING_POWERSAVE_MODE = 2226; // 0x8b2
-    field public static final int UE_RAT_CHANGE = 2105; // 0x839
-    field public static final int UE_SECURITY_CAPABILITIES_MISMATCH = 2185; // 0x889
-    field public static final int UMTS_HANDOVER_TO_IWLAN = 2199; // 0x897
-    field public static final int UMTS_REACTIVATION_REQ = 39; // 0x27
-    field public static final int UNACCEPTABLE_NETWORK_PARAMETER = 65538; // 0x10002
-    field public static final int UNACCEPTABLE_NON_EPS_AUTHENTICATION = 2187; // 0x88b
-    field public static final int UNKNOWN = 65536; // 0x10000
-    field public static final int UNKNOWN_INFO_ELEMENT = 99; // 0x63
-    field public static final int UNKNOWN_PDP_ADDRESS_TYPE = 28; // 0x1c
-    field public static final int UNKNOWN_PDP_CONTEXT = 43; // 0x2b
-    field public static final int UNPREFERRED_RAT = 2039; // 0x7f7
-    field public static final int UNSUPPORTED_1X_PREV = 2214; // 0x8a6
-    field public static final int UNSUPPORTED_APN_IN_CURRENT_PLMN = 66; // 0x42
-    field public static final int UNSUPPORTED_QCI_VALUE = 59; // 0x3b
-    field public static final int USER_AUTHENTICATION = 29; // 0x1d
-    field public static final int VSNCP_ADMINISTRATIVELY_PROHIBITED = 2245; // 0x8c5
-    field public static final int VSNCP_APN_UNATHORIZED = 2238; // 0x8be
-    field public static final int VSNCP_GEN_ERROR = 2237; // 0x8bd
-    field public static final int VSNCP_INSUFFICIENT_PARAMETERS = 2243; // 0x8c3
-    field public static final int VSNCP_NO_PDN_GATEWAY_ADDRESS = 2240; // 0x8c0
-    field public static final int VSNCP_PDN_EXISTS_FOR_THIS_APN = 2248; // 0x8c8
-    field public static final int VSNCP_PDN_GATEWAY_REJECT = 2242; // 0x8c2
-    field public static final int VSNCP_PDN_GATEWAY_UNREACHABLE = 2241; // 0x8c1
-    field public static final int VSNCP_PDN_ID_IN_USE = 2246; // 0x8c6
-    field public static final int VSNCP_PDN_LIMIT_EXCEEDED = 2239; // 0x8bf
-    field public static final int VSNCP_RECONNECT_NOT_ALLOWED = 2249; // 0x8c9
-    field public static final int VSNCP_RESOURCE_UNAVAILABLE = 2244; // 0x8c4
-    field public static final int VSNCP_SUBSCRIBER_LIMITATION = 2247; // 0x8c7
-    field public static final int VSNCP_TIMEOUT = 2236; // 0x8bc
+    field @Deprecated public static final int VSNCP_APN_UNATHORIZED = 2238; // 0x8be
   }
 
   public final class DataSpecificRegistrationInfo implements android.os.Parcelable {
diff --git a/api/test-current.txt b/api/test-current.txt
index 957794c..9e37a3c 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -846,6 +846,11 @@
     method @NonNull public static android.content.integrity.IntegrityFormula packageNameEquals(@NonNull String);
   }
 
+  public static final class IntegrityFormula.SourceStamp {
+    method @NonNull public static android.content.integrity.IntegrityFormula notTrusted();
+    method @NonNull public static android.content.integrity.IntegrityFormula stampCertificateHashEquals(@NonNull String);
+  }
+
   public final class Rule implements android.os.Parcelable {
     ctor public Rule(@NonNull android.content.integrity.IntegrityFormula, int);
     method public int describeContents();
@@ -1473,6 +1478,10 @@
     method @NonNull public String getOriginalId();
   }
 
+  public class MediaRouter2.RoutingController {
+    method @NonNull public String getOriginalId();
+  }
+
   public final class PlaybackParams implements android.os.Parcelable {
     method public int getAudioStretchMode();
     method public android.media.PlaybackParams setAudioStretchMode(int);
@@ -2529,6 +2538,11 @@
     method public void log(android.os.StrictMode.ViolationInfo);
   }
 
+  public static final class StrictMode.VmPolicy.Builder {
+    method @NonNull public android.os.StrictMode.VmPolicy.Builder detectIncorrectContextUse();
+    method @NonNull public android.os.StrictMode.VmPolicy.Builder permitIncorrectContextUse();
+  }
+
   public class SystemConfigManager {
     method @NonNull @RequiresPermission("android.permission.READ_CARRIER_APP_INFO") public java.util.Set<java.lang.String> getDisabledUntilUsedPreinstalledCarrierApps();
     method @NonNull @RequiresPermission("android.permission.READ_CARRIER_APP_INFO") public java.util.Map<java.lang.String,java.util.List<java.lang.String>> getDisabledUntilUsedPreinstalledCarrierAssociatedApps();
@@ -3145,6 +3159,7 @@
   public abstract class InlineSuggestionRenderService extends android.app.Service {
     ctor public InlineSuggestionRenderService();
     method @Nullable public final android.os.IBinder onBind(@NonNull android.content.Intent);
+    method @Nullable public android.os.Bundle onGetInlineSuggestionsRendererInfo();
     method @Nullable public android.view.View onRenderSuggestion(@NonNull android.service.autofill.InlinePresentation, int, int);
     field public static final String SERVICE_INTERFACE = "android.service.autofill.InlineSuggestionRenderService";
   }
diff --git a/cmds/hid/jni/com_android_commands_hid_Device.cpp b/cmds/hid/jni/com_android_commands_hid_Device.cpp
index f56dd6e..95de6c5 100644
--- a/cmds/hid/jni/com_android_commands_hid_Device.cpp
+++ b/cmds/hid/jni/com_android_commands_hid_Device.cpp
@@ -129,7 +129,7 @@
 }
 
 std::unique_ptr<Device> Device::open(int32_t id, const char* name, int32_t vid, int32_t pid,
-                                     const std::vector<uint8_t>& descriptor,
+                                     uint16_t bus, const std::vector<uint8_t>& descriptor,
                                      std::unique_ptr<DeviceCallback> callback) {
     size_t size = descriptor.size();
     if (size > HID_MAX_DESCRIPTOR_SIZE) {
@@ -148,7 +148,7 @@
     strlcpy(reinterpret_cast<char*>(ev.u.create2.name), name, sizeof(ev.u.create2.name));
     memcpy(&ev.u.create2.rd_data, descriptor.data(), size * sizeof(ev.u.create2.rd_data[0]));
     ev.u.create2.rd_size = size;
-    ev.u.create2.bus = BUS_BLUETOOTH;
+    ev.u.create2.bus = bus;
     ev.u.create2.vendor = vid;
     ev.u.create2.product = pid;
     ev.u.create2.version = 0;
@@ -293,8 +293,8 @@
     return data;
 }
 
-static jlong openDevice(JNIEnv* env, jclass /* clazz */, jstring rawName, jint id, jint vid, jint pid,
-        jbyteArray rawDescriptor, jobject callback) {
+static jlong openDevice(JNIEnv* env, jclass /* clazz */, jstring rawName, jint id, jint vid,
+                        jint pid, jint bus, jbyteArray rawDescriptor, jobject callback) {
     ScopedUtfChars name(env, rawName);
     if (name.c_str() == nullptr) {
         return 0;
@@ -305,7 +305,7 @@
     std::unique_ptr<uhid::DeviceCallback> cb(new uhid::DeviceCallback(env, callback));
 
     std::unique_ptr<uhid::Device> d =
-            uhid::Device::open(id, reinterpret_cast<const char*>(name.c_str()), vid, pid, desc,
+            uhid::Device::open(id, reinterpret_cast<const char*>(name.c_str()), vid, pid, bus, desc,
                                std::move(cb));
     return reinterpret_cast<jlong>(d.release());
 }
@@ -339,14 +339,14 @@
 }
 
 static JNINativeMethod sMethods[] = {
-    { "nativeOpenDevice",
-            "(Ljava/lang/String;III[B"
-            "Lcom/android/commands/hid/Device$DeviceCallback;)J",
-            reinterpret_cast<void*>(openDevice) },
-    { "nativeSendReport", "(J[B)V", reinterpret_cast<void*>(sendReport) },
-    { "nativeSendGetFeatureReportReply", "(JI[B)V",
-            reinterpret_cast<void*>(sendGetFeatureReportReply) },
-    { "nativeCloseDevice", "(J)V", reinterpret_cast<void*>(closeDevice) },
+        {"nativeOpenDevice",
+         "(Ljava/lang/String;IIII[B"
+         "Lcom/android/commands/hid/Device$DeviceCallback;)J",
+         reinterpret_cast<void*>(openDevice)},
+        {"nativeSendReport", "(J[B)V", reinterpret_cast<void*>(sendReport)},
+        {"nativeSendGetFeatureReportReply", "(JI[B)V",
+         reinterpret_cast<void*>(sendGetFeatureReportReply)},
+        {"nativeCloseDevice", "(J)V", reinterpret_cast<void*>(closeDevice)},
 };
 
 int register_com_android_commands_hid_Device(JNIEnv* env) {
diff --git a/cmds/hid/jni/com_android_commands_hid_Device.h b/cmds/hid/jni/com_android_commands_hid_Device.h
index 93ea881..7202b45 100644
--- a/cmds/hid/jni/com_android_commands_hid_Device.h
+++ b/cmds/hid/jni/com_android_commands_hid_Device.h
@@ -43,7 +43,7 @@
 class Device {
 public:
     static std::unique_ptr<Device> open(int32_t id, const char* name, int32_t vid, int32_t pid,
-                                        const std::vector<uint8_t>& descriptor,
+                                        uint16_t bus, const std::vector<uint8_t>& descriptor,
                                         std::unique_ptr<DeviceCallback> callback);
 
     ~Device();
diff --git a/cmds/hid/src/com/android/commands/hid/Device.java b/cmds/hid/src/com/android/commands/hid/Device.java
index 874604c..dade415 100644
--- a/cmds/hid/src/com/android/commands/hid/Device.java
+++ b/cmds/hid/src/com/android/commands/hid/Device.java
@@ -52,13 +52,13 @@
         System.loadLibrary("hidcommand_jni");
     }
 
-    private static native long nativeOpenDevice(String name, int id, int vid, int pid,
+    private static native long nativeOpenDevice(String name, int id, int vid, int pid, int bus,
             byte[] descriptor, DeviceCallback callback);
     private static native void nativeSendReport(long ptr, byte[] data);
     private static native void nativeSendGetFeatureReportReply(long ptr, int id, byte[] data);
     private static native void nativeCloseDevice(long ptr);
 
-    public Device(int id, String name, int vid, int pid, byte[] descriptor,
+    public Device(int id, String name, int vid, int pid, int bus, byte[] descriptor,
             byte[] report, SparseArray<byte[]> featureReports, Map<ByteBuffer, byte[]> outputs) {
         mId = id;
         mThread = new HandlerThread("HidDeviceHandler");
@@ -70,6 +70,7 @@
         args.argi1 = id;
         args.argi2 = vid;
         args.argi3 = pid;
+        args.argi4 = bus;
         if (name != null) {
             args.arg1 = name;
         } else {
@@ -115,7 +116,7 @@
                 case MSG_OPEN_DEVICE:
                     SomeArgs args = (SomeArgs) msg.obj;
                     mPtr = nativeOpenDevice((String) args.arg1, args.argi1, args.argi2, args.argi3,
-                            (byte[]) args.arg2, new DeviceCallback());
+                            args.argi4, (byte[]) args.arg2, new DeviceCallback());
                     pauseEvents();
                     break;
                 case MSG_SEND_REPORT:
diff --git a/cmds/hid/src/com/android/commands/hid/Event.java b/cmds/hid/src/com/android/commands/hid/Event.java
index 62587a7..d4bf1d8 100644
--- a/cmds/hid/src/com/android/commands/hid/Event.java
+++ b/cmds/hid/src/com/android/commands/hid/Event.java
@@ -36,12 +36,28 @@
     public static final String COMMAND_DELAY = "delay";
     public static final String COMMAND_REPORT = "report";
 
+    // These constants come from "include/uapi/linux/input.h" in the kernel
+    enum Bus {
+        USB(0x03), BLUETOOTH(0x05);
+
+        Bus(int value) {
+            mValue = value;
+        }
+
+        int getValue() {
+            return mValue;
+        }
+
+        private int mValue;
+    }
+
     private int mId;
     private String mCommand;
     private String mName;
     private byte[] mDescriptor;
     private int mVid;
     private int mPid;
+    private Bus mBus;
     private byte[] mReport;
     private SparseArray<byte[]> mFeatureReports;
     private Map<ByteBuffer, byte[]> mOutputs;
@@ -71,6 +87,10 @@
         return mPid;
     }
 
+    public int getBus() {
+        return mBus.getValue();
+    }
+
     public byte[] getReport() {
         return mReport;
     }
@@ -94,6 +114,7 @@
             + ", descriptor=" + Arrays.toString(mDescriptor)
             + ", vid=" + mVid
             + ", pid=" + mPid
+            + ", bus=" + mBus
             + ", report=" + Arrays.toString(mReport)
             + ", feature_reports=" + mFeatureReports.toString()
             + ", outputs=" + mOutputs.toString()
@@ -144,6 +165,10 @@
             mEvent.mPid = pid;
         }
 
+        public void setBus(Bus bus) {
+            mEvent.mBus = bus;
+        }
+
         public void setDuration(int duration) {
             mEvent.mDuration = duration;
         }
@@ -206,6 +231,9 @@
                             case "pid":
                                 eb.setPid(readInt());
                                 break;
+                            case "bus":
+                                eb.setBus(readBus());
+                                break;
                             case "report":
                                 eb.setReport(readData());
                                 break;
@@ -264,6 +292,11 @@
             return Integer.decode(val);
         }
 
+        private Bus readBus() throws IOException {
+            String val = mReader.nextString();
+            return Bus.valueOf(val.toUpperCase());
+        }
+
         private SparseArray<byte[]> readFeatureReports()
                 throws IllegalStateException, IOException {
             SparseArray<byte[]> featureReports = new SparseArray<>();
diff --git a/cmds/hid/src/com/android/commands/hid/Hid.java b/cmds/hid/src/com/android/commands/hid/Hid.java
index 0ee2cc4..fac0ab2 100644
--- a/cmds/hid/src/com/android/commands/hid/Hid.java
+++ b/cmds/hid/src/com/android/commands/hid/Hid.java
@@ -113,7 +113,7 @@
                     "Tried to send command \"" + e.getCommand() + "\" to an unregistered device!");
         }
         int id = e.getId();
-        Device d = new Device(id, e.getName(), e.getVendorId(), e.getProductId(),
+        Device d = new Device(id, e.getName(), e.getVendorId(), e.getProductId(), e.getBus(),
                 e.getDescriptor(), e.getReport(), e.getFeatureReports(), e.getOutputs());
         mDevices.append(id, d);
     }
diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp
index 93522d4..73a8f66 100644
--- a/cmds/statsd/Android.bp
+++ b/cmds/statsd/Android.bp
@@ -217,7 +217,10 @@
 
     shared_libs: ["libgtest_prod"],
 
-    init_rc: ["statsd.rc"],
+    apex_available: [
+        "com.android.os.statsd",
+        "test_com.android.os.statsd",
+    ],
 }
 
 // ==============
@@ -299,6 +302,11 @@
     static_libs: [
         "libgmock",
         "libplatformprotos",
+
+        // TODO(b/149842105): Make libstatssocket shared and remove libcutils once statsd_test is
+        // moved to the apex.
+        "libstatssocket",
+        "libcutils",
     ],
 
     proto: {
@@ -308,7 +316,6 @@
 
     shared_libs: [
         "libprotobuf-cpp-lite",
-        "libstatssocket"
     ],
 
 }
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index a4e8fdc..43d0fce 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -392,6 +392,7 @@
         WifiFailureStatReported wifi_failure_stat_reported = 252 [(module) = "wifi"];
         WifiConnectionResultReported wifi_connection_result_reported = 253 [(module) = "wifi"];
         AppFreezeChanged app_freeze_changed = 254 [(module) = "framework"];
+        SnapshotMergeReported snapshot_merge_reported = 255;
         SdkExtensionStatus sdk_extension_status = 354;
     }
 
@@ -4418,6 +4419,52 @@
     optional int32 error_code = 2;
 }
 
+/**
+ * Collects Virtual A/B statistics related to the use of dm-snapshot performed
+ * after an OTA.
+ *
+ * Logged from:
+ *  - system/core/fs_mgr/libsnapshot/snapshot.cpp
+ *  - system/core/fs_mgr/libsnapshot/snapshotctl.cpp
+ */
+message SnapshotMergeReported {
+    // Keep in sync with
+    // system/core/fs_mgr/libsnapshot/android/snapshot/snapshot.proto
+    enum UpdateState {
+        // No update or merge is in progress.
+        NONE = 0;
+        // An update is applying; snapshots may already exist.
+        INITIATED = 1;
+        // An update is pending, but has not been successfully booted yet.
+        UNVERIFIED = 2;
+        // The kernel is merging in the background.
+        MERGING = 3;
+        // Post-merge cleanup steps could not be completed due to a transient
+        // error, but the next reboot will finish any pending operations.
+        MERGE_NEEDS_REBOOT = 4;
+        // Merging is complete, and needs to be acknowledged.
+        MERGE_COMPLETED = 5;
+        // Merging failed due to an unrecoverable error.
+        MERGE_FAILED = 6;
+        // The update was implicitly cancelled, either by a rollback or a flash
+        // operation via fastboot. This state can only be returned by WaitForMerge.
+        CANCELLED = 7;
+    };
+
+    // Status of the update after the merge attempts.
+    optional UpdateState final_state = 1;
+
+    // Time to complete a merge operation in milliseconds.
+    // A negative value corresponds to the case in which the merge operation
+    // was interrupted and resumed (e.g. in case of a system reboot during the
+    // merge).
+    optional int64 duration_millis = 2;
+
+    // Number of reboots that occurred after issuing and before completing the
+    // merge of all the snapshot devices.
+    optional int32 intermediate_reboots = 3;
+}
+
 //////////////////////////////////////////////////////////////////////
 // Pulled atoms below this line //
 //////////////////////////////////////////////////////////////////////
diff --git a/cmds/statsd/src/storage/StorageManager.cpp b/cmds/statsd/src/storage/StorageManager.cpp
index 4899b4a..dcfdfe3 100644
--- a/cmds/statsd/src/storage/StorageManager.cpp
+++ b/cmds/statsd/src/storage/StorageManager.cpp
@@ -75,11 +75,11 @@
                         (long long)id);
 }
 
-static const char* findTrainInfoFileNameLocked(const string& trainName) {
+static string findTrainInfoFileNameLocked(const string& trainName) {
     unique_ptr<DIR, decltype(&closedir)> dir(opendir(TRAIN_INFO_DIR), closedir);
     if (dir == NULL) {
         VLOG("Path %s does not exist", TRAIN_INFO_DIR);
-        return nullptr;
+        return "";
     }
     dirent* de;
     while ((de = readdir(dir.get()))) {
@@ -90,12 +90,12 @@
         if (fileNameLength >= trainName.length()) {
             if (0 == strncmp(fileName + fileNameLength - trainName.length(), trainName.c_str(),
                              trainName.length())) {
-                return fileName;
+              return string(fileName);
             }
         }
     }
 
-    return nullptr;
+    return "";
 }
 
 // Returns array of int64_t which contains timestamp in seconds, uid,
@@ -267,13 +267,13 @@
 
 bool StorageManager::readTrainInfoLocked(const std::string& trainName, InstallTrainInfo& trainInfo) {
     trimToFit(TRAIN_INFO_DIR, /*parseTimestampOnly=*/ true);
-    const char* fileName = findTrainInfoFileNameLocked(trainName);
-    if (fileName == nullptr) {
+    string fileName = findTrainInfoFileNameLocked(trainName);
+    if (fileName.empty()) {
         return false;
     }
-    int fd = open(StringPrintf("%s/%s", TRAIN_INFO_DIR, fileName).c_str(), O_RDONLY | O_CLOEXEC);
+    int fd = open(StringPrintf("%s/%s", TRAIN_INFO_DIR, fileName.c_str()).c_str(), O_RDONLY | O_CLOEXEC);
     if (fd == -1) {
-        VLOG("Failed to open %s", fileName);
+        VLOG("Failed to open %s", fileName.c_str());
         return false;
     }
 
diff --git a/cmds/telecom/src/com/android/commands/telecom/Telecom.java b/cmds/telecom/src/com/android/commands/telecom/Telecom.java
index 9707405..fe270a4 100644
--- a/cmds/telecom/src/com/android/commands/telecom/Telecom.java
+++ b/cmds/telecom/src/com/android/commands/telecom/Telecom.java
@@ -46,6 +46,10 @@
      * @param args The command-line arguments
      */
     public static void main(String[] args) {
+        // Initialize the telephony module.
+        // TODO: Do it in zygote and RuntimeInit. b/148897549
+        ActivityThread.initializeMainlineModules();
+
       (new Telecom()).run(args);
     }
 
diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
index c1e2195..3b0667d 100644
--- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
+++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
@@ -27,6 +27,7 @@
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 import android.content.Context;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ResolveInfo;
@@ -34,6 +35,7 @@
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.content.res.XmlResourceParser;
+import android.graphics.drawable.Drawable;
 import android.hardware.fingerprint.FingerprintManager;
 import android.os.Build;
 import android.os.Parcel;
@@ -786,12 +788,34 @@
      *    {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong>
      * </p>
      * @return The animated image resource id.
+     * @hide
      */
     public int getAnimatedImageRes() {
         return mAnimatedImageRes;
     }
 
     /**
+     * The animated image drawable.
+     * <p>
+     *    <strong>Statically set from
+     *    {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong>
+     * </p>
+     * @return The animated image drawable.
+     */
+    @Nullable
+    public Drawable loadAnimatedImage(@NonNull Context context)  {
+        if (mAnimatedImageRes == /* invalid */ 0) {
+            return null;
+        }
+
+        final PackageManager packageManager = context.getPackageManager();
+        final String packageName = mComponentName.getPackageName();
+        final ApplicationInfo applicationInfo = mResolveInfo.serviceInfo.applicationInfo;
+
+        return packageManager.getDrawable(packageName, mAnimatedImageRes, applicationInfo);
+    }
+
+    /**
      * Whether this service can retrieve the current window's content.
      * <p>
      *    <strong>Statically set from
diff --git a/core/java/android/accessibilityservice/AccessibilityShortcutInfo.java b/core/java/android/accessibilityservice/AccessibilityShortcutInfo.java
index 9912d2b..6209679 100644
--- a/core/java/android/accessibilityservice/AccessibilityShortcutInfo.java
+++ b/core/java/android/accessibilityservice/AccessibilityShortcutInfo.java
@@ -22,10 +22,12 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.content.res.XmlResourceParser;
+import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
 import android.util.Xml;
 
@@ -193,12 +195,32 @@
      * The animated image resource id of the accessibility shortcut target.
      *
      * @return The animated image resource id.
+     *
+     * @hide
      */
     public int getAnimatedImageRes() {
         return mAnimatedImageRes;
     }
 
     /**
+     * The animated image drawable of the accessibility shortcut target.
+     *
+     * @return The animated image drawable.
+     */
+    @Nullable
+    public Drawable loadAnimatedImage(@NonNull Context context) {
+        if (mAnimatedImageRes == /* invalid */ 0) {
+            return null;
+        }
+
+        final PackageManager packageManager = context.getPackageManager();
+        final String packageName = mComponentName.getPackageName();
+        final ApplicationInfo applicationInfo = mActivityInfo.applicationInfo;
+
+        return packageManager.getDrawable(packageName, mAnimatedImageRes, applicationInfo);
+    }
+
+    /**
      * The localized html description of the accessibility shortcut target.
      *
      * @return The localized html description.
diff --git a/core/java/android/accessibilityservice/OWNERS b/core/java/android/accessibilityservice/OWNERS
index 265674a..c6f42f7 100644
--- a/core/java/android/accessibilityservice/OWNERS
+++ b/core/java/android/accessibilityservice/OWNERS
@@ -1,3 +1,4 @@
 svetoslavganov@google.com
 pweaver@google.com
 rhedjao@google.com
+qasid@google.com
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 6b5bfda..8df26cb 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -16,6 +16,9 @@
 
 package android.app;
 
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.os.StrictMode.vmIncorrectContextUseEnabled;
+
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -64,6 +67,7 @@
 import android.os.Looper;
 import android.os.Process;
 import android.os.RemoteException;
+import android.os.StrictMode;
 import android.os.Trace;
 import android.os.UserHandle;
 import android.os.UserManager;
@@ -247,6 +251,7 @@
 
     private boolean mIsSystemOrSystemUiContext;
     private boolean mIsUiContext;
+    private boolean mIsAssociatedWithDisplay;
 
     @GuardedBy("mSync")
     private File mDatabasesDir;
@@ -1891,9 +1896,20 @@
 
     @Override
     public Object getSystemService(String name) {
-        if (isUiComponent(name) && !isUiContext()) {
-            Log.w(TAG, name + " should be accessed from Activity or other visual Context");
+        // Check incorrect Context usage.
+        if (isUiComponent(name) && !isUiContext() && vmIncorrectContextUseEnabled()) {
+            final String errorMessage = "Tried to access visual service " + name
+                    + " from a non-visual Context.";
+            final String message = "Visual services, such as WindowManager, WallpaperService or "
+                    + "LayoutInflater should be accessed from Activity or other visual Context. "
+                    + "Use an Activity or a Context created with "
+                    + "Context#createWindowContext(int, Bundle), which are adjusted to the "
+                    + "configuration and visual bounds of an area on screen.";
+            final Exception exception = new IllegalAccessException(errorMessage);
+            StrictMode.onIncorrectContextUsed(message, exception);
+            Log.e(TAG, errorMessage + message, exception);
         }
+
         return SystemServiceRegistry.getSystemService(this, name);
     }
 
@@ -1902,8 +1918,17 @@
         return SystemServiceRegistry.getSystemServiceName(serviceClass);
     }
 
-    boolean isUiContext() {
-        return mIsSystemOrSystemUiContext || mIsUiContext;
+    private boolean isUiContext() {
+        return mIsSystemOrSystemUiContext || mIsUiContext || isSystemOrSystemUI();
+    }
+
+    /**
+     * Temporary workaround to permit incorrect usages of Context by SystemUI.
+     * TODO(b/149790106): Fix usages and remove.
+     */
+    private boolean isSystemOrSystemUI() {
+        return ActivityThread.isSystem() || checkPermission("android.permission.STATUS_BAR_SERVICE",
+                Binder.getCallingPid(), Binder.getCallingUid()) == PERMISSION_GRANTED;
     }
 
     private static boolean isUiComponent(String name) {
@@ -1925,7 +1950,7 @@
             final int appId = UserHandle.getAppId(uid);
             if (appId == Process.ROOT_UID || appId == Process.SYSTEM_UID) {
                 Slog.w(TAG, "Missing ActivityManager; assuming " + uid + " holds " + permission);
-                return PackageManager.PERMISSION_GRANTED;
+                return PERMISSION_GRANTED;
             }
             Slog.w(TAG, "Missing ActivityManager; assuming " + uid + " does not hold "
                     + permission);
@@ -1989,7 +2014,7 @@
     private void enforce(
             String permission, int resultOfCheck,
             boolean selfToo, int uid, String message) {
-        if (resultOfCheck != PackageManager.PERMISSION_GRANTED) {
+        if (resultOfCheck != PERMISSION_GRANTED) {
             throw new SecurityException(
                     (message != null ? (message + ": ") : "") +
                     (selfToo
@@ -2116,15 +2141,15 @@
         if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
             if (readPermission == null
                     || checkPermission(readPermission, pid, uid)
-                    == PackageManager.PERMISSION_GRANTED) {
-                return PackageManager.PERMISSION_GRANTED;
+                    == PERMISSION_GRANTED) {
+                return PERMISSION_GRANTED;
             }
         }
         if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
             if (writePermission == null
                     || checkPermission(writePermission, pid, uid)
-                    == PackageManager.PERMISSION_GRANTED) {
-                return PackageManager.PERMISSION_GRANTED;
+                    == PERMISSION_GRANTED) {
+                return PERMISSION_GRANTED;
             }
         }
         return uri != null ? checkUriPermission(uri, pid, uid, modeFlags)
@@ -2157,7 +2182,7 @@
     private void enforceForUri(
             int modeFlags, int resultOfCheck, boolean selfToo,
             int uid, Uri uri, String message) {
-        if (resultOfCheck != PackageManager.PERMISSION_GRANTED) {
+        if (resultOfCheck != PERMISSION_GRANTED) {
             throw new SecurityException(
                     (message != null ? (message + ": ") : "") +
                     (selfToo
@@ -2373,6 +2398,7 @@
                 null, getDisplayAdjustments(displayId).getCompatibilityInfo(),
                 mResources.getLoaders()));
         context.mDisplay = display;
+        context.mIsAssociatedWithDisplay = true;
         return context;
     }
 
@@ -2390,6 +2416,7 @@
         ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo, mFeatureId,
                 mSplitName, token, mUser, mFlags, mClassLoader, null);
         context.mIsUiContext = true;
+        context.mIsAssociatedWithDisplay = true;
         return context;
     }
 
@@ -2440,6 +2467,19 @@
 
     @Override
     public Display getDisplay() {
+        if (!mIsSystemOrSystemUiContext && !mIsAssociatedWithDisplay && !isSystemOrSystemUI()) {
+            throw new UnsupportedOperationException("Tried to obtain display from a Context not "
+                    + "associated with  one. Only visual Contexts (such as Activity or one created "
+                    + "with Context#createWindowContext) or ones created with "
+                    + "Context#createDisplayContext are associated with displays. Other types of "
+                    + "Contexts are typically related to background entities and may return an "
+                    + "arbitrary display.");
+        }
+        return getDisplayNoVerify();
+    }
+
+    @Override
+    public Display getDisplayNoVerify() {
         if (mDisplay == null) {
             return mResourcesManager.getAdjustedDisplay(Display.DEFAULT_DISPLAY,
                     mResources);
@@ -2450,13 +2490,14 @@
 
     @Override
     public int getDisplayId() {
-        final Display display = getDisplay();
+        final Display display = getDisplayNoVerify();
         return display != null ? display.getDisplayId() : Display.DEFAULT_DISPLAY;
     }
 
     @Override
     public void updateDisplay(int displayId) {
         mDisplay = mResourcesManager.getAdjustedDisplay(displayId, mResources);
+        mIsAssociatedWithDisplay = true;
     }
 
     @Override
@@ -2630,6 +2671,7 @@
         ContextImpl context = new ContextImpl(null, mainThread, packageInfo, null,
                 activityInfo.splitName, activityToken, null, 0, classLoader, null);
         context.mIsUiContext = true;
+        context.mIsAssociatedWithDisplay = true;
 
         // Clamp display ID to DEFAULT_DISPLAY if it is INVALID_DISPLAY.
         displayId = (displayId != Display.INVALID_DISPLAY) ? displayId : Display.DEFAULT_DISPLAY;
diff --git a/core/java/android/app/DexLoadReporter.java b/core/java/android/app/DexLoadReporter.java
index 229bee5..5bc9992 100644
--- a/core/java/android/app/DexLoadReporter.java
+++ b/core/java/android/app/DexLoadReporter.java
@@ -28,9 +28,8 @@
 
 import java.io.File;
 import java.io.IOException;
-import java.util.ArrayList;
 import java.util.HashSet;
-import java.util.List;
+import java.util.Map;
 import java.util.Set;
 
 /**
@@ -87,50 +86,32 @@
     }
 
     @Override
-    public void report(List<ClassLoader> classLoadersChain, List<String> classPaths) {
-        if (classLoadersChain.size() != classPaths.size()) {
-            Slog.wtf(TAG, "Bad call to DexLoadReporter: argument size mismatch");
-            return;
-        }
-        if (classPaths.isEmpty()) {
-            Slog.wtf(TAG, "Bad call to DexLoadReporter: empty dex paths");
-            return;
-        }
-
-        // The first element of classPaths is the list of dex files that should be registered.
-        // The classpath is represented as a list of dex files separated by File.pathSeparator.
-        String[] dexPathsForRegistration = classPaths.get(0).split(File.pathSeparator);
-        if (dexPathsForRegistration.length == 0) {
-            // No dex files to register.
+    public void report(Map<String, String> classLoaderContextMap) {
+        if (classLoaderContextMap.isEmpty()) {
+            Slog.wtf(TAG, "Bad call to DexLoadReporter: empty classLoaderContextMap");
             return;
         }
 
         // Notify the package manager about the dex loads unconditionally.
         // The load might be for either a primary or secondary dex file.
-        notifyPackageManager(classLoadersChain, classPaths);
+        notifyPackageManager(classLoaderContextMap);
         // Check for secondary dex files and register them for profiling if possible.
         // Note that we only register the dex paths belonging to the first class loader.
-        registerSecondaryDexForProfiling(dexPathsForRegistration);
+        registerSecondaryDexForProfiling(classLoaderContextMap.keySet());
     }
 
-    private void notifyPackageManager(List<ClassLoader> classLoadersChain,
-            List<String> classPaths) {
+    private void notifyPackageManager(Map<String, String> classLoaderContextMap) {
         // Get the class loader names for the binder call.
-        List<String> classLoadersNames = new ArrayList<>(classPaths.size());
-        for (ClassLoader classLoader : classLoadersChain) {
-            classLoadersNames.add(classLoader.getClass().getName());
-        }
         String packageName = ActivityThread.currentPackageName();
         try {
-            ActivityThread.getPackageManager().notifyDexLoad(
-                    packageName, classLoadersNames, classPaths,
-                    VMRuntime.getRuntime().vmInstructionSet());
+            ActivityThread.getPackageManager().notifyDexLoad(packageName,
+                    classLoaderContextMap, VMRuntime.getRuntime().vmInstructionSet());
         } catch (RemoteException re) {
             Slog.e(TAG, "Failed to notify PM about dex load for package " + packageName, re);
         }
     }
 
-    private void registerSecondaryDexForProfiling(String[] dexPaths) {
+    private void registerSecondaryDexForProfiling(Set<String> dexPaths) {
         if (!SystemProperties.getBoolean("dalvik.vm.dexopt.secondary", false)) {
             return;
         }
diff --git a/core/java/android/app/KeyguardManager.java b/core/java/android/app/KeyguardManager.java
index 4b0cadb..2122e92 100644
--- a/core/java/android/app/KeyguardManager.java
+++ b/core/java/android/app/KeyguardManager.java
@@ -25,6 +25,7 @@
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.app.admin.DevicePolicyManager;
+import android.app.admin.DevicePolicyManager.PasswordComplexity;
 import android.app.admin.PasswordMetrics;
 import android.app.trust.ITrustManager;
 import android.compat.annotation.UnsupportedAppUsage;
@@ -676,8 +677,9 @@
     /**
     * Determine if a given password is valid based off its lock type and expected complexity level.
     *
-    * @param isPin - whether this is a PIN-type password (only digits)
-    * @param password - password to validate
+    * @param lockType - type of lock as specified in {@link LockTypes}
+    * @param password - password to validate; this has the same encoding
+    *        as the output of String#getBytes
     * @param complexity - complexity level imposed by the requester
     *        as defined in {@code DevicePolicyManager.PasswordComplexity}
     * @return true if the password is valid, false otherwise
@@ -685,8 +687,8 @@
     */
     @RequiresPermission(Manifest.permission.SET_INITIAL_LOCK)
     @SystemApi
-    public boolean validateLockPasswordComplexity(
-            boolean isPin, @NonNull byte[] password, int complexity) {
+    public boolean isValidLockPasswordComplexity(@LockTypes int lockType, @NonNull byte[] password,
+            @PasswordComplexity int complexity) {
         if (!checkInitialLockMethodUsage()) {
             return false;
         }
@@ -696,9 +698,11 @@
                 (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
         PasswordMetrics adminMetrics =
                 devicePolicyManager.getPasswordMinimumMetrics(mContext.getUserId());
+        // Check if the password fits the mold of a pin or pattern.
+        boolean isPinOrPattern = lockType != LockTypes.PASSWORD;
 
         return PasswordMetrics.validatePassword(
-                adminMetrics, complexity, isPin, password).size() == 0;
+                adminMetrics, complexity, isPinOrPattern, password).size() == 0;
     }
 
     /**
@@ -712,7 +716,7 @@
     */
     @RequiresPermission(Manifest.permission.SET_INITIAL_LOCK)
     @SystemApi
-    public int getMinLockLength(boolean isPin, int complexity) {
+    public int getMinLockLength(boolean isPin, @PasswordComplexity int complexity) {
         if (!checkInitialLockMethodUsage()) {
             return -1;
         }
@@ -731,7 +735,8 @@
     * Set the lockscreen password after validating against its expected complexity level.
     *
     * @param lockType - type of lock as specified in {@link LockTypes}
-    * @param password - password to validate
+    * @param password - password to validate; this has the same encoding
+    *        as the output of String#getBytes
     * @param complexity - complexity level imposed by the requester
     *        as defined in {@code DevicePolicyManager.PasswordComplexity}
     * @return true if the lock is successfully set, false otherwise
@@ -739,7 +744,8 @@
     */
     @RequiresPermission(Manifest.permission.SET_INITIAL_LOCK)
     @SystemApi
-    public boolean setLock(@LockTypes int lockType, @NonNull byte[] password, int complexity) {
+    public boolean setLock(@LockTypes int lockType, @NonNull byte[] password,
+            @PasswordComplexity int complexity) {
         if (!checkInitialLockMethodUsage()) {
             return false;
         }
@@ -750,7 +756,7 @@
             Log.e(TAG, "Password already set, rejecting call to setLock");
             return false;
         }
-        if (!validateLockPasswordComplexity(lockType != LockTypes.PASSWORD, password, complexity)) {
+        if (!isValidLockPasswordComplexity(lockType, password, complexity)) {
             Log.e(TAG, "Password is not valid, rejecting call to setLock");
             return false;
         }
diff --git a/core/java/android/app/TaskEmbedder.java b/core/java/android/app/TaskEmbedder.java
index 761b225..5ebcc46 100644
--- a/core/java/android/app/TaskEmbedder.java
+++ b/core/java/android/app/TaskEmbedder.java
@@ -597,7 +597,7 @@
         if (mTmpDisplayMetrics == null) {
             mTmpDisplayMetrics = new DisplayMetrics();
         }
-        mContext.getDisplay().getMetrics(mTmpDisplayMetrics);
+        mContext.getDisplayNoVerify().getRealMetrics(mTmpDisplayMetrics);
         return mTmpDisplayMetrics.densityDpi;
     }
 
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index 5f74d2e..d9405e1 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -2097,7 +2097,7 @@
 
         public ColorManagementProxy(@NonNull Context context) {
             // Get a list of supported wide gamut color spaces.
-            Display display = context.getDisplay();
+            Display display = context.getDisplayNoVerify();
             if (display != null) {
                 mSupportedColorSpaces.addAll(Arrays.asList(display.getSupportedWideColorGamut()));
             }
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 139b179..b219394 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -33,6 +33,7 @@
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.annotation.TestApi;
+import android.annotation.UserHandleAware;
 import android.annotation.UserIdInt;
 import android.annotation.WorkerThread;
 import android.app.Activity;
@@ -5740,6 +5741,25 @@
     }
 
     /**
+     * Returns whether the admin has enabled always-on VPN lockdown for the current user.
+     *
+     * Only callable by the system.
+    * @hide
+    */
+    @UserHandleAware
+    public boolean isAlwaysOnVpnLockdownEnabled() {
+        throwIfParentInstance("isAlwaysOnVpnLockdownEnabled");
+        if (mService != null) {
+            try {
+                return mService.isAlwaysOnVpnLockdownEnabledForUser(myUserId());
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+        return false;
+    }
+
+    /**
      * Called by device or profile owner to query the set of packages that are allowed to access
      * the network directly when always-on VPN is in lockdown mode but not connected. Returns
      * {@code null} when always-on VPN is not active or not in lockdown mode.
@@ -5786,6 +5806,26 @@
     }
 
     /**
+     * Returns the VPN package name if the admin has enabled always-on VPN on the current user,
+     * or {@code null} if none is set.
+     *
+     * Only callable by the system.
+     * @hide
+     */
+    @UserHandleAware
+    public @Nullable String getAlwaysOnVpnPackage() {
+        throwIfParentInstance("getAlwaysOnVpnPackage");
+        if (mService != null) {
+            try {
+                return mService.getAlwaysOnVpnPackageForUser(myUserId());
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+        return null;
+    }
+
+    /**
      * Called by an application that is administering the device to disable all cameras on the
      * device, for this user. After setting this, no applications running as this user will be able
      * to access any cameras on the device.
@@ -8949,49 +8989,6 @@
     }
 
     /**
-     * Called by device owners to request a location provider to change its allowed state. For a
-     * provider to be enabled requires both that the master location setting is enabled, and that
-     * the provider itself is allowed. Most location providers are always allowed. Some location
-     * providers may have user consents or terms and conditions that must be accepted, or some other
-     * type of blocker before they are allowed however. Every location provider is responsible for
-     * its own allowed state.
-     *
-     * <p>This method requests that a location provider change its allowed state. For providers that
-     * are always allowed and have no state to change, this will have no effect. If the provider
-     * does require some consent, terms and conditions, or other blocking state, using this API
-     * implies that the device owner is agreeing/disagreeing to any consents, terms and conditions,
-     * etc, and the provider should make a best effort to adjust it's allowed state accordingly.
-     *
-     * <p>Location providers are generally only responsible for the current user, and callers must
-     * assume that this method will only affect provider state for the current user. Callers are
-     * responsible for tracking current user changes and re-updating provider state as necessary.
-     *
-     * <p>While providers are expected to make a best effort to honor this request, it is not a
-     * given that all providers will support such a request. If a provider does change its state as
-     * a result of this request, that may happen asynchronously after some delay. Test location
-     * providers set through {@link android.location.LocationManager#addTestProvider} will respond
-     * to this request to aide in testing.
-     *
-     * @param admin          Which {@link DeviceAdminReceiver} this request is associated with
-     * @param provider       A location provider as listed by
-     *                       {@link android.location.LocationManager#getAllProviders()}
-     * @param providerAllowed Whether the location provider is being requested to enable or disable
-     *                       itself
-     * @throws SecurityException if {@code admin} is not a device owner.
-     */
-    public void requestSetLocationProviderAllowed(@NonNull ComponentName admin,
-            @NonNull String provider, boolean providerAllowed) {
-        throwIfParentInstance("requestSetLocationProviderAllowed");
-        if (mService != null) {
-            try {
-                mService.requestSetLocationProviderAllowed(admin, provider, providerAllowed);
-            } catch (RemoteException e) {
-                throw e.rethrowFromSystemServer();
-            }
-        }
-    }
-
-    /**
      * Called by profile or device owners to update {@link android.provider.Settings.Secure}
      * settings. Validation that the value of the setting is in the correct form for the setting
      * type should be performed by the caller.
@@ -9935,20 +9932,27 @@
     }
 
     /**
-     * Called by device owner to control the security logging feature.
+     * Called by device owner or a profile owner of an organization-owned managed profile to
+     * control the security logging feature.
      *
      * <p> Security logs contain various information intended for security auditing purposes.
-     * See {@link SecurityEvent} for details.
+     * When security logging is enabled by a profile owner of
+     * an organization-owned managed profile, certain security logs are not visible (for example
+     * personal app launch events) or they will be redacted (for example, details of the physical
+     * volume mount events). Please see {@link SecurityEvent} for details.
      *
      * <p><strong>Note:</strong> The device owner won't be able to retrieve security logs if there
      * are unaffiliated secondary users or profiles on the device, regardless of whether the
      * feature is enabled. Logs will be discarded if the internal buffer fills up while waiting for
      * all users to become affiliated. Therefore it's recommended that affiliation ids are set for
-     * new users as soon as possible after provisioning via {@link #setAffiliationIds}.
+     * new users as soon as possible after provisioning via {@link #setAffiliationIds}. Profile
+     * owner of organization-owned managed profile is not subject to this restriction since all
+     * privacy-sensitive events happening outside the managed profile would have been redacted
+     * already.
      *
-     * @param admin Which device owner this request is associated with.
+     * @param admin Which device admin this request is associated with.
      * @param enabled whether security logging should be enabled or not.
-     * @throws SecurityException if {@code admin} is not a device owner.
+     * @throws SecurityException if {@code admin} is not allowed to control security logging.
      * @see #setAffiliationIds
      * @see #retrieveSecurityLogs
      */
@@ -9962,14 +9966,14 @@
     }
 
     /**
-     * Return whether security logging is enabled or not by the device owner.
+     * Return whether security logging is enabled or not by the admin.
      *
-     * <p>Can only be called by the device owner, otherwise a {@link SecurityException} will be
-     * thrown.
+     * <p>Can only be called by the device owner or a profile owner of an organization-owned
+     * managed profile, otherwise a {@link SecurityException} will be thrown.
      *
-     * @param admin Which device owner this request is associated with.
+     * @param admin Which device admin this request is associated with.
      * @return {@code true} if security logging is enabled by device owner, {@code false} otherwise.
-     * @throws SecurityException if {@code admin} is not a device owner.
+     * @throws SecurityException if {@code admin} is not allowed to control security logging.
      */
     public boolean isSecurityLoggingEnabled(@Nullable ComponentName admin) {
         throwIfParentInstance("isSecurityLoggingEnabled");
@@ -9981,20 +9985,21 @@
     }
 
     /**
-     * Called by device owner to retrieve all new security logging entries since the last call to
-     * this API after device boots.
+     * Called by device owner or profile owner of an organization-owned managed profile to retrieve
+     * all new security logging entries since the last call to this API after device boots.
      *
      * <p> Access to the logs is rate limited and it will only return new logs after the device
      * owner has been notified via {@link DeviceAdminReceiver#onSecurityLogsAvailable}.
      *
-     * <p>If there is any other user or profile on the device, it must be affiliated with the
-     * device. Otherwise a {@link SecurityException} will be thrown. See {@link #isAffiliatedUser}.
+     * <p> When called by a device owner, if there is any other user or profile on the device,
+     * it must be affiliated with the device. Otherwise a {@link SecurityException} will be thrown.
+     * See {@link #isAffiliatedUser}.
      *
-     * @param admin Which device owner this request is associated with.
+     * @param admin Which device admin this request is associated with.
      * @return the new batch of security logs which is a list of {@link SecurityEvent},
      * or {@code null} if rate limitation is exceeded or if logging is currently disabled.
-     * @throws SecurityException if {@code admin} is not a device owner, or there is at least one
-     * profile or secondary user that is not affiliated with the device.
+     * @throws SecurityException if {@code admin} is not allowed to access security logging,
+     * or there is at least one profile or secondary user that is not affiliated with the device.
      * @see #isAffiliatedUser
      * @see DeviceAdminReceiver#onSecurityLogsAvailable
      */
@@ -10127,21 +10132,23 @@
     }
 
     /**
-     * Called by device owners to retrieve device logs from before the device's last reboot.
+     * Called by device owner or profile owner of an organization-owned managed profile to retrieve
+     * device logs from before the device's last reboot.
      * <p>
      * <strong> This API is not supported on all devices. Calling this API on unsupported devices
      * will result in {@code null} being returned. The device logs are retrieved from a RAM region
      * which is not guaranteed to be corruption-free during power cycles, as a result be cautious
      * about data corruption when parsing. </strong>
      *
-     * <p>If there is any other user or profile on the device, it must be affiliated with the
-     * device. Otherwise a {@link SecurityException} will be thrown. See {@link #isAffiliatedUser}.
+     * <p> When called by a device owner, if there is any other user or profile on the device,
+     * it must be affiliated with the device. Otherwise a {@link SecurityException} will be thrown.
+     * See {@link #isAffiliatedUser}.
      *
-     * @param admin Which device owner this request is associated with.
+     * @param admin Which device admin this request is associated with.
      * @return Device logs from before the latest reboot of the system, or {@code null} if this API
      *         is not supported on the device.
-     * @throws SecurityException if {@code admin} is not a device owner, or there is at least one
-     * profile or secondary user that is not affiliated with the device.
+     * @throws SecurityException if {@code admin} is not allowed to access security logging, or
+     * there is at least one profile or secondary user that is not affiliated with the device.
      * @see #isAffiliatedUser
      * @see #retrieveSecurityLogs
      */
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 25c1e12..da48663 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -196,7 +196,9 @@
 
     boolean setAlwaysOnVpnPackage(in ComponentName who, String vpnPackage, boolean lockdown, in List<String> lockdownWhitelist);
     String getAlwaysOnVpnPackage(in ComponentName who);
+    String getAlwaysOnVpnPackageForUser(int userHandle);
     boolean isAlwaysOnVpnLockdownEnabled(in ComponentName who);
+    boolean isAlwaysOnVpnLockdownEnabledForUser(int userHandle);
     List<String> getAlwaysOnVpnLockdownWhitelist(in ComponentName who);
 
     void addPersistentPreferredActivity(in ComponentName admin, in IntentFilter filter, in ComponentName activity);
@@ -270,7 +272,6 @@
     boolean hasLockdownAdminConfiguredNetworks(in ComponentName who);
 
     void setLocationEnabled(in ComponentName who, boolean locationEnabled);
-    void requestSetLocationProviderAllowed(in ComponentName who, in String provider, boolean providerAllowed);
 
     boolean setTime(in ComponentName who, long millis);
     boolean setTimeZone(in ComponentName who, String timeZone);
diff --git a/core/java/android/app/admin/SecurityLog.java b/core/java/android/app/admin/SecurityLog.java
index 91cf120..fb7f573 100644
--- a/core/java/android/app/admin/SecurityLog.java
+++ b/core/java/android/app/admin/SecurityLog.java
@@ -23,11 +23,13 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.SystemProperties;
+import android.os.UserHandle;
 import android.util.EventLog.Event;
 
 import java.io.IOException;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Objects;
 
@@ -104,7 +106,8 @@
     /**
      * Indicates that a shell command was issued over ADB via {@code adb shell <command>}
      * The log entry contains a {@code String} payload containing the shell command, accessible
-     * via {@link SecurityEvent#getData()}.
+     * via {@link SecurityEvent#getData()}. If security logging is enabled on organization-owned
+     * managed profile devices, the shell command will be redacted to an empty string.
      */
     public static final int TAG_ADB_SHELL_CMD = SecurityLogTags.SECURITY_ADB_SHELL_COMMAND;
 
@@ -133,6 +136,8 @@
      * <li> [3] app pid ({@code Integer})
      * <li> [4] seinfo tag ({@code String})
      * <li> [5] SHA-256 hash of the base APK in hexadecimal ({@code String})
+     * If security logging is enabled on organization-owned managed profile devices, only events
+     * happening inside the managed profile will be visible.
      */
     public static final int TAG_APP_PROCESS_START = SecurityLogTags.SECURITY_APP_PROCESS_START;
 
@@ -205,7 +210,8 @@
      * following information about the event, encapsulated in an {@link Object} array and
      * accessible via {@link SecurityEvent#getData()}:
      * <li> [0] mount point ({@code String})
-     * <li> [1] volume label ({@code String}).
+     * <li> [1] volume label ({@code String}). Redacted to empty string on organization-owned
+     *     managed profile devices.
      */
     public static final int TAG_MEDIA_MOUNT = SecurityLogTags.SECURITY_MEDIA_MOUNTED;
 
@@ -214,7 +220,8 @@
      * following information about the event, encapsulated in an {@link Object} array and
      * accessible via {@link SecurityEvent#getData()}:
      * <li> [0] mount point ({@code String})
-     * <li> [1] volume label ({@code String}).
+     * <li> [1] volume label ({@code String}). Redacted to empty string on organization-owned
+     *     managed profile devices.
      */
     public static final int TAG_MEDIA_UNMOUNT = SecurityLogTags.SECURITY_MEDIA_UNMOUNTED;
 
@@ -340,6 +347,9 @@
      * <li> [0] result ({@code Integer}, 0 if operation failed, 1 if succeeded)
      * <li> [1] alias of the key ({@code String})
      * <li> [2] requesting process uid ({@code Integer}).
+     *
+     * If security logging is enabled on organization-owned managed profile devices, only events
+     * happening inside the managed profile will be visible.
      */
     public static final int TAG_KEY_GENERATED =
             SecurityLogTags.SECURITY_KEY_GENERATED;
@@ -351,6 +361,9 @@
      * <li> [0] result ({@code Integer}, 0 if operation failed, 1 if succeeded)
      * <li> [1] alias of the key ({@code String})
      * <li> [2] requesting process uid ({@code Integer}).
+     *
+     * If security logging is enabled on organization-owned managed profile devices, only events
+     * happening inside the managed profile will be visible.
      */
     public static final int TAG_KEY_IMPORT = SecurityLogTags.SECURITY_KEY_IMPORTED;
 
@@ -361,6 +374,9 @@
      * <li> [0] result ({@code Integer}, 0 if operation failed, 1 if succeeded)
      * <li> [1] alias of the key ({@code String})
      * <li> [2] requesting process uid ({@code Integer}).
+     *
+     * If security logging is enabled on organization-owned managed profile devices, only events
+     * happening inside the managed profile will be visible.
      */
     public static final int TAG_KEY_DESTRUCTION = SecurityLogTags.SECURITY_KEY_DESTROYED;
 
@@ -370,6 +386,11 @@
      * {@link Object} array and accessible via {@link SecurityEvent#getData()}:
      * <li> [0] result ({@code Integer}, 0 if operation failed, 1 if succeeded)
      * <li> [1] subject of the certificate ({@code String}).
+     * <li> [2] which user the certificate is installed for ({@code Integer}), only available from
+     *   version {@link android.os.Build.VERSION_CODES#R}.
+     *
+     * If security logging is enabled on organization-owned managed profile devices, only events
+     * happening inside the managed profile will be visible.
      */
     public static final int TAG_CERT_AUTHORITY_INSTALLED =
             SecurityLogTags.SECURITY_CERT_AUTHORITY_INSTALLED;
@@ -380,6 +401,11 @@
      * {@link Object} array and accessible via {@link SecurityEvent#getData()}:
      * <li> [0] result ({@code Integer}, 0 if operation failed, 1 if succeeded)
      * <li> [1] subject of the certificate ({@code String}).
+     * <li> [2] which user the certificate is removed from ({@code Integer}), only available from
+     *   version {@link android.os.Build.VERSION_CODES#R}.
+     *
+     * If security logging is enabled on organization-owned managed profile devices, only events
+     * happening inside the managed profile will be visible.
      */
     public static final int TAG_CERT_AUTHORITY_REMOVED =
             SecurityLogTags.SECURITY_CERT_AUTHORITY_REMOVED;
@@ -422,6 +448,9 @@
      * {@link SecurityEvent#getData()}:
      * <li> [0] alias of the key ({@code String})
      * <li> [1] owner application uid ({@code Integer}).
+     *
+     * If security logging is enabled on organization-owned managed profile devices, only events
+     * happening inside the managed profile will be visible.
      */
     public static final int TAG_KEY_INTEGRITY_VIOLATION =
             SecurityLogTags.SECURITY_KEY_INTEGRITY_VIOLATION;
@@ -535,6 +564,16 @@
             return mEvent.getData();
         }
 
+        /** @hide */
+        public int getIntegerData(int index) {
+            return (Integer) ((Object[]) mEvent.getData())[index];
+        }
+
+        /** @hide */
+        public String getStringData(int index) {
+            return (String) ((Object[]) mEvent.getData())[index];
+        }
+
         /**
          * @hide
          */
@@ -554,7 +593,7 @@
          * Returns severity level for the event.
          */
         public @SecurityLogLevel int getLogLevel() {
-            switch (mEvent.getTag()) {
+            switch (getTag()) {
                 case TAG_ADB_SHELL_INTERACTIVE:
                 case TAG_ADB_SHELL_CMD:
                 case TAG_SYNC_RECV_FILE:
@@ -608,6 +647,75 @@
             return array.length >= 1 && array[0] instanceof Integer && (Integer) array[0] != 0;
         }
 
+        /**
+         * Returns a copy of the security event suitable to be consumed by the provided user.
+         * This method will either return the original event itself if the event does not contain
+         * any sensitive data; or a copy of itself but with sensitive information redacted; or
+         * {@code null} if the entire event should not be accessed by the given user.
+         *
+         * @param accessingUser which user this security event is to be accessed, must be a
+         *     concrete user id.
+         * @hide
+         */
+        public SecurityEvent redact(int accessingUser) {
+            // Which user the event is associated with, for the purpose of log redaction.
+            final int userId;
+            switch (getTag()) {
+                case SecurityLog.TAG_ADB_SHELL_CMD:
+                    return new SecurityEvent(getId(), mEvent.withNewData("").getBytes());
+                case SecurityLog.TAG_MEDIA_MOUNT:
+                case SecurityLog.TAG_MEDIA_UNMOUNT:
+                    // Partial redaction
+                    String mountPoint;
+                    try {
+                        mountPoint = getStringData(0);
+                    } catch (Exception e) {
+                        return null;
+                    }
+                    return new SecurityEvent(getId(),
+                            mEvent.withNewData(new Object[] {mountPoint, ""}).getBytes());
+                case SecurityLog.TAG_APP_PROCESS_START:
+                    try {
+                        userId = UserHandle.getUserId(getIntegerData(2));
+                    } catch (Exception e) {
+                        return null;
+                    }
+                    break;
+                case SecurityLog.TAG_CERT_AUTHORITY_INSTALLED:
+                case SecurityLog.TAG_CERT_AUTHORITY_REMOVED:
+                    try {
+                        userId = getIntegerData(2);
+                    } catch (Exception e) {
+                        return null;
+                    }
+                    break;
+                case SecurityLog.TAG_KEY_GENERATED:
+                case SecurityLog.TAG_KEY_IMPORT:
+                case SecurityLog.TAG_KEY_DESTRUCTION:
+                    try {
+                        userId = UserHandle.getUserId(getIntegerData(2));
+                    } catch (Exception e) {
+                        return null;
+                    }
+                    break;
+                case SecurityLog.TAG_KEY_INTEGRITY_VIOLATION:
+                    try {
+                        userId = UserHandle.getUserId(getIntegerData(1));
+                    } catch (Exception e) {
+                        return null;
+                    }
+                    break;
+                default:
+                    userId = UserHandle.USER_NULL;
+            }
+            // If the event is not user-specific, or matches the accessing user, return it
+            // unmodified, else redact by returning null
+            if (userId == UserHandle.USER_NULL || accessingUser == userId) {
+                return this;
+            } else {
+                return null;
+            }
+        }
 
         @Override
         public int describeContents() {
@@ -657,6 +765,30 @@
             return other != null && mEvent.equals(other.mEvent);
         }
     }
+
+    /**
+     * Redacts events in-place according to which user will consume the events.
+     *
+     * @param accessingUser which user will consume the redacted events, or UserHandle.USER_ALL if
+     *     redaction should be skipped.
+     * @hide
+     */
+    public static void redactEvents(ArrayList<SecurityEvent> logList, int accessingUser) {
+        if (accessingUser == UserHandle.USER_ALL) return;
+        int end = 0;
+        for (int i = 0; i < logList.size(); i++) {
+            SecurityEvent event = logList.get(i);
+            event = event.redact(accessingUser);
+            if (event != null) {
+                logList.set(end, event);
+                end++;
+            }
+        }
+        for (int i = logList.size() - 1; i >= end; i--) {
+            logList.remove(i);
+        }
+    }
+
     /**
      * Retrieve all security logs and return immediately.
      * @hide
diff --git a/core/java/android/app/admin/SecurityLogTags.logtags b/core/java/android/app/admin/SecurityLogTags.logtags
index 4e67fe2..100fd4c 100644
--- a/core/java/android/app/admin/SecurityLogTags.logtags
+++ b/core/java/android/app/admin/SecurityLogTags.logtags
@@ -33,8 +33,8 @@
 210026 security_key_destroyed                   (success|1),(key_id|3),(uid|1)
 210027 security_user_restriction_added          (package|3),(admin_user|1),(restriction|3)
 210028 security_user_restriction_removed        (package|3),(admin_user|1),(restriction|3)
-210029 security_cert_authority_installed        (success|1),(subject|3)
-210030 security_cert_authority_removed          (success|1),(subject|3)
+210029 security_cert_authority_installed        (success|1),(subject|3),(target_user|1)
+210030 security_cert_authority_removed          (success|1),(subject|3),(target_user|1)
 210031 security_crypto_self_test_completed      (success|1)
 210032 security_key_integrity_violation         (key_id|3),(uid|1)
 210033 security_cert_validation_failure         (reason|3)
diff --git a/core/java/android/app/trust/IStrongAuthTracker.aidl b/core/java/android/app/trust/IStrongAuthTracker.aidl
index 36c71bf..6d54396 100644
--- a/core/java/android/app/trust/IStrongAuthTracker.aidl
+++ b/core/java/android/app/trust/IStrongAuthTracker.aidl
@@ -23,4 +23,5 @@
  */
 oneway interface IStrongAuthTracker {
     void onStrongAuthRequiredChanged(int strongAuthRequired, int userId);
+    void onIsNonStrongBiometricAllowedChanged(boolean allowed, int userId);
 }
\ No newline at end of file
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index e1942da..bd3298c 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -580,6 +580,15 @@
         }
 
         @Override
+        public void canonicalizeAsync(String callingPkg, @Nullable String featureId, Uri uri,
+                RemoteCallback callback) {
+            final Bundle result = new Bundle();
+            result.putParcelable(ContentResolver.REMOTE_CALLBACK_RESULT,
+                    canonicalize(callingPkg, featureId, uri));
+            callback.sendResult(result);
+        }
+
+        @Override
         public Uri uncanonicalize(String callingPkg, String featureId,  Uri uri) {
             uri = validateIncomingUri(uri);
             int userId = getUserIdFromUri(uri);
diff --git a/core/java/android/content/ContentProviderNative.java b/core/java/android/content/ContentProviderNative.java
index 0f1442d..7bc5901 100644
--- a/core/java/android/content/ContentProviderNative.java
+++ b/core/java/android/content/ContentProviderNative.java
@@ -359,6 +359,16 @@
                     return true;
                 }
 
+                case CANONICALIZE_ASYNC_TRANSACTION: {
+                    data.enforceInterface(IContentProvider.descriptor);
+                    String callingPkg = data.readString();
+                    String featureId = data.readString();
+                    Uri uri = Uri.CREATOR.createFromParcel(data);
+                    RemoteCallback callback = RemoteCallback.CREATOR.createFromParcel(data);
+                    canonicalizeAsync(callingPkg, featureId, uri, callback);
+                    return true;
+                }
+
                 case UNCANONICALIZE_TRANSACTION:
                 {
                     data.enforceInterface(IContentProvider.descriptor);
@@ -823,6 +833,25 @@
     }
 
     @Override
+    /* oneway */ public void canonicalizeAsync(String callingPkg, @Nullable String featureId,
+            Uri uri, RemoteCallback callback) throws RemoteException {
+        Parcel data = Parcel.obtain();
+        try {
+            data.writeInterfaceToken(IContentProvider.descriptor);
+
+            data.writeString(callingPkg);
+            data.writeString(featureId);
+            uri.writeToParcel(data, 0);
+            callback.writeToParcel(data, 0);
+
+            mRemote.transact(IContentProvider.CANONICALIZE_ASYNC_TRANSACTION, data, null,
+                    Binder.FLAG_ONEWAY);
+        } finally {
+            data.recycle();
+        }
+    }
+
+    @Override
     public Uri uncanonicalize(String callingPkg, @Nullable String featureId, Uri url)
             throws RemoteException {
         Parcel data = Parcel.obtain();
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 0e0161f..b748cfa 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -712,14 +712,17 @@
      * {@link #CONTENT_PROVIDER_PUBLISH_TIMEOUT_MILLIS}.
      * @hide
      */
-    public static final int CONTENT_PROVIDER_WAIT_TIMEOUT_MILLIS =
+    public static final int CONTENT_PROVIDER_READY_TIMEOUT_MILLIS =
             CONTENT_PROVIDER_PUBLISH_TIMEOUT_MILLIS + 10 * 1000;
 
+    // Timeout given a ContentProvider that has already been started and connected to.
+    private static final int CONTENT_PROVIDER_TIMEOUT_MILLIS = 3 * 1000;
+
     // Should be >= {@link #CONTENT_PROVIDER_WAIT_TIMEOUT_MILLIS}, because that's how
     // long ActivityManagerService is giving a content provider to get published if a new process
     // needs to be started for that.
-    private static final int GET_TYPE_TIMEOUT_MILLIS =
-            CONTENT_PROVIDER_WAIT_TIMEOUT_MILLIS + 5 * 1000;
+    private static final int REMOTE_CONTENT_PROVIDER_TIMEOUT_MILLIS =
+            CONTENT_PROVIDER_READY_TIMEOUT_MILLIS + CONTENT_PROVIDER_TIMEOUT_MILLIS;
 
     public ContentResolver(@Nullable Context context) {
         this(context, null);
@@ -833,10 +836,10 @@
         IContentProvider provider = acquireExistingProvider(url);
         if (provider != null) {
             try {
-                final GetTypeResultListener resultListener = new GetTypeResultListener();
+                final StringResultListener resultListener = new StringResultListener();
                 provider.getTypeAsync(url, new RemoteCallback(resultListener));
-                resultListener.waitForResult();
-                return resultListener.type;
+                resultListener.waitForResult(CONTENT_PROVIDER_TIMEOUT_MILLIS);
+                return resultListener.result;
             } catch (RemoteException e) {
                 // Arbitrary and not worth documenting, as Activity
                 // Manager will kill this process shortly anyway.
@@ -854,13 +857,13 @@
         }
 
         try {
-            GetTypeResultListener resultListener = new GetTypeResultListener();
+            final StringResultListener resultListener = new StringResultListener();
             ActivityManager.getService().getProviderMimeTypeAsync(
                     ContentProvider.getUriWithoutUserId(url),
                     resolveUserId(url),
                     new RemoteCallback(resultListener));
-            resultListener.waitForResult();
-            return resultListener.type;
+            resultListener.waitForResult(REMOTE_CONTENT_PROVIDER_TIMEOUT_MILLIS);
+            return resultListener.result;
         } catch (RemoteException e) {
             // We just failed to send a oneway request to the System Server. Nothing to do.
             return null;
@@ -870,27 +873,29 @@
         }
     }
 
-    private static class GetTypeResultListener implements RemoteCallback.OnResultListener {
+    private abstract static class ResultListener<T> implements RemoteCallback.OnResultListener {
         @GuardedBy("this")
         public boolean done;
 
         @GuardedBy("this")
-        public String type;
+        public T result;
 
         @Override
         public void onResult(Bundle result) {
             synchronized (this) {
-                type = result.getString(REMOTE_CALLBACK_RESULT);
+                this.result = getResultFromBundle(result);
                 done = true;
                 notifyAll();
             }
         }
 
-        public void waitForResult() {
+        protected abstract T getResultFromBundle(Bundle result);
+
+        public void waitForResult(long timeout) {
             synchronized (this) {
                 if (!done) {
                     try {
-                        wait(GET_TYPE_TIMEOUT_MILLIS);
+                        wait(timeout);
                     } catch (InterruptedException e) {
                         // Ignore
                     }
@@ -899,6 +904,20 @@
         }
     }
 
+    private static class StringResultListener extends ResultListener<String> {
+        @Override
+        protected String getResultFromBundle(Bundle result) {
+            return result.getString(REMOTE_CALLBACK_RESULT);
+        }
+    }
+
+    private static class UriResultListener extends ResultListener<Uri> {
+        @Override
+        protected Uri getResultFromBundle(Bundle result) {
+            return result.getParcelable(REMOTE_CALLBACK_RESULT);
+        }
+    }
+
     /**
      * Query for the possible MIME types for the representations the given
      * content URL can be returned when opened as as stream with
@@ -1192,7 +1211,11 @@
         }
 
         try {
-            return provider.canonicalize(mPackageName, mFeatureId, url);
+            final UriResultListener resultListener = new UriResultListener();
+            provider.canonicalizeAsync(mPackageName, mFeatureId, url,
+                    new RemoteCallback(resultListener));
+            resultListener.waitForResult(CONTENT_PROVIDER_TIMEOUT_MILLIS);
+            return resultListener.result;
         } catch (RemoteException e) {
             // Arbitrary and not worth documenting, as Activity
             // Manager will kill this process shortly anyway.
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index ae12de0..c6e84b7 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3495,13 +3495,23 @@
      * <dl>
      *  <dt> {@link #WINDOW_SERVICE} ("window")
      *  <dd> The top-level window manager in which you can place custom
-     *  windows.  The returned object is a {@link android.view.WindowManager}.
+     *  windows.  The returned object is a {@link android.view.WindowManager}. Must only be obtained
+     *  from a visual context such as Activity or a Context created with
+     *  {@link #createWindowContext(int, Bundle)}, which are adjusted to the configuration and
+     *  visual bounds of an area on screen.
      *  <dt> {@link #LAYOUT_INFLATER_SERVICE} ("layout_inflater")
      *  <dd> A {@link android.view.LayoutInflater} for inflating layout resources
-     *  in this context.
+     *  in this context. Must only be obtained from a visual context such as Activity or a Context
+     *  created with {@link #createWindowContext(int, Bundle)}, which are adjusted to the
+     *  configuration and visual bounds of an area on screen.
      *  <dt> {@link #ACTIVITY_SERVICE} ("activity")
      *  <dd> A {@link android.app.ActivityManager} for interacting with the
      *  global activity state of the system.
+     *  <dt> {@link #WALLPAPER_SERVICE} ("wallpaper")
+     *  <dd> A {@link android.service.wallpaper.WallpaperService} for accessing wallpapers in this
+     *  context. Must only be obtained from a visual context such as Activity or a Context created
+     *  with {@link #createWindowContext(int, Bundle)}, which are adjusted to the configuration and
+     *  visual bounds of an area on screen.
      *  <dt> {@link #POWER_SERVICE} ("power")
      *  <dd> A {@link android.os.PowerManager} for controlling power
      *  management.
@@ -5901,6 +5911,8 @@
      * {@link #createDisplayContext(Display)} to get a display object associated with a Context, or
      * {@link android.hardware.display.DisplayManager#getDisplay} to get a display object by id.
      * @return Returns the {@link Display} object this context is associated with.
+     * @throws UnsupportedOperationException if the method is called on an instance that is not
+     *         associated with any display.
      */
     @Nullable
     public Display getDisplay() {
@@ -5908,6 +5920,17 @@
     }
 
     /**
+     * A version of {@link #getDisplay()} that does not perform a Context misuse check to be used by
+     * legacy APIs.
+     * TODO(b/149790106): Fix usages and remove.
+     * @hide
+     */
+    @Nullable
+    public Display getDisplayNoVerify() {
+        throw new RuntimeException("Not implemented. Must override in a subclass.");
+    }
+
+    /**
      * Gets the ID of the display this context is associated with.
      *
      * @return display ID associated with this {@link Context}.
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index f6515e8..e5381ea 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -1003,6 +1003,12 @@
         return mBase.getDisplay();
     }
 
+    /** @hide */
+    @Override
+    public @Nullable Display getDisplayNoVerify() {
+        return mBase.getDisplayNoVerify();
+    }
+
     /**
      * @hide
      */
diff --git a/core/java/android/content/IContentProvider.java b/core/java/android/content/IContentProvider.java
index 4658ba1..37643da 100644
--- a/core/java/android/content/IContentProvider.java
+++ b/core/java/android/content/IContentProvider.java
@@ -45,7 +45,7 @@
     public String getType(Uri url) throws RemoteException;
 
     /**
-     * An oneway version of getType. The functionality is exactly the same, except that the
+     * A oneway version of getType. The functionality is exactly the same, except that the
      * call returns immediately, and the resulting type is returned when available via
      * a binder callback.
      */
@@ -126,6 +126,14 @@
     public Uri canonicalize(String callingPkg, @Nullable String featureId, Uri uri)
             throws RemoteException;
 
+    /**
+     * A oneway version of canonicalize. The functionality is exactly the same, except that the
+     * call returns immediately, and the resulting type is returned when available via
+     * a binder callback.
+     */
+    void canonicalizeAsync(String callingPkg, @Nullable String featureId, Uri uri,
+            RemoteCallback callback) throws RemoteException;
+
     public Uri uncanonicalize(String callingPkg, @Nullable String featureId, Uri uri)
             throws RemoteException;
 
@@ -162,4 +170,5 @@
     static final int REFRESH_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 26;
     static final int CHECK_URI_PERMISSION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 27;
     int GET_TYPE_ASYNC_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 28;
+    int CANONICALIZE_ASYNC_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 29;
 }
diff --git a/core/java/android/content/integrity/AppInstallMetadata.java b/core/java/android/content/integrity/AppInstallMetadata.java
index 4be7e6d..4ec9476 100644
--- a/core/java/android/content/integrity/AppInstallMetadata.java
+++ b/core/java/android/content/integrity/AppInstallMetadata.java
@@ -42,6 +42,9 @@
     private final List<String> mInstallerCertificates;
     private final long mVersionCode;
     private final boolean mIsPreInstalled;
+    private final boolean mIsStampTrusted;
+    // Raw string encoding for the SHA-256 hash of the certificate of the stamp.
+    private final String mStampCertificateHash;
     private final Map<String, String> mAllowedInstallersAndCertificates;
 
     private AppInstallMetadata(Builder builder) {
@@ -51,6 +54,8 @@
         this.mInstallerCertificates = builder.mInstallerCertificates;
         this.mVersionCode = builder.mVersionCode;
         this.mIsPreInstalled = builder.mIsPreInstalled;
+        this.mIsStampTrusted = builder.mIsStampTrusted;
+        this.mStampCertificateHash = builder.mStampCertificateHash;
         this.mAllowedInstallersAndCertificates = builder.mAllowedInstallersAndCertificates;
     }
 
@@ -84,9 +89,17 @@
         return mIsPreInstalled;
     }
 
-    /**
-     * Get the allowed installers and their corresponding cert.
-     */
+    /** @see AppInstallMetadata.Builder#setIsStampTrusted(boolean) */
+    public boolean isStampTrusted() {
+        return mIsStampTrusted;
+    }
+
+    /** @see AppInstallMetadata.Builder#setStampCertificateHash(String) */
+    public String getStampCertificateHash() {
+        return mStampCertificateHash;
+    }
+
+    /** Get the allowed installers and their corresponding cert. */
     public Map<String, String> getAllowedInstallersAndCertificates() {
         return mAllowedInstallersAndCertificates;
     }
@@ -95,13 +108,16 @@
     public String toString() {
         return String.format(
                 "AppInstallMetadata { PackageName = %s, AppCerts = %s, InstallerName = %s,"
-                    + " InstallerCerts = %s, VersionCode = %d, PreInstalled = %b }",
+                        + " InstallerCerts = %s, VersionCode = %d, PreInstalled = %b, "
+                        + "StampTrusted = %b, StampCert = %s }",
                 mPackageName,
                 mAppCertificates,
                 mInstallerName == null ? "null" : mInstallerName,
                 mInstallerCertificates == null ? "null" : mInstallerCertificates,
                 mVersionCode,
-                mIsPreInstalled);
+                mIsPreInstalled,
+                mIsStampTrusted,
+                mStampCertificateHash == null ? "null" : mStampCertificateHash);
     }
 
     /** Builder class for constructing {@link AppInstallMetadata} objects. */
@@ -112,6 +128,8 @@
         private List<String> mInstallerCertificates;
         private long mVersionCode;
         private boolean mIsPreInstalled;
+        private boolean mIsStampTrusted;
+        private String mStampCertificateHash;
         private Map<String, String> mAllowedInstallersAndCertificates;
 
         public Builder() {
@@ -203,6 +221,31 @@
         }
 
         /**
+         * Set certificate hash of the stamp embedded in the APK.
+         *
+         * <p>It is represented as the raw string encoding for the SHA-256 hash of the certificate
+         * of the stamp.
+         *
+         * @see AppInstallMetadata#getStampCertificateHash()
+         */
+        @NonNull
+        public Builder setStampCertificateHash(@NonNull String stampCertificateHash) {
+            this.mStampCertificateHash = Objects.requireNonNull(stampCertificateHash);
+            return this;
+        }
+
+        /**
+         * Set whether the stamp embedded in the APK is trusted or not.
+         *
+         * @see AppInstallMetadata#isStampTrusted()
+         */
+        @NonNull
+        public Builder setIsStampTrusted(boolean isStampTrusted) {
+            this.mIsStampTrusted = isStampTrusted;
+            return this;
+        }
+
+        /**
          * Build {@link AppInstallMetadata}.
          *
          * @throws IllegalArgumentException if package name or app certificate is null
diff --git a/core/java/android/content/integrity/AtomicFormula.java b/core/java/android/content/integrity/AtomicFormula.java
index d911eab..977a631 100644
--- a/core/java/android/content/integrity/AtomicFormula.java
+++ b/core/java/android/content/integrity/AtomicFormula.java
@@ -47,12 +47,14 @@
     /** @hide */
     @IntDef(
             value = {
-                    PACKAGE_NAME,
-                    APP_CERTIFICATE,
-                    INSTALLER_NAME,
-                    INSTALLER_CERTIFICATE,
-                    VERSION_CODE,
-                    PRE_INSTALLED,
+                PACKAGE_NAME,
+                APP_CERTIFICATE,
+                INSTALLER_NAME,
+                INSTALLER_CERTIFICATE,
+                VERSION_CODE,
+                PRE_INSTALLED,
+                STAMP_TRUSTED,
+                STAMP_CERTIFICATE_HASH,
             })
     @Retention(RetentionPolicy.SOURCE)
     public @interface Key {}
@@ -105,6 +107,20 @@
      */
     public static final int PRE_INSTALLED = 5;
 
+    /**
+     * If the APK has an embedded trusted stamp.
+     *
+     * <p>Can only be used in {@link BooleanAtomicFormula}.
+     */
+    public static final int STAMP_TRUSTED = 6;
+
+    /**
+     * SHA-256 of the certificate used to sign the stamp embedded in the APK.
+     *
+     * <p>Can only be used in {@link StringAtomicFormula}.
+     */
+    public static final int STAMP_CERTIFICATE_HASH = 7;
+
     public static final int EQ = 0;
     public static final int GT = 1;
     public static final int GTE = 2;
@@ -266,9 +282,7 @@
         }
 
         private static boolean isValidOperator(int operator) {
-            return operator == EQ
-                    || operator == GT
-                    || operator == GTE;
+            return operator == EQ || operator == GT || operator == GTE;
         }
 
         private static long getLongMetadataValue(AppInstallMetadata appInstallMetadata, int key) {
@@ -300,7 +314,8 @@
                     key == PACKAGE_NAME
                             || key == APP_CERTIFICATE
                             || key == INSTALLER_CERTIFICATE
-                            || key == INSTALLER_NAME,
+                            || key == INSTALLER_NAME
+                            || key == STAMP_CERTIFICATE_HASH,
                     String.format(
                             "Key %s cannot be used with StringAtomicFormula", keyToString(key)));
             mValue = null;
@@ -321,7 +336,8 @@
                     key == PACKAGE_NAME
                             || key == APP_CERTIFICATE
                             || key == INSTALLER_CERTIFICATE
-                            || key == INSTALLER_NAME,
+                            || key == INSTALLER_NAME
+                            || key == STAMP_CERTIFICATE_HASH,
                     String.format(
                             "Key %s cannot be used with StringAtomicFormula", keyToString(key)));
             mValue = value;
@@ -329,15 +345,14 @@
         }
 
         /**
-         * Constructs a new {@link StringAtomicFormula} together with handling the necessary
-         * hashing for the given key.
+         * Constructs a new {@link StringAtomicFormula} together with handling the necessary hashing
+         * for the given key.
          *
-         * <p> The value will be automatically hashed with SHA256 and the hex digest will be
-         * computed when the key is PACKAGE_NAME or INSTALLER_NAME and the value is more than 32
-         * characters.
+         * <p>The value will be automatically hashed with SHA256 and the hex digest will be computed
+         * when the key is PACKAGE_NAME or INSTALLER_NAME and the value is more than 32 characters.
          *
-         * <p> The APP_CERTIFICATES and INSTALLER_CERTIFICATES are always delivered in hashed
-         * form. So the isHashedValue is set to true by default.
+         * <p>The APP_CERTIFICATES, INSTALLER_CERTIFICATES, and STAMP_CERTIFICATE_HASH are always
+         * delivered in hashed form. So the isHashedValue is set to true by default.
          *
          * @throws IllegalArgumentException if {@code key} cannot be used with string value.
          */
@@ -347,13 +362,15 @@
                     key == PACKAGE_NAME
                             || key == APP_CERTIFICATE
                             || key == INSTALLER_CERTIFICATE
-                            || key == INSTALLER_NAME,
+                            || key == INSTALLER_NAME
+                            || key == STAMP_CERTIFICATE_HASH,
                     String.format(
                             "Key %s cannot be used with StringAtomicFormula", keyToString(key)));
             mValue = hashValue(key, value);
             mIsHashedValue =
                     key == APP_CERTIFICATE
-                            || key == INSTALLER_CERTIFICATE
+                                    || key == INSTALLER_CERTIFICATE
+                                    || key == STAMP_CERTIFICATE_HASH
                             ? true
                             : !mValue.equals(value);
         }
@@ -460,6 +477,8 @@
                     return appInstallMetadata.getInstallerCertificates();
                 case AtomicFormula.INSTALLER_NAME:
                     return Collections.singletonList(appInstallMetadata.getInstallerName());
+                case AtomicFormula.STAMP_CERTIFICATE_HASH:
+                    return Collections.singletonList(appInstallMetadata.getStampCertificateHash());
                 default:
                     throw new IllegalStateException(
                             "Unexpected key in StringAtomicFormula: " + key);
@@ -502,7 +521,7 @@
         public BooleanAtomicFormula(@Key int key) {
             super(key);
             checkArgument(
-                    key == PRE_INSTALLED,
+                    key == PRE_INSTALLED || key == STAMP_TRUSTED,
                     String.format(
                             "Key %s cannot be used with BooleanAtomicFormula", keyToString(key)));
             mValue = null;
@@ -519,7 +538,7 @@
         public BooleanAtomicFormula(@Key int key, boolean value) {
             super(key);
             checkArgument(
-                    key == PRE_INSTALLED,
+                    key == PRE_INSTALLED || key == STAMP_TRUSTED,
                     String.format(
                             "Key %s cannot be used with BooleanAtomicFormula", keyToString(key)));
             mValue = value;
@@ -615,6 +634,8 @@
             switch (key) {
                 case AtomicFormula.PRE_INSTALLED:
                     return appInstallMetadata.isPreInstalled();
+                case AtomicFormula.STAMP_TRUSTED:
+                    return appInstallMetadata.isStampTrusted();
                 default:
                     throw new IllegalStateException(
                             "Unexpected key in BooleanAtomicFormula: " + key);
@@ -640,6 +661,10 @@
                 return "INSTALLER_CERTIFICATE";
             case PRE_INSTALLED:
                 return "PRE_INSTALLED";
+            case STAMP_TRUSTED:
+                return "STAMP_TRUSTED";
+            case STAMP_CERTIFICATE_HASH:
+                return "STAMP_CERTIFICATE_HASH";
             default:
                 throw new IllegalArgumentException("Unknown key " + key);
         }
@@ -664,6 +689,8 @@
                 || key == VERSION_CODE
                 || key == INSTALLER_NAME
                 || key == INSTALLER_CERTIFICATE
-                || key == PRE_INSTALLED;
+                || key == PRE_INSTALLED
+                || key == STAMP_TRUSTED
+                || key == STAMP_CERTIFICATE_HASH;
     }
 }
diff --git a/core/java/android/content/integrity/IntegrityFormula.java b/core/java/android/content/integrity/IntegrityFormula.java
index c5e5c8a..fc177721 100644
--- a/core/java/android/content/integrity/IntegrityFormula.java
+++ b/core/java/android/content/integrity/IntegrityFormula.java
@@ -90,8 +90,7 @@
             return new BooleanAtomicFormula(AtomicFormula.PRE_INSTALLED, true);
         }
 
-        private Application() {
-        }
+        private Application() {}
     }
 
     /** Factory class for creating integrity formulas based on installer. */
@@ -117,26 +116,45 @@
          */
         @NonNull
         public static IntegrityFormula certificatesContain(@NonNull String installerCertificate) {
-            return new StringAtomicFormula(AtomicFormula.INSTALLER_CERTIFICATE,
-                    installerCertificate);
+            return new StringAtomicFormula(
+                    AtomicFormula.INSTALLER_CERTIFICATE, installerCertificate);
         }
 
-        private Installer() {
+        private Installer() {}
+    }
+
+    /** Factory class for creating integrity formulas based on source stamp. */
+    public static final class SourceStamp {
+        /** Returns an integrity formula that checks the equality to a stamp certificate hash. */
+        @NonNull
+        public static IntegrityFormula stampCertificateHashEquals(
+                @NonNull String stampCertificateHash) {
+            return new StringAtomicFormula(
+                    AtomicFormula.STAMP_CERTIFICATE_HASH, stampCertificateHash);
         }
+
+        /**
+         * Returns an integrity formula that is valid when stamp embedded in the APK is NOT trusted.
+         */
+        @NonNull
+        public static IntegrityFormula notTrusted() {
+            return new BooleanAtomicFormula(AtomicFormula.STAMP_TRUSTED, /* value= */ false);
+        }
+
+        private SourceStamp() {}
     }
 
     /** @hide */
     @IntDef(
             value = {
-                    COMPOUND_FORMULA_TAG,
-                    STRING_ATOMIC_FORMULA_TAG,
-                    LONG_ATOMIC_FORMULA_TAG,
-                    BOOLEAN_ATOMIC_FORMULA_TAG,
-                    INSTALLER_ALLOWED_BY_MANIFEST_FORMULA_TAG
+                COMPOUND_FORMULA_TAG,
+                STRING_ATOMIC_FORMULA_TAG,
+                LONG_ATOMIC_FORMULA_TAG,
+                BOOLEAN_ATOMIC_FORMULA_TAG,
+                INSTALLER_ALLOWED_BY_MANIFEST_FORMULA_TAG
             })
     @Retention(RetentionPolicy.SOURCE)
-    @interface Tag {
-    }
+    @interface Tag {}
 
     /** @hide */
     public static final int COMPOUND_FORMULA_TAG = 0;
@@ -171,8 +189,8 @@
     public abstract boolean isAppCertificateFormula();
 
     /**
-     * Returns true when the formula (or one of its atomic formulas) has installer package name
-     * or installer certificate as key.
+     * Returns true when the formula (or one of its atomic formulas) has installer package name or
+     * installer certificate as key.
      *
      * @hide
      */
@@ -243,15 +261,12 @@
         return new CompoundFormula(CompoundFormula.AND, Arrays.asList(formulae));
     }
 
-    /**
-     * Returns a formula that evaluates to true when {@code formula} evaluates to false.
-     */
+    /** Returns a formula that evaluates to true when {@code formula} evaluates to false. */
     @NonNull
     public static IntegrityFormula not(@NonNull IntegrityFormula formula) {
         return new CompoundFormula(CompoundFormula.NOT, Arrays.asList(formula));
     }
 
     // Constructor is package private so it cannot be inherited outside of this package.
-    IntegrityFormula() {
-    }
+    IntegrityFormula() {}
 }
diff --git a/core/java/android/content/pm/AndroidTestBaseUpdater.java b/core/java/android/content/pm/AndroidTestBaseUpdater.java
new file mode 100644
index 0000000..1cbbdca
--- /dev/null
+++ b/core/java/android/content/pm/AndroidTestBaseUpdater.java
@@ -0,0 +1,26 @@
+/*
+ * 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;
+
+/**
+ * Dummy class to maintain legacy behavior of including a class in core source to toggle
+ * whether or not a shared library is stripped at build time.
+ *
+ * @hide
+ */
+public class AndroidTestBaseUpdater {
+}
diff --git a/core/java/android/content/pm/ILauncherApps.aidl b/core/java/android/content/pm/ILauncherApps.aidl
index b5f4f80..8a89840 100644
--- a/core/java/android/content/pm/ILauncherApps.aidl
+++ b/core/java/android/content/pm/ILauncherApps.aidl
@@ -95,9 +95,9 @@
 
     void registerShortcutChangeCallback(String callingPackage, long changedSince,
             String packageName, in List shortcutIds, in List<LocusId> locusIds,
-            in ComponentName componentName, int flags, in IShortcutChangeCallback callback,
-            int callbackId);
-    void unregisterShortcutChangeCallback(String callingPackage, int callbackId);
+            in ComponentName componentName, int flags, in IShortcutChangeCallback callback);
+    void unregisterShortcutChangeCallback(String callingPackage,
+            in IShortcutChangeCallback callback);
 
     void cacheShortcuts(String callingPackage, String packageName, in List<String> shortcutIds,
             in UserHandle user);
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index b89901a..e9cdbf28 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -482,19 +482,12 @@
      * Notify the package manager that a list of dex files have been loaded.
      *
      * @param loadingPackageName the name of the package who performs the load
-     * @param classLoadersNames the names of the class loaders present in the loading chain. The
-     *    list encodes the class loader chain in the natural order. The first class loader has
-     *    the second one as its parent and so on. The dex files present in the class path of the
-     *    first class loader will be recorded in the usage file.
-     * @param classPaths the class paths corresponding to the class loaders names from
-     *     {@param classLoadersNames}. The the first element corresponds to the first class loader
-     *     and so on. A classpath is represented as a list of dex files separated by
-     *     {@code File.pathSeparator}, or null if the class loader's classpath is not known.
-     *     The dex files found in the first class path will be recorded in the usage file.
+     * @param classLoaderContextMap a map from file paths to dex files that have been loaded to
+     *     the class loader context that was used to load them.
      * @param loaderIsa the ISA of the loader process
      */
-    oneway void notifyDexLoad(String loadingPackageName, in List<String> classLoadersNames,
-            in List<String> classPaths, String loaderIsa);
+    oneway void notifyDexLoad(String loadingPackageName,
+            in Map<String, String> classLoaderContextMap, String loaderIsa);
 
     /**
      * Register an application dex module with the package manager.
diff --git a/core/java/android/content/pm/IShortcutService.aidl b/core/java/android/content/pm/IShortcutService.aidl
index 9e85fc3..29a55b7 100644
--- a/core/java/android/content/pm/IShortcutService.aidl
+++ b/core/java/android/content/pm/IShortcutService.aidl
@@ -76,4 +76,6 @@
     void removeLongLivedShortcuts(String packageName, in List shortcutIds, int userId);
 
     ParceledListSlice getShortcuts(String packageName, int matchFlags, int userId);
+
+    void pushDynamicShortcut(String packageName, in ShortcutInfo shortcut, int userId);
 }
\ No newline at end of file
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index 5aa0208..86242fd 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -17,6 +17,7 @@
 package android.content.pm;
 
 import static android.Manifest.permission;
+
 import android.annotation.CallbackExecutor;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
@@ -161,7 +162,7 @@
     private final List<CallbackMessageHandler> mCallbacks = new ArrayList<>();
     private final List<SessionCallbackDelegate> mDelegates = new ArrayList<>();
 
-    private final Map<Integer, Pair<Executor, ShortcutChangeCallback>>
+    private final Map<ShortcutChangeCallback, Pair<Executor, IShortcutChangeCallback>>
             mShortcutChangeCallbacks = new HashMap<>();
 
     /**
@@ -549,8 +550,8 @@
             android.content.pm.IShortcutChangeCallback.Stub {
         private final WeakReference<Pair<Executor, ShortcutChangeCallback>> mRemoteReferences;
 
-        ShortcutChangeCallbackProxy(Pair<Executor, ShortcutChangeCallback> remoteReferences) {
-            mRemoteReferences = new WeakReference<>(remoteReferences);
+        ShortcutChangeCallbackProxy(Executor executor, ShortcutChangeCallback callback) {
+            mRemoteReferences = new WeakReference<>(new Pair<>(executor, callback));
         }
 
         @Override
@@ -1753,14 +1754,12 @@
         Objects.requireNonNull(executor, "Executor cannot be null");
 
         synchronized (mShortcutChangeCallbacks) {
-            final int callbackId = callback.hashCode();
-            final Pair<Executor, ShortcutChangeCallback> state = new Pair<>(executor, callback);
-            mShortcutChangeCallbacks.put(callbackId, state);
+            IShortcutChangeCallback proxy = new ShortcutChangeCallbackProxy(executor, callback);
+            mShortcutChangeCallbacks.put(callback, new Pair<>(executor, proxy));
             try {
                 mService.registerShortcutChangeCallback(mContext.getPackageName(),
                         query.mChangedSince, query.mPackage, query.mShortcutIds, query.mLocusIds,
-                        query.mActivity, query.mQueryFlags, new ShortcutChangeCallbackProxy(state),
-                        callbackId);
+                        query.mActivity, query.mQueryFlags, proxy);
             } catch (RemoteException e) {
                 throw e.rethrowFromSystemServer();
             }
@@ -1779,12 +1778,10 @@
         Objects.requireNonNull(callback, "Callback cannot be null");
 
         synchronized (mShortcutChangeCallbacks) {
-            final int callbackId = callback.hashCode();
-            if (mShortcutChangeCallbacks.containsKey(callbackId)) {
-                mShortcutChangeCallbacks.remove(callbackId);
+            if (mShortcutChangeCallbacks.containsKey(callback)) {
+                IShortcutChangeCallback proxy = mShortcutChangeCallbacks.remove(callback).second;
                 try {
-                    mService.unregisterShortcutChangeCallback(mContext.getPackageName(),
-                            callbackId);
+                    mService.unregisterShortcutChangeCallback(mContext.getPackageName(), proxy);
                 } catch (RemoteException e) {
                     throw e.rethrowFromSystemServer();
                 }
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 168679e..1de82450 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -41,7 +41,6 @@
 import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
 import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_UNSPECIFIED;
 
-import android.annotation.AnyThread;
 import android.annotation.IntDef;
 import android.annotation.IntRange;
 import android.annotation.NonNull;
@@ -56,12 +55,7 @@
 import android.content.ComponentName;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.content.pm.PackageParserCacheHelper.ReadHelper;
-import android.content.pm.PackageParserCacheHelper.WriteHelper;
-import android.content.pm.parsing.AndroidPackage;
-import android.content.pm.parsing.ApkParseUtils;
-import android.content.pm.parsing.PackageImpl;
-import android.content.pm.parsing.ParsedPackage;
+import android.content.pm.parsing.ParsingPackageUtils;
 import android.content.pm.permission.SplitPermissionInfoParcelable;
 import android.content.pm.split.DefaultSplitAssetLoader;
 import android.content.pm.split.SplitAssetDependencyLoader;
@@ -79,14 +73,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 +108,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,9 +305,6 @@
 
     public int mParseError = PackageManager.INSTALL_SUCCEEDED;
 
-    public ThreadLocal<ApkParseUtils.ParseResult> mSharedResult
-            = ThreadLocal.withInitial(ApkParseUtils.ParseResult::new);
-
     public static boolean sCompatibilityModeEnabled = true;
     public static boolean sUseRoundIcon = false;
 
@@ -1054,7 +1040,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 +1068,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 +1075,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 +1137,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 {
@@ -1695,7 +1486,7 @@
         }
     }
 
-    private static String validateName(String name, boolean requireSeparator,
+    public static String validateName(String name, boolean requireSeparator,
             boolean requireFilename) {
         final int N = name.length();
         boolean hasSep = false;
diff --git a/core/java/android/content/pm/PackageUserState.java b/core/java/android/content/pm/PackageUserState.java
index da7623a..30cf4e7 100644
--- a/core/java/android/content/pm/PackageUserState.java
+++ b/core/java/android/content/pm/PackageUserState.java
@@ -28,7 +28,7 @@
 import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
 
 import android.compat.annotation.UnsupportedAppUsage;
-import android.content.pm.parsing.ComponentParseUtils;
+import android.content.pm.parsing.component.ParsedMainComponent;
 import android.os.BaseBundle;
 import android.os.Debug;
 import android.os.PersistableBundle;
@@ -163,7 +163,7 @@
     }
 
     public boolean isMatch(boolean isSystem, boolean isPackageEnabled,
-            ComponentParseUtils.ParsedComponent component, int flags) {
+            ParsedMainComponent component, int flags) {
         return isMatch(isSystem, isPackageEnabled, component.isEnabled(),
                 component.isDirectBootAware(), component.getName(), flags);
     }
@@ -217,7 +217,7 @@
     }
 
     public boolean isEnabled(boolean isPackageEnabled,
-            ComponentParseUtils.ParsedComponent parsedComponent, int flags) {
+            ParsedMainComponent parsedComponent, int flags) {
         return isEnabled(isPackageEnabled, parsedComponent.isEnabled(), parsedComponent.getName(),
                 flags);
     }
diff --git a/core/java/android/content/pm/ResolveInfo.java b/core/java/android/content/pm/ResolveInfo.java
index 55846ad..82b07f2 100644
--- a/core/java/android/content/pm/ResolveInfo.java
+++ b/core/java/android/content/pm/ResolveInfo.java
@@ -39,6 +39,8 @@
  */
 public class ResolveInfo implements Parcelable {
     private static final String TAG = "ResolveInfo";
+    private static final String INTENT_FORWARDER_ACTIVITY =
+            "com.android.internal.app.IntentForwarderActivity";
 
     /**
      * The activity or broadcast receiver that corresponds to this resolution
@@ -351,6 +353,16 @@
         }
     }
 
+    /**
+     * Returns whether this resolution represents the intent forwarder activity.
+     *
+     * @return whether this resolution represents the intent forwarder activity
+     */
+    public boolean isCrossProfileIntentForwarderActivity() {
+        return activityInfo != null
+                && INTENT_FORWARDER_ACTIVITY.equals(activityInfo.targetActivity);
+    }
+
     public ResolveInfo() {
         targetUserId = UserHandle.USER_CURRENT;
     }
diff --git a/core/java/android/content/pm/SharedLibraryInfo.java b/core/java/android/content/pm/SharedLibraryInfo.java
index 2863b26..fe4b36f 100644
--- a/core/java/android/content/pm/SharedLibraryInfo.java
+++ b/core/java/android/content/pm/SharedLibraryInfo.java
@@ -20,7 +20,6 @@
 import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.content.pm.parsing.AndroidPackage;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -39,28 +38,6 @@
 public final class SharedLibraryInfo implements Parcelable {
 
     /** @hide */
-    public static SharedLibraryInfo createForStatic(AndroidPackage pkg) {
-        return new SharedLibraryInfo(null, pkg.getPackageName(),
-                pkg.makeListAllCodePaths(),
-                pkg.getStaticSharedLibName(),
-                pkg.getStaticSharedLibVersion(),
-                TYPE_STATIC,
-                new VersionedPackage(pkg.getManifestPackageName(),
-                        pkg.getLongVersionCode()),
-                null, null);
-    }
-
-    /** @hide */
-    public static SharedLibraryInfo createForDynamic(AndroidPackage pkg, String name) {
-        return new SharedLibraryInfo(null, pkg.getPackageName(),
-                pkg.makeListAllCodePaths(), name,
-                (long) VERSION_UNDEFINED,
-                TYPE_DYNAMIC, new VersionedPackage(pkg.getPackageName(),
-                pkg.getLongVersionCode()),
-                null, null);
-    }
-
-    /** @hide */
     @IntDef(flag = true, prefix = { "TYPE_" }, value = {
             TYPE_BUILTIN,
             TYPE_DYNAMIC,
diff --git a/core/java/android/content/pm/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java
index bde4f61..49e8c05 100644
--- a/core/java/android/content/pm/ShortcutInfo.java
+++ b/core/java/android/content/pm/ShortcutInfo.java
@@ -1726,11 +1726,11 @@
     }
 
     /**
-     * @return true if pinned but neither static nor dynamic.
+     * @return true if pinned or cached, but neither static nor dynamic.
      * @hide
      */
     public boolean isFloating() {
-        return isPinned() && !(isDynamic() || isManifestShortcut());
+        return (isPinned() || isCached()) && !(isDynamic() || isManifestShortcut());
     }
 
     /** @hide */
diff --git a/core/java/android/content/pm/ShortcutManager.java b/core/java/android/content/pm/ShortcutManager.java
index 3eea3f6..35c99a1 100644
--- a/core/java/android/content/pm/ShortcutManager.java
+++ b/core/java/android/content/pm/ShortcutManager.java
@@ -24,6 +24,7 @@
 import android.annotation.SystemService;
 import android.annotation.TestApi;
 import android.annotation.UserIdInt;
+import android.app.Notification;
 import android.app.usage.UsageStatsManager;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
@@ -741,4 +742,33 @@
             throw e.rethrowFromSystemServer();
         }
     }
+
+    /**
+     * Publish a single dynamic shortcut. If there are already dynamic or pinned shortcuts with the
+     * same ID, each mutable shortcut is updated.
+     *
+     * <p>This method is useful when posting notifications which are tagged with shortcut IDs; In
+     * order to make sure shortcuts exist and are up-to-date, without the need to explicitly handle
+     * the shortcut count limit.
+     * @see android.app.NotificationManager#notify(int, Notification)
+     * @see Notification.Builder#setShortcutId(String)
+     *
+     * <p>If {@link #getMaxShortcutCountPerActivity()} is already reached, an existing shortcut with
+     * the lowest rank will be removed to add space for the new shortcut.
+     *
+     * <p>If the rank of the shortcut is not explicitly set, it will be set to zero, and shortcut
+     * will be added to the top of the list.
+     *
+     * @throws IllegalArgumentException if trying to update an immutable shortcut.
+     *
+     * @throws IllegalStateException when the user is locked.
+     */
+    public void pushDynamicShortcut(@NonNull ShortcutInfo shortcut) {
+        try {
+            mService.pushDynamicShortcut(mContext.getPackageName(), shortcut, injectMyUserId());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
 }
diff --git a/core/java/android/content/pm/ShortcutServiceInternal.java b/core/java/android/content/pm/ShortcutServiceInternal.java
index 3a93421..a50ce92 100644
--- a/core/java/android/content/pm/ShortcutServiceInternal.java
+++ b/core/java/android/content/pm/ShortcutServiceInternal.java
@@ -65,6 +65,9 @@
 
     public abstract void addListener(@NonNull ShortcutChangeListener listener);
 
+    public abstract void addShortcutChangeCallback(
+            @NonNull LauncherApps.ShortcutChangeCallback callback);
+
     public abstract int getShortcutIconResId(int launcherUserId, @NonNull String callingPackage,
             @NonNull String packageName, @NonNull String shortcutId, int userId);
 
diff --git a/core/java/android/content/pm/dex/DexMetadataHelper.java b/core/java/android/content/pm/dex/DexMetadataHelper.java
index 4cd201f..cdb1d22 100644
--- a/core/java/android/content/pm/dex/DexMetadataHelper.java
+++ b/core/java/android/content/pm/dex/DexMetadataHelper.java
@@ -22,7 +22,6 @@
 import android.content.pm.PackageParser;
 import android.content.pm.PackageParser.PackageLite;
 import android.content.pm.PackageParser.PackageParserException;
-import android.content.pm.parsing.AndroidPackage;
 import android.util.ArrayMap;
 import android.util.jar.StrictJarFile;
 
@@ -87,16 +86,6 @@
      *
      * NOTE: involves I/O checks.
      */
-    public static Map<String, String> getPackageDexMetadata(AndroidPackage pkg) {
-        return buildPackageApkToDexMetadataMap(pkg.makeListAllCodePaths());
-    }
-
-    /**
-     * Return the dex metadata files for the given package as a map
-     * [code path -> dex metadata path].
-     *
-     * NOTE: involves I/O checks.
-     */
     private static Map<String, String> getPackageDexMetadata(PackageLite pkg) {
         return buildPackageApkToDexMetadataMap(pkg.getAllCodePaths());
     }
@@ -114,7 +103,7 @@
      * This should only be used for code paths extracted from a package structure after the naming
      * was enforced in the installer.
      */
-    private static Map<String, String> buildPackageApkToDexMetadataMap(
+    public static Map<String, String> buildPackageApkToDexMetadataMap(
             List<String> codePaths) {
         ArrayMap<String, String> result = new ArrayMap<>();
         for (int i = codePaths.size() - 1; i >= 0; i--) {
@@ -157,25 +146,12 @@
     }
 
     /**
-     * Validate the dex metadata files installed for the given package.
-     *
-     * @throws PackageParserException in case of errors.
-     */
-    public static void validatePackageDexMetadata(AndroidPackage pkg)
-            throws PackageParserException {
-        Collection<String> apkToDexMetadataList = getPackageDexMetadata(pkg).values();
-        for (String dexMetadata : apkToDexMetadataList) {
-            validateDexMetadataFile(dexMetadata);
-        }
-    }
-
-    /**
      * Validate that the given file is a dex metadata archive.
      * This is just a sanity validation that the file is a zip archive.
      *
      * @throws PackageParserException if the file is not a .dm file.
      */
-    private static void validateDexMetadataFile(String dmaPath) throws PackageParserException {
+    public static void validateDexMetadataFile(String dmaPath) throws PackageParserException {
         StrictJarFile jarFile = null;
         try {
             jarFile = new StrictJarFile(dmaPath, false, false);
diff --git a/core/java/android/content/pm/parsing/AndroidPackage.java b/core/java/android/content/pm/parsing/AndroidPackage.java
deleted file mode 100644
index 2003ce2..0000000
--- a/core/java/android/content/pm/parsing/AndroidPackage.java
+++ /dev/null
@@ -1,497 +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.Intent;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.ConfigurationInfo;
-import android.content.pm.FeatureGroupInfo;
-import android.content.pm.FeatureInfo;
-import android.content.pm.PackageParser;
-import android.content.pm.PackageUserState;
-import android.content.pm.SharedLibraryInfo;
-import android.content.pm.parsing.ComponentParseUtils.ParsedActivity;
-import android.content.pm.parsing.ComponentParseUtils.ParsedActivityIntentInfo;
-import android.content.pm.parsing.ComponentParseUtils.ParsedFeature;
-import android.content.pm.parsing.ComponentParseUtils.ParsedInstrumentation;
-import android.content.pm.parsing.ComponentParseUtils.ParsedPermission;
-import android.content.pm.parsing.ComponentParseUtils.ParsedPermissionGroup;
-import android.content.pm.parsing.ComponentParseUtils.ParsedProvider;
-import android.content.pm.parsing.ComponentParseUtils.ParsedService;
-import android.os.Bundle;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.util.ArrayMap;
-import android.util.ArraySet;
-import android.util.SparseArray;
-
-import java.security.PublicKey;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.UUID;
-
-/**
- * The last state of a package during parsing/install before it is available in
- * {@link com.android.server.pm.PackageManagerService#mPackages}.
- *
- * It is the responsibility of the caller to understand what data is available at what step of the
- * parsing or install process.
- *
- * TODO(b/135203078): Nullability annotations
- * TODO(b/135203078): Remove get/setAppInfo differences
- *
- * @hide
- */
-public interface AndroidPackage extends Parcelable {
-
-    /**
-     * This will eventually be removed. Avoid calling this at all costs.
-     */
-    @Deprecated
-    AndroidPackageWrite mutate();
-
-    boolean canHaveOatDir();
-
-    boolean cantSaveState();
-
-    List<String> getAdoptPermissions();
-
-    List<String> getAllCodePaths();
-
-    List<String> getAllCodePathsExcludingResourceOnly();
-
-    String getAppComponentFactory();
-
-    /**
-     * TODO(b/135203078): Use non-AppInfo method
-     * @deprecated use {@link #getClassLoaderName()}
-     */
-    @Deprecated
-    String getAppInfoClassLoaderName();
-
-    /**
-     * TODO(b/135203078): Use non-AppInfo method
-     * @deprecated use {@link #getCodePath()}
-     */
-    @Deprecated
-    String getAppInfoCodePath();
-
-    /**
-     * TODO(b/135203078): Use non-AppInfo method
-     * @deprecated use {@link #getName()}
-     */
-    @Deprecated
-    String getAppInfoName();
-
-    /**
-     * TODO(b/135203078): Use non-AppInfo method
-     * @deprecated use {@link #getPackageName()}
-     */
-    @Deprecated
-    String getAppInfoPackageName();
-
-    /**
-     * TODO(b/135203078): Use non-AppInfo method
-     * @deprecated use {@link #getProcessName()}
-     */
-    @Deprecated
-    String getAppInfoProcessName();
-
-    /**
-     * TODO(b/135203078): Use non-AppInfo method
-     * @deprecated use {@link #getCodePath()}
-     */
-    @Deprecated
-    String getAppInfoResourcePath();
-
-    Bundle getAppMetaData();
-
-    /**
-     * TODO(b/135203078): Use non-AppInfo method
-     * @deprecated use {@link #getVolumeUuid()}
-     */
-    @Deprecated
-    String getApplicationInfoVolumeUuid();
-
-    String getBackupAgentName();
-
-    int getBanner();
-
-    String getBaseCodePath();
-
-    int getBaseRevisionCode();
-
-    int getCategory();
-
-    String getClassLoaderName();
-
-    String getClassName();
-
-    String getCodePath();
-
-    int getCompatibleWidthLimitDp();
-
-    int getCompileSdkVersion();
-
-    String getCompileSdkVersionCodeName();
-
-    @Nullable
-    List<ConfigurationInfo> getConfigPreferences();
-
-    String getCpuAbiOverride();
-
-    String getCredentialProtectedDataDir();
-
-    String getDataDir();
-
-    int getDescriptionRes();
-
-    String getDeviceProtectedDataDir();
-
-    List<FeatureGroupInfo> getFeatureGroups();
-
-    int getFlags();
-
-    int getFullBackupContent();
-
-    int getHiddenApiEnforcementPolicy();
-
-    int getIcon();
-
-    int getIconRes();
-
-    List<String> getImplicitPermissions();
-
-    int getInstallLocation();
-
-    Map<String, ArraySet<PublicKey>> getKeySetMapping();
-
-    int getLabelRes();
-
-    int getLargestWidthLimitDp();
-
-    long[] getLastPackageUsageTimeInMills();
-
-    long getLatestForegroundPackageUseTimeInMills();
-
-    long getLatestPackageUseTimeInMills();
-
-    List<String> getLibraryNames();
-
-    int getLogo();
-
-    long getLongVersionCode();
-
-    String getManageSpaceActivityName();
-
-    String getManifestPackageName();
-
-    float getMaxAspectRatio();
-
-    Bundle getMetaData(); // TODO(b/135203078): Make all the Bundles immutable
-
-    @Nullable
-    Set<String> getMimeGroups();
-
-    float getMinAspectRatio();
-
-    int getMinSdkVersion();
-
-    String getName();
-
-    String getNativeLibraryDir();
-
-    String getNativeLibraryRootDir();
-
-    int getNetworkSecurityConfigRes();
-
-    CharSequence getNonLocalizedLabel();
-
-    @Nullable
-    List<String> getOriginalPackages();
-
-    String getOverlayCategory();
-
-    int getOverlayPriority();
-
-    String getOverlayTarget();
-
-    String getOverlayTargetName();
-
-    /**
-     * Map of overlayable name to actor name.
-     */
-    Map<String, String> getOverlayables();
-
-    // TODO(b/135203078): Does this and getAppInfoPackageName have to be separate methods?
-    //  The refactor makes them the same value with no known consequences, so should be redundant.
-    String getPackageName();
-
-    @Nullable
-    List<ParsedActivity> getActivities();
-
-    @Nullable
-    List<ParsedInstrumentation> getInstrumentations();
-
-    @Nullable
-    List<ParsedFeature> getFeatures();
-
-    @Nullable
-    List<ParsedPermissionGroup> getPermissionGroups();
-
-    @Nullable
-    List<ParsedPermission> getPermissions();
-
-    @Nullable
-    List<ParsedProvider> getProviders();
-
-    @Nullable
-    List<ParsedActivity> getReceivers();
-
-    @Nullable
-    List<ParsedService> getServices();
-
-    String getPermission();
-
-    @Nullable
-    List<ParsedActivityIntentInfo> getPreferredActivityFilters();
-
-    int getPreferredOrder();
-
-    String getPrimaryCpuAbi();
-
-    int getPrivateFlags();
-
-    String getProcessName();
-
-    @Nullable
-    List<String> getProtectedBroadcasts();
-
-    String getPublicSourceDir();
-
-    List<Intent> getQueriesIntents();
-
-    List<String> getQueriesPackages();
-
-    Set<String> getQueriesProviders();
-
-    String getRealPackage();
-
-    // TODO(b/135203078): Rename to getRequiredFeatures? Somewhat ambiguous whether "Req" is
-    //  required or requested.
-    @Nullable
-    List<FeatureInfo> getReqFeatures();
-
-    List<String> getRequestedPermissions();
-
-    String getRequiredAccountType();
-
-    int getRequiresSmallestWidthDp();
-
-    byte[] getRestrictUpdateHash();
-
-    String getRestrictedAccountType();
-
-    int getRoundIconRes();
-
-    String getScanPublicSourceDir();
-
-    String getScanSourceDir();
-
-    String getSeInfo();
-
-    String getSeInfoUser();
-
-    String getSecondaryCpuAbi();
-
-    String getSecondaryNativeLibraryDir();
-
-    String getSharedUserId();
-
-    int getSharedUserLabel();
-
-    PackageParser.SigningDetails getSigningDetails();
-
-    String[] getSplitClassLoaderNames();
-
-    @Nullable
-    String[] getSplitCodePaths();
-
-    @Nullable
-    SparseArray<int[]> getSplitDependencies();
-
-    int[] getSplitFlags();
-
-    String[] getSplitNames();
-
-    String[] getSplitPublicSourceDirs();
-
-    int[] getSplitRevisionCodes();
-
-    String getStaticSharedLibName();
-
-    long getStaticSharedLibVersion();
-
-    // TODO(b/135203078): Return String directly
-    UUID getStorageUuid();
-
-    int getTargetSandboxVersion();
-
-    int getTargetSdkVersion();
-
-    String getTaskAffinity();
-
-    int getTheme();
-
-    int getUiOptions();
-
-    int getUid();
-
-    Set<String> getUpgradeKeySets();
-
-    @Nullable
-    List<String> getUsesLibraries();
-
-    @Nullable
-    String[] getUsesLibraryFiles();
-
-    List<SharedLibraryInfo> getUsesLibraryInfos();
-
-    @Nullable
-    List<String> getUsesOptionalLibraries();
-
-    @Nullable
-    List<String> getUsesStaticLibraries();
-
-    @Nullable
-    String[][] getUsesStaticLibrariesCertDigests();
-
-    @Nullable
-    long[] getUsesStaticLibrariesVersions();
-
-    @Nullable
-    ArrayMap<String, ComponentParseUtils.ParsedProcess> getProcesses();
-
-    int getVersionCode();
-
-    int getVersionCodeMajor();
-
-    String getVersionName();
-
-    String getVolumeUuid();
-
-    String getZygotePreloadName();
-
-    boolean hasComponentClassName(String className);
-
-    boolean hasPreserveLegacyExternalStorage();
-
-    // App Info
-
-    boolean hasRequestedLegacyExternalStorage();
-
-    boolean isBaseHardwareAccelerated();
-
-    boolean isCoreApp();
-
-    boolean isDefaultToDeviceProtectedStorage();
-
-    boolean isDirectBootAware();
-
-    boolean isEmbeddedDexUsed();
-
-    boolean isEnabled();
-
-    boolean isCrossProfile();
-
-    boolean isEncryptionAware();
-
-    boolean isExternal();
-
-    boolean isForceQueryable();
-
-    boolean isForwardLocked();
-
-    boolean isHiddenUntilInstalled();
-
-    boolean isInstantApp();
-
-    boolean isInternal();
-
-    boolean isLibrary();
-
-    // TODO(b/135203078): Should probably be in a utility class
-    boolean isMatch(int flags);
-
-    boolean isNativeLibraryRootRequiresIsa();
-
-    boolean isOem();
-
-    boolean isOverlayIsStatic();
-
-    boolean isPrivileged();
-
-    boolean isProduct();
-
-    boolean isProfileableByShell();
-
-    boolean isRequiredForAllUsers();
-
-    boolean isStaticSharedLibrary();
-
-    boolean isStub();
-
-    boolean isSystem(); // TODO(b/135203078): Collapse with isSystemApp, should be exactly the same.
-
-    boolean isSystemApp();
-
-    boolean isSystemExt();
-
-    boolean isUpdatedSystemApp();
-
-    boolean isUse32BitAbi();
-
-    boolean isVendor();
-
-    boolean isVisibleToInstantApps();
-
-    List<String> makeListAllCodePaths(); // TODO(b/135203078): Collapse with getAllCodePaths
-
-    boolean requestsIsolatedSplitLoading();
-
-    /**
-     * Generates an {@link ApplicationInfo} object with only the data available in this object.
-     *
-     * This does not contain any system or user state data, and should be avoided. Prefer
-     * {@link PackageInfoUtils#generateApplicationInfo(AndroidPackage, int, PackageUserState, int)}.
-     */
-    ApplicationInfo toAppInfoWithoutState();
-
-    Creator<PackageImpl> CREATOR = new Creator<PackageImpl>() {
-        @Override
-        public PackageImpl createFromParcel(Parcel source) {
-            return new PackageImpl(source);
-        }
-
-        @Override
-        public PackageImpl[] newArray(int size) {
-            return new PackageImpl[size];
-        }
-    };
-}
diff --git a/core/java/android/content/pm/parsing/AndroidPackageWrite.java b/core/java/android/content/pm/parsing/AndroidPackageWrite.java
deleted file mode 100644
index b7595d2..0000000
--- a/core/java/android/content/pm/parsing/AndroidPackageWrite.java
+++ /dev/null
@@ -1,59 +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.PackageParser;
-import android.content.pm.SharedLibraryInfo;
-
-import java.util.List;
-
-/**
- * Contains remaining mutable fields after package parsing has completed.
- *
- * Most are state that can probably be tracked outside of the AndroidPackage object. New methods
- * should never be added to this interface.
- *
- * TODO(b/135203078): Remove entirely
- *
- * @deprecated the eventual goal is that the object returned from parsing represents exactly what
- * was parsed from the APK, and so further mutation should be disallowed,
- * with any state being stored in another class
- *
- * @hide
- */
-@Deprecated
-public interface AndroidPackageWrite extends AndroidPackage {
-
-    AndroidPackageWrite setUsesLibraryFiles(@Nullable String[] usesLibraryFiles);
-
-    // TODO(b/135203078): Remove or use a non-system wide representation of the shared libraries;
-    //  this doesn't represent what was parsed from the APK
-    AndroidPackageWrite setUsesLibraryInfos(@Nullable List<SharedLibraryInfo> usesLibraryInfos);
-
-    AndroidPackageWrite setHiddenUntilInstalled(boolean hidden);
-
-    AndroidPackageWrite setUpdatedSystemApp(boolean updatedSystemApp);
-
-    AndroidPackageWrite setLastPackageUsageTimeInMills(int reason, long time);
-
-    AndroidPackageWrite setPrimaryCpuAbi(String primaryCpuAbi);
-
-    AndroidPackageWrite setSeInfo(String seInfo);
-
-    AndroidPackageWrite setSigningDetails(PackageParser.SigningDetails signingDetails);
-}
diff --git a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
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/ApkParseUtils.java b/core/java/android/content/pm/parsing/ApkParseUtils.java
deleted file mode 100644
index 905794b..0000000
--- a/core/java/android/content/pm/parsing/ApkParseUtils.java
+++ /dev/null
@@ -1,3349 +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 static android.content.pm.ActivityInfo.FLAG_SUPPORTS_PICTURE_IN_PICTURE;
-import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE;
-import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
-import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
-import static android.content.pm.PackageManager.FEATURE_WATCH;
-import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST;
-import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
-import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
-import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NOT_APK;
-import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION;
-import static android.os.Build.VERSION_CODES.O;
-import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
-import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_UNSPECIFIED;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.app.ActivityTaskManager;
-import android.app.ActivityThread;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.ActivityInfo;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.ConfigurationInfo;
-import android.content.pm.FeatureGroupInfo;
-import android.content.pm.FeatureInfo;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageItemInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageParser;
-import android.content.pm.PackageParser.PackageParserException;
-import android.content.pm.PackageParser.SigningDetails;
-import android.content.pm.Signature;
-import android.content.pm.permission.SplitPermissionInfoParcelable;
-import android.content.pm.split.DefaultSplitAssetLoader;
-import android.content.pm.split.SplitAssetDependencyLoader;
-import android.content.pm.split.SplitAssetLoader;
-import android.content.res.ApkAssets;
-import android.content.res.AssetManager;
-import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.content.res.TypedArray;
-import android.content.res.XmlResourceParser;
-import android.net.Uri;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.FileUtils;
-import android.os.RemoteException;
-import android.os.SystemProperties;
-import android.os.Trace;
-import android.os.ext.SdkExtensions;
-import android.text.TextUtils;
-import android.util.ArrayMap;
-import android.util.ArraySet;
-import android.util.AttributeSet;
-import android.util.DisplayMetrics;
-import android.util.Pair;
-import android.util.Slog;
-import android.util.SparseArray;
-import android.util.TypedValue;
-import android.util.apk.ApkSignatureVerifier;
-
-import com.android.internal.R;
-import com.android.internal.os.ClassLoaderFactory;
-import com.android.internal.util.ArrayUtils;
-import com.android.internal.util.XmlUtils;
-
-import libcore.io.IoUtils;
-import libcore.util.EmptyArray;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
-import java.io.File;
-import java.io.IOException;
-import java.security.PublicKey;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.StringTokenizer;
-
-/** @hide */
-public class ApkParseUtils {
-
-    // TODO(b/135203078): Consolidate log tags
-    static final String TAG = "PackageParsing";
-
-    /**
-     * Parse the package at the given location. Automatically detects if the
-     * package is a monolithic style (single APK file) or cluster style
-     * (directory of APKs).
-     * <p>
-     * This performs sanity checking on cluster style packages, such as
-     * requiring identical package name and version codes, a single base APK,
-     * and unique split names.
-     * <p>
-     * Note that this <em>does not</em> perform signature verification; that
-     * must be done separately in {@link #collectCertificates(ParsedPackage, boolean)}.
-     *
-     * If {@code useCaches} is true, the package parser might return a cached
-     * result from a previous parse of the same {@code packageFile} with the same
-     * {@code flags}. Note that this method does not check whether {@code packageFile}
-     * has changed since the last parse, it's up to callers to do so.
-     *
-     * @see PackageParser#parsePackageLite(File, int)
-     */
-    public static ParsingPackage parsePackage(
-            ParseInput parseInput,
-            String[] separateProcesses,
-            PackageParser.Callback callback,
-            DisplayMetrics displayMetrics,
-            boolean onlyCoreApps,
-            File packageFile,
-            int flags
-    ) throws PackageParserException {
-        if (packageFile.isDirectory()) {
-            return parseClusterPackage(parseInput, separateProcesses, callback, displayMetrics,
-                    onlyCoreApps, packageFile, flags);
-        } else {
-            return parseMonolithicPackage(parseInput, separateProcesses, callback, displayMetrics,
-                    onlyCoreApps, packageFile, flags);
-        }
-    }
-
-    /**
-     * Parse all APKs contained in the given directory, treating them as a
-     * single package. This also performs sanity checking, such as requiring
-     * identical package name and version codes, a single base APK, and unique
-     * split names.
-     * <p>
-     * Note that this <em>does not</em> perform signature verification; that
-     * must be done separately in {@link #collectCertificates(ParsedPackage, boolean)}.
-     */
-    private static ParsingPackage parseClusterPackage(
-            ParseInput parseInput,
-            String[] separateProcesses,
-            PackageParser.Callback callback,
-            DisplayMetrics displayMetrics,
-            boolean onlyCoreApps,
-            File packageDir,
-            int flags
-    ) throws PackageParserException {
-        final PackageParser.PackageLite lite = ApkLiteParseUtils.parseClusterPackageLite(packageDir,
-                0);
-        if (onlyCoreApps && !lite.coreApp) {
-            throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
-                    "Not a coreApp: " + packageDir);
-        }
-
-        // Build the split dependency tree.
-        SparseArray<int[]> splitDependencies = null;
-        final SplitAssetLoader assetLoader;
-        if (lite.isolatedSplits && !ArrayUtils.isEmpty(lite.splitNames)) {
-            try {
-                splitDependencies = SplitAssetDependencyLoader.createDependenciesFromPackage(lite);
-                assetLoader = new SplitAssetDependencyLoader(lite, splitDependencies, flags);
-            } catch (SplitAssetDependencyLoader.IllegalDependencyException e) {
-                throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST, e.getMessage());
-            }
-        } else {
-            assetLoader = new DefaultSplitAssetLoader(lite, flags);
-        }
-
-        try {
-            final AssetManager assets = assetLoader.getBaseAssetManager();
-            final File baseApk = new File(lite.baseCodePath);
-            ParsingPackage parsingPackage = parseBaseApk(parseInput, separateProcesses, callback,
-                    displayMetrics, baseApk, assets, flags);
-            if (parsingPackage == null) {
-                throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
-                        "Failed to parse base APK: " + baseApk);
-            }
-
-            if (!ArrayUtils.isEmpty(lite.splitNames)) {
-                parsingPackage.asSplit(
-                        lite.splitNames,
-                        lite.splitCodePaths,
-                        lite.splitRevisionCodes,
-                        splitDependencies
-                );
-                final int num = lite.splitNames.length;
-
-                for (int i = 0; i < num; i++) {
-                    final AssetManager splitAssets = assetLoader.getSplitAssetManager(i);
-                    parseSplitApk(parseInput, displayMetrics, separateProcesses, parsingPackage, i,
-                            splitAssets, flags);
-                }
-            }
-
-            return parsingPackage.setCodePath(lite.codePath)
-                    .setUse32BitAbi(lite.use32bitAbi);
-        } finally {
-            IoUtils.closeQuietly(assetLoader);
-        }
-    }
-
-    /**
-     * Parse the given APK file, treating it as as a single monolithic package.
-     * <p>
-     * Note that this <em>does not</em> perform signature verification; that
-     * must be done separately in {@link #collectCertificates(AndroidPackage, boolean)}.
-     */
-    public static ParsingPackage parseMonolithicPackage(
-            ParseInput parseInput,
-            String[] separateProcesses,
-            PackageParser.Callback callback,
-            DisplayMetrics displayMetrics,
-            boolean onlyCoreApps,
-            File apkFile,
-            int flags
-    ) throws PackageParserException {
-        final PackageParser.PackageLite lite = ApkLiteParseUtils.parseMonolithicPackageLite(apkFile,
-                flags);
-        if (onlyCoreApps) {
-            if (!lite.coreApp) {
-                throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
-                        "Not a coreApp: " + apkFile);
-            }
-        }
-
-        final SplitAssetLoader assetLoader = new DefaultSplitAssetLoader(lite, flags);
-        try {
-            return parseBaseApk(parseInput, separateProcesses, callback,
-                    displayMetrics, apkFile, assetLoader.getBaseAssetManager(), flags)
-                    .setCodePath(apkFile.getCanonicalPath())
-                    .setUse32BitAbi(lite.use32bitAbi);
-        } catch (IOException e) {
-            throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
-                    "Failed to get path: " + apkFile, e);
-        } finally {
-            IoUtils.closeQuietly(assetLoader);
-        }
-    }
-
-    private static ParsingPackage parseBaseApk(
-            ParseInput parseInput,
-            String[] separateProcesses,
-            PackageParser.Callback callback,
-            DisplayMetrics displayMetrics,
-            File apkFile,
-            AssetManager assets,
-            int flags
-    ) throws PackageParserException {
-        final String apkPath = apkFile.getAbsolutePath();
-
-        String volumeUuid = null;
-        if (apkPath.startsWith(PackageParser.MNT_EXPAND)) {
-            final int end = apkPath.indexOf('/', PackageParser.MNT_EXPAND.length());
-            volumeUuid = apkPath.substring(PackageParser.MNT_EXPAND.length(), end);
-        }
-
-        if (PackageParser.DEBUG_JAR) Slog.d(TAG, "Scanning base APK: " + apkPath);
-
-        XmlResourceParser parser = null;
-        try {
-            final int cookie = assets.findCookieForPath(apkPath);
-            if (cookie == 0) {
-                throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,
-                        "Failed adding asset path: " + apkPath);
-            }
-            parser = assets.openXmlResourceParser(cookie, PackageParser.ANDROID_MANIFEST_FILENAME);
-            final Resources res = new Resources(assets, displayMetrics, null);
-
-            ParseResult result = parseBaseApk(parseInput, separateProcesses, callback, apkPath, res,
-                    parser, flags);
-            if (!result.isSuccess()) {
-                throw new PackageParserException(result.getParseError(),
-                        apkPath + " (at " + parser.getPositionDescription() + "): "
-                                + result.getErrorMessage());
-            }
-
-            ParsingPackage pkg = result.getResultAndNull();
-            ApkAssets apkAssets = assets.getApkAssets()[0];
-            if (apkAssets.definesOverlayable()) {
-                SparseArray<String> packageNames = assets.getAssignedPackageIdentifiers();
-                int size = packageNames.size();
-                for (int index = 0; index < size; index++) {
-                    String packageName = packageNames.get(index);
-                    Map<String, String> overlayableToActor = assets.getOverlayableMap(packageName);
-                    if (overlayableToActor != null && !overlayableToActor.isEmpty()) {
-                        for (String overlayable : overlayableToActor.keySet()) {
-                            pkg.addOverlayable(overlayable, overlayableToActor.get(overlayable));
-                        }
-                    }
-                }
-            }
-
-            return pkg.setVolumeUuid(volumeUuid)
-                    .setApplicationVolumeUuid(volumeUuid)
-                    .setSigningDetails(SigningDetails.UNKNOWN);
-        } catch (PackageParserException e) {
-            throw e;
-        } catch (Exception e) {
-            throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
-                    "Failed to read manifest from " + apkPath, e);
-        } finally {
-            IoUtils.closeQuietly(parser);
-        }
-    }
-
-    private static void parseSplitApk(
-            ParseInput parseInput,
-            DisplayMetrics displayMetrics,
-            String[] separateProcesses,
-            ParsingPackage parsingPackage,
-            int splitIndex,
-            AssetManager assets,
-            int flags
-    ) throws PackageParserException {
-        final String apkPath = parsingPackage.getSplitCodePaths()[splitIndex];
-
-        if (PackageParser.DEBUG_JAR) Slog.d(TAG, "Scanning split APK: " + apkPath);
-
-        final Resources res;
-        XmlResourceParser parser = null;
-        try {
-            // This must always succeed, as the path has been added to the AssetManager before.
-            final int cookie = assets.findCookieForPath(apkPath);
-            if (cookie == 0) {
-                throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,
-                        "Failed adding asset path: " + apkPath);
-            }
-
-            parser = assets.openXmlResourceParser(cookie, PackageParser.ANDROID_MANIFEST_FILENAME);
-            res = new Resources(assets, displayMetrics, null);
-
-            final String[] outError = new String[1];
-            ParseResult parseResult = parseSplitApk(parseInput, separateProcesses, parsingPackage,
-                    res, parser, flags, splitIndex, outError);
-            if (!parseResult.isSuccess()) {
-                throw new PackageParserException(parseResult.getParseError(),
-                        apkPath + " (at " + parser.getPositionDescription() + "): "
-                                + parseResult.getErrorMessage());
-            }
-        } catch (PackageParserException e) {
-            throw e;
-        } catch (Exception e) {
-            throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
-                    "Failed to read manifest from " + apkPath, e);
-        } finally {
-            IoUtils.closeQuietly(parser);
-        }
-    }
-
-    /**
-     * Parse the manifest of a <em>base APK</em>. When adding new features you
-     * need to consider whether they should be supported by split APKs and child
-     * packages.
-     *
-     * @param apkPath  The package apk file path
-     * @param res      The resources from which to resolve values
-     * @param parser   The manifest parser
-     * @param flags    Flags how to parse
-     * @return Parsed package or null on error.
-     */
-    private static ParseResult parseBaseApk(
-            ParseInput parseInput,
-            String[] separateProcesses,
-            PackageParser.Callback callback,
-            String apkPath,
-            Resources res,
-            XmlResourceParser parser,
-            int flags
-    ) throws XmlPullParserException, IOException {
-        final String splitName;
-        final String pkgName;
-
-        try {
-            Pair<String, String> packageSplit = PackageParser.parsePackageSplitNames(parser,
-                    parser);
-            pkgName = packageSplit.first;
-            splitName = packageSplit.second;
-
-            if (!TextUtils.isEmpty(splitName)) {
-                return parseInput.error(
-                        PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,
-                        "Expected base APK, but found split " + splitName
-                );
-            }
-        } catch (PackageParserException e) {
-            return parseInput.error(PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME);
-        }
-
-        TypedArray manifestArray = null;
-
-        try {
-            manifestArray = res.obtainAttributes(parser, R.styleable.AndroidManifest);
-
-            boolean isCoreApp = parser.getAttributeBooleanValue(null, "coreApp", false);
-
-            ParsingPackage parsingPackage = PackageImpl.forParsing(
-                    pkgName,
-                    apkPath,
-                    manifestArray,
-                    isCoreApp
-            );
-
-            ParseResult result = parseBaseApkTags(parseInput, separateProcesses, callback,
-                    parsingPackage, manifestArray, res, parser, flags);
-            if (!result.isSuccess()) {
-                return result;
-            }
-
-            return parseInput.success(parsingPackage);
-        } finally {
-            if (manifestArray != null) {
-                manifestArray.recycle();
-            }
-        }
-    }
-
-    /**
-     * Parse the manifest of a <em>split APK</em>.
-     * <p>
-     * Note that split APKs have many more restrictions on what they're capable
-     * of doing, so many valid features of a base APK have been carefully
-     * omitted here.
-     *
-     * @param parsingPackage builder to fill
-     * @return false on failure
-     */
-    private static ParseResult parseSplitApk(
-            ParseInput parseInput,
-            String[] separateProcesses,
-            ParsingPackage parsingPackage,
-            Resources res,
-            XmlResourceParser parser,
-            int flags,
-            int splitIndex,
-            String[] outError
-    ) throws XmlPullParserException, IOException, PackageParserException {
-        AttributeSet attrs = parser;
-
-        // We parsed manifest tag earlier; just skip past it
-        PackageParser.parsePackageSplitNames(parser, attrs);
-
-        int type;
-
-        boolean foundApp = false;
-
-        int outerDepth = parser.getDepth();
-        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
-                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
-            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
-                continue;
-            }
-
-            String tagName = parser.getName();
-            if (tagName.equals(PackageParser.TAG_APPLICATION)) {
-                if (foundApp) {
-                    if (PackageParser.RIGID_PARSER) {
-                        return parseInput.error(
-                                PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
-                                "<manifest> has more than one <application>"
-                        );
-                    } else {
-                        Slog.w(TAG, "<manifest> has more than one <application>");
-                        XmlUtils.skipCurrentTag(parser);
-                        continue;
-                    }
-                }
-
-                foundApp = true;
-                ParseResult parseResult = parseSplitApplication(parseInput, separateProcesses,
-                        parsingPackage, res,
-                        parser, flags,
-                        splitIndex, outError);
-                if (!parseResult.isSuccess()) {
-                    return parseResult;
-                }
-
-            } else if (PackageParser.RIGID_PARSER) {
-                return parseInput.error(
-                        PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
-                        "Bad element under <manifest>: " + parser.getName()
-                );
-
-            } else {
-                Slog.w(TAG, "Unknown element under <manifest>: " + parser.getName()
-                        + " at " + parsingPackage.getBaseCodePath() + " "
-                        + parser.getPositionDescription());
-                XmlUtils.skipCurrentTag(parser);
-                continue;
-            }
-        }
-
-        if (!foundApp) {
-            return parseInput.error(
-                    PackageManager.INSTALL_PARSE_FAILED_MANIFEST_EMPTY,
-                    "<manifest> does not contain an <application>"
-            );
-        }
-
-        return parseInput.success(parsingPackage);
-    }
-
-    /**
-     * Parse the {@code application} XML tree at the current parse location in a
-     * <em>split APK</em> manifest.
-     * <p>
-     * Note that split APKs have many more restrictions on what they're capable
-     * of doing, so many valid features of a base APK have been carefully
-     * omitted here.
-     */
-    private static ParseResult parseSplitApplication(
-            ParseInput parseInput,
-            String[] separateProcesses,
-            ParsingPackage parsingPackage,
-            Resources res,
-            XmlResourceParser parser,
-            int flags,
-            int splitIndex,
-            String[] outError
-    ) throws XmlPullParserException, IOException {
-        TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestApplication);
-
-        parsingPackage.setSplitHasCode(splitIndex, sa.getBoolean(
-                R.styleable.AndroidManifestApplication_hasCode, true));
-
-        final String classLoaderName = sa.getString(
-                R.styleable.AndroidManifestApplication_classLoader);
-        if (classLoaderName == null || ClassLoaderFactory.isValidClassLoaderName(classLoaderName)) {
-            parsingPackage.setSplitClassLoaderName(splitIndex, classLoaderName);
-        } else {
-            return parseInput.error(
-                    PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
-                    "Invalid class loader name: " + classLoaderName
-            );
-        }
-
-        final int innerDepth = parser.getDepth();
-        int type;
-        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
-                && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
-            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
-                continue;
-            }
-
-            ComponentParseUtils.ParsedComponent parsedComponent = null;
-
-            String tagName = parser.getName();
-            switch (tagName) {
-                case "activity":
-                    ComponentParseUtils.ParsedActivity activity =
-                            ComponentParseUtils.parseActivity(separateProcesses,
-                                    parsingPackage,
-                                    res, parser, flags,
-                                    outError,
-                                    false,
-                                    parsingPackage.isBaseHardwareAccelerated());
-                    if (activity == null) {
-                        return parseInput.error(
-                                PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
-                                outError[0]
-                        );
-                    }
-
-                    parsingPackage.addActivity(activity);
-                    parsedComponent = activity;
-                    break;
-                case "receiver":
-                    activity = ComponentParseUtils.parseActivity(
-                            separateProcesses, parsingPackage,
-                            res, parser, flags, outError,
-                            true, false);
-                    if (activity == null) {
-                        return parseInput.error(
-                                PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
-                                outError[0]
-                        );
-                    }
-
-                    parsingPackage.addReceiver(activity);
-                    parsedComponent = activity;
-                    break;
-                case "service":
-                    ComponentParseUtils.ParsedService s = ComponentParseUtils.parseService(
-                            separateProcesses,
-                            parsingPackage,
-                            res, parser, flags, outError
-                    );
-                    if (s == null) {
-                        return parseInput.error(
-                                PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
-                                outError[0]
-                        );
-                    }
-
-                    parsingPackage.addService(s);
-                    parsedComponent = s;
-                    break;
-                case "provider":
-                    ComponentParseUtils.ParsedProvider p = ComponentParseUtils.parseProvider(
-                            separateProcesses,
-                            parsingPackage,
-                            res, parser, flags, outError);
-                    if (p == null) {
-                        return parseInput.error(
-                                PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
-                                outError[0]
-                        );
-                    }
-
-                    parsingPackage.addProvider(p);
-                    parsedComponent = p;
-                    break;
-                case "activity-alias":
-                    activity = ComponentParseUtils.parseActivityAlias(
-                            parsingPackage,
-                            res,
-                            parser,
-                            outError
-                    );
-                    if (activity == null) {
-                        return parseInput.error(
-                                PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
-                                outError[0]
-                        );
-                    }
-
-                    parsingPackage.addActivity(activity);
-                    parsedComponent = activity;
-                    break;
-                case "meta-data":
-                    // note: application meta-data is stored off to the side, so it can
-                    // remain null in the primary copy (we like to avoid extra copies because
-                    // it can be large)
-                    Bundle appMetaData = parseMetaData(parsingPackage, res, parser,
-                            parsingPackage.getAppMetaData(),
-                            outError);
-                    if (appMetaData == null) {
-                        return parseInput.error(
-                                PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
-                                outError[0]
-                        );
-                    }
-
-                    parsingPackage.setAppMetaData(appMetaData);
-                    break;
-                case "uses-static-library":
-                    ParseResult parseResult = parseUsesStaticLibrary(parseInput, parsingPackage,
-                            res, parser);
-                    if (!parseResult.isSuccess()) {
-                        return parseResult;
-                    }
-
-                    break;
-                case "uses-library":
-                    sa = res.obtainAttributes(parser, R.styleable.AndroidManifestUsesLibrary);
-
-                    // Note: don't allow this value to be a reference to a resource
-                    // that may change.
-                    String lname = sa.getNonResourceString(
-                            R.styleable.AndroidManifestUsesLibrary_name);
-                    boolean req = sa.getBoolean(
-                            R.styleable.AndroidManifestUsesLibrary_required, true);
-
-                    sa.recycle();
-
-                    if (lname != null) {
-                        lname = lname.intern();
-                        if (req) {
-                            // Upgrade to treat as stronger constraint
-                            parsingPackage.addUsesLibrary(lname)
-                                    .removeUsesOptionalLibrary(lname);
-                        } else {
-                            // Ignore if someone already defined as required
-                            if (!ArrayUtils.contains(parsingPackage.getUsesLibraries(), lname)) {
-                                parsingPackage.addUsesOptionalLibrary(lname);
-                            }
-                        }
-                    }
-
-                    XmlUtils.skipCurrentTag(parser);
-                    break;
-                case "uses-package":
-                    // Dependencies for app installers; we don't currently try to
-                    // enforce this.
-                    XmlUtils.skipCurrentTag(parser);
-                    break;
-                default:
-                    if (!PackageParser.RIGID_PARSER) {
-                        Slog.w(TAG, "Unknown element under <application>: " + tagName
-                                + " at " + parsingPackage.getBaseCodePath() + " "
-                                + parser.getPositionDescription());
-                        XmlUtils.skipCurrentTag(parser);
-                        continue;
-                    } else {
-                        return parseInput.error(
-                                PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
-                                "Bad element under <application>: " + tagName
-                        );
-                    }
-            }
-
-            if (parsedComponent != null && parsedComponent.getSplitName() == null) {
-                // If the loaded component did not specify a split, inherit the split name
-                // based on the split it is defined in.
-                // This is used to later load the correct split when starting this
-                // component.
-                parsedComponent.setSplitName(parsingPackage.getSplitNames()[splitIndex]);
-            }
-        }
-
-        return parseInput.success(parsingPackage);
-    }
-
-    private static ParseResult parseBaseApkTags(
-            ParseInput parseInput,
-            String[] separateProcesses,
-            PackageParser.Callback callback,
-            ParsingPackage parsingPackage,
-            TypedArray manifestArray,
-            Resources res,
-            XmlResourceParser parser,
-            int flags
-    ) throws XmlPullParserException, IOException {
-        int type;
-        boolean foundApp = false;
-
-        TypedArray sa = manifestArray;
-
-        ParseResult sharedUserResult = parseSharedUser(parseInput, parsingPackage, sa);
-        if (!sharedUserResult.isSuccess()) {
-            return sharedUserResult;
-        }
-
-        parseManifestAttributes(sa, parsingPackage, flags);
-
-        int outerDepth = parser.getDepth();
-        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
-                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
-            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
-                continue;
-            }
-
-            String tagName = parser.getName();
-
-            // All methods return a boolean, even if they can't fail. This can be enforced
-            // by making this final and not assigned, forcing the switch to assign success
-            // once in every branch.
-            final boolean success;
-            ParseResult parseResult = null;
-
-            // TODO(b/135203078): Either use all booleans or all ParseResults
-            // TODO(b/135203078): Convert to instance methods to share variables
-            switch (tagName) {
-                case PackageParser.TAG_APPLICATION:
-                    if (foundApp) {
-                        if (PackageParser.RIGID_PARSER) {
-                            return parseInput.error(
-                                    PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
-                                    "<manifest> has more than one <application>"
-                            );
-                        } else {
-                            Slog.w(TAG, "<manifest> has more than one <application>");
-                            XmlUtils.skipCurrentTag(parser);
-                            success = true;
-                        }
-                    } else {
-                        foundApp = true;
-                        parseResult = parseBaseApplication(parseInput, separateProcesses,
-                                callback,
-                                parsingPackage, res, parser, flags);
-                        success = parseResult.isSuccess();
-                    }
-                    break;
-                case PackageParser.TAG_OVERLAY:
-                    parseResult = parseOverlay(parseInput, parsingPackage, res, parser);
-                    success = parseResult.isSuccess();
-                    break;
-                case PackageParser.TAG_KEY_SETS:
-                    parseResult = parseKeySets(parseInput, parsingPackage, res, parser);
-                    success = parseResult.isSuccess();
-                    break;
-                case PackageParser.TAG_FEATURE:
-                    parseResult = parseFeature(parseInput, parsingPackage, res, parser);
-                    success = parseResult.isSuccess();
-                    break;
-                case PackageParser.TAG_PERMISSION_GROUP:
-                    parseResult = parsePermissionGroup(parseInput, parsingPackage, res,
-                            parser);
-                    success = parseResult.isSuccess();
-                    break;
-                case PackageParser.TAG_PERMISSION:
-                    parseResult = parsePermission(parseInput, parsingPackage, res, parser);
-                    success = parseResult.isSuccess();
-                    break;
-                case PackageParser.TAG_PERMISSION_TREE:
-                    parseResult = parsePermissionTree(parseInput, parsingPackage, res, parser);
-                    success = parseResult.isSuccess();
-                    break;
-                case PackageParser.TAG_USES_PERMISSION:
-                case PackageParser.TAG_USES_PERMISSION_SDK_M:
-                case PackageParser.TAG_USES_PERMISSION_SDK_23:
-                    parseResult = parseUsesPermission(parseInput, parsingPackage, res, parser,
-                            callback);
-                    success = parseResult.isSuccess();
-                    break;
-                case PackageParser.TAG_USES_CONFIGURATION:
-                    success = parseUsesConfiguration(parsingPackage, res, parser);
-                    break;
-                case PackageParser.TAG_USES_FEATURE:
-                    success = parseUsesFeature(parsingPackage, res, parser);
-                    break;
-                case PackageParser.TAG_FEATURE_GROUP:
-                    success = parseFeatureGroup(parsingPackage, res, parser);
-                    break;
-                case PackageParser.TAG_USES_SDK:
-                    parseResult = parseUsesSdk(parseInput, parsingPackage, res, parser);
-                    success = parseResult.isSuccess();
-                    break;
-                case PackageParser.TAG_SUPPORT_SCREENS:
-                    success = parseSupportScreens(parsingPackage, res, parser);
-                    break;
-                case PackageParser.TAG_PROTECTED_BROADCAST:
-                    success = parseProtectedBroadcast(parsingPackage, res, parser);
-                    break;
-                case PackageParser.TAG_INSTRUMENTATION:
-                    parseResult = parseInstrumentation(parseInput, parsingPackage, res,
-                            parser);
-                    success = parseResult.isSuccess();
-                    break;
-                case PackageParser.TAG_ORIGINAL_PACKAGE:
-                    success = parseOriginalPackage(parsingPackage, res, parser);
-                    break;
-                case PackageParser.TAG_ADOPT_PERMISSIONS:
-                    success = parseAdoptPermissions(parsingPackage, res, parser);
-                    break;
-                case PackageParser.TAG_USES_GL_TEXTURE:
-                case PackageParser.TAG_COMPATIBLE_SCREENS:
-                case PackageParser.TAG_SUPPORTS_INPUT:
-                case PackageParser.TAG_EAT_COMMENT:
-                    // Just skip this tag
-                    XmlUtils.skipCurrentTag(parser);
-                    success = true;
-                    break;
-                case PackageParser.TAG_RESTRICT_UPDATE:
-                    success = parseRestrictUpdateHash(flags, parsingPackage, res, parser);
-                    break;
-                case PackageParser.TAG_QUERIES:
-                    parseResult = parseQueries(parseInput, parsingPackage, res, parser);
-                    success = parseResult.isSuccess();
-                    break;
-                default:
-                    parseResult = parseUnknownTag(parseInput, parsingPackage, parser);
-                    success = parseResult.isSuccess();
-                    break;
-            }
-
-            if (parseResult != null && !parseResult.isSuccess()) {
-                return parseResult;
-            }
-
-            if (!success) {
-                return parseResult;
-            }
-        }
-
-        if (!foundApp && ArrayUtils.size(parsingPackage.getInstrumentations()) == 0) {
-            return parseInput.error(
-                    PackageManager.INSTALL_PARSE_FAILED_MANIFEST_EMPTY,
-                    "<manifest> does not contain an <application> or <instrumentation>"
-            );
-        }
-
-        if (!ComponentParseUtils.ParsedFeature.isCombinationValid(parsingPackage.getFeatures())) {
-            return parseInput.error(
-                    INSTALL_PARSE_FAILED_BAD_MANIFEST,
-                    "Combination <feature> tags are not valid"
-            );
-        }
-
-        convertNewPermissions(parsingPackage);
-
-        convertSplitPermissions(parsingPackage);
-
-        // At this point we can check if an application is not supporting densities and hence
-        // cannot be windowed / resized. Note that an SDK version of 0 is common for
-        // pre-Doughnut applications.
-        if (parsingPackage.usesCompatibilityMode()) {
-            adjustPackageToBeUnresizeableAndUnpipable(parsingPackage);
-        }
-
-        return parseInput.success(parsingPackage);
-    }
-
-    private static ParseResult parseUnknownTag(
-            ParseInput parseInput,
-            ParsingPackage parsingPackage,
-            XmlResourceParser parser
-    ) throws IOException, XmlPullParserException {
-        if (PackageParser.RIGID_PARSER) {
-            return parseInput.error(
-                    PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
-                    "Bad element under <manifest>: " + parser.getName()
-            );
-        } else {
-            Slog.w(TAG, "Unknown element under <manifest>: " + parser.getName()
-                    + " at " + parsingPackage.getBaseCodePath() + " "
-                    + parser.getPositionDescription());
-            XmlUtils.skipCurrentTag(parser);
-            return parseInput.success(parsingPackage);
-        }
-    }
-
-    private static ParseResult parseSharedUser(
-            ParseInput parseInput,
-            ParsingPackage parsingPackage,
-            TypedArray manifestArray
-    ) {
-        String str = manifestArray.getNonConfigurationString(
-                R.styleable.AndroidManifest_sharedUserId, 0);
-        if (TextUtils.isEmpty(str)) {
-            return parseInput.success(parsingPackage);
-        }
-
-        String nameError = validateName(str, true, true);
-        if (nameError != null && !"android".equals(parsingPackage.getPackageName())) {
-            return parseInput.error(
-                    PackageManager.INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID,
-                    "<manifest> specifies bad sharedUserId name \"" + str + "\": "
-                            + nameError
-            );
-        }
-
-        int sharedUserLabel = manifestArray.getResourceId(
-                R.styleable.AndroidManifest_sharedUserLabel, 0);
-        parsingPackage.setSharedUserId(str.intern())
-                .setSharedUserLabel(sharedUserLabel);
-
-        return parseInput.success(parsingPackage);
-    }
-
-    private static void parseManifestAttributes(
-            TypedArray manifestArray,
-            ParsingPackage parsingPackage,
-            int flags
-    ) {
-        int installLocation = manifestArray.getInteger(R.styleable.AndroidManifest_installLocation,
-                PackageParser.PARSE_DEFAULT_INSTALL_LOCATION);
-
-        final int targetSandboxVersion = manifestArray.getInteger(
-                R.styleable.AndroidManifest_targetSandboxVersion,
-                PackageParser.PARSE_DEFAULT_TARGET_SANDBOX);
-
-        parsingPackage.setInstallLocation(installLocation)
-                .setTargetSandboxVersion(targetSandboxVersion);
-
-        /* Set the global "on SD card" flag */
-        parsingPackage.setExternalStorage((flags & PackageParser.PARSE_EXTERNAL_STORAGE) != 0);
-
-        parsingPackage.setIsolatedSplitLoading(manifestArray.getBoolean(
-                R.styleable.AndroidManifest_isolatedSplits, false));
-    }
-
-    private static ParseResult parseKeySets(
-            ParseInput parseInput,
-            ParsingPackage parsingPackage,
-            Resources res,
-            XmlResourceParser parser
-    ) throws XmlPullParserException, IOException {
-        // we've encountered the 'key-sets' tag
-        // all the keys and keysets that we want must be defined here
-        // so we're going to iterate over the parser and pull out the things we want
-        int outerDepth = parser.getDepth();
-        int currentKeySetDepth = -1;
-        int type;
-        String currentKeySet = null;
-        ArrayMap<String, PublicKey> publicKeys = new ArrayMap<>();
-        ArraySet<String> upgradeKeySets = new ArraySet<>();
-        ArrayMap<String, ArraySet<String>> definedKeySets =
-                new ArrayMap<>();
-        ArraySet<String> improperKeySets = new ArraySet<>();
-        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
-                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
-            if (type == XmlPullParser.END_TAG) {
-                if (parser.getDepth() == currentKeySetDepth) {
-                    currentKeySet = null;
-                    currentKeySetDepth = -1;
-                }
-                continue;
-            }
-            String tagName = parser.getName();
-            if (tagName.equals("key-set")) {
-                if (currentKeySet != null) {
-                    return parseInput.error(
-                            PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
-                            "Improperly nested 'key-set' tag at " + parser.getPositionDescription()
-                    );
-                }
-                final TypedArray sa = res.obtainAttributes(parser,
-                        R.styleable.AndroidManifestKeySet);
-                final String keysetName = sa.getNonResourceString(
-                        R.styleable.AndroidManifestKeySet_name);
-                definedKeySets.put(keysetName, new ArraySet<>());
-                currentKeySet = keysetName;
-                currentKeySetDepth = parser.getDepth();
-                sa.recycle();
-            } else if (tagName.equals("public-key")) {
-                if (currentKeySet == null) {
-                    return parseInput.error(
-                            PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
-                            "Improperly nested 'key-set' tag at " + parser.getPositionDescription()
-                    );
-                }
-                final TypedArray sa = res.obtainAttributes(parser,
-                        R.styleable.AndroidManifestPublicKey);
-                final String publicKeyName = sa.getNonResourceString(
-                        R.styleable.AndroidManifestPublicKey_name);
-                final String encodedKey = sa.getNonResourceString(
-                        R.styleable.AndroidManifestPublicKey_value);
-                if (encodedKey == null && publicKeys.get(publicKeyName) == null) {
-                    sa.recycle();
-                    return parseInput.error(
-                            PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
-                            "'public-key' " + publicKeyName + " must define a public-key value"
-                                    + " on first use at " + parser.getPositionDescription()
-                    );
-                } else if (encodedKey != null) {
-                    PublicKey currentKey = PackageParser.parsePublicKey(encodedKey);
-                    if (currentKey == null) {
-                        Slog.w(TAG, "No recognized valid key in 'public-key' tag at "
-                                + parser.getPositionDescription() + " key-set " + currentKeySet
-                                + " will not be added to the package's defined key-sets.");
-                        sa.recycle();
-                        improperKeySets.add(currentKeySet);
-                        XmlUtils.skipCurrentTag(parser);
-                        continue;
-                    }
-                    if (publicKeys.get(publicKeyName) == null
-                            || publicKeys.get(publicKeyName).equals(currentKey)) {
-
-                        /* public-key first definition, or matches old definition */
-                        publicKeys.put(publicKeyName, currentKey);
-                    } else {
-                        sa.recycle();
-                        return parseInput.error(
-                                PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
-                                "Value of 'public-key' " + publicKeyName
-                                        + " conflicts with previously defined value at "
-                                        + parser.getPositionDescription()
-                        );
-                    }
-                }
-                definedKeySets.get(currentKeySet).add(publicKeyName);
-                sa.recycle();
-                XmlUtils.skipCurrentTag(parser);
-            } else if (tagName.equals("upgrade-key-set")) {
-                final TypedArray sa = res.obtainAttributes(parser,
-                        R.styleable.AndroidManifestUpgradeKeySet);
-                String name = sa.getNonResourceString(
-                        R.styleable.AndroidManifestUpgradeKeySet_name);
-                upgradeKeySets.add(name);
-                sa.recycle();
-                XmlUtils.skipCurrentTag(parser);
-            } else if (PackageParser.RIGID_PARSER) {
-                return parseInput.error(
-                        PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
-                        "Bad element under <key-sets>: " + parser.getName()
-                                + " at " + parsingPackage.getBaseCodePath() + " "
-                                + parser.getPositionDescription()
-                );
-            } else {
-                Slog.w(TAG, "Unknown element under <key-sets>: " + parser.getName()
-                        + " at " + parsingPackage.getBaseCodePath() + " "
-                        + parser.getPositionDescription());
-                XmlUtils.skipCurrentTag(parser);
-                continue;
-            }
-        }
-        String packageName = parsingPackage.getPackageName();
-        Set<String> publicKeyNames = publicKeys.keySet();
-        if (publicKeyNames.removeAll(definedKeySets.keySet())) {
-            return parseInput.error(
-                    PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
-                    "Package" + packageName + " AndroidManifest.xml "
-                            + "'key-set' and 'public-key' names must be distinct."
-            );
-        }
-
-        for (ArrayMap.Entry<String, ArraySet<String>> e : definedKeySets.entrySet()) {
-            final String keySetName = e.getKey();
-            if (e.getValue().size() == 0) {
-                Slog.w(TAG, "Package" + packageName + " AndroidManifest.xml "
-                        + "'key-set' " + keySetName + " has no valid associated 'public-key'."
-                        + " Not including in package's defined key-sets.");
-                continue;
-            } else if (improperKeySets.contains(keySetName)) {
-                Slog.w(TAG, "Package" + packageName + " AndroidManifest.xml "
-                        + "'key-set' " + keySetName + " contained improper 'public-key'"
-                        + " tags. Not including in package's defined key-sets.");
-                continue;
-            }
-
-            for (String s : e.getValue()) {
-                parsingPackage.addKeySet(keySetName, publicKeys.get(s));
-            }
-        }
-        if (parsingPackage.getKeySetMapping().keySet().containsAll(upgradeKeySets)) {
-            parsingPackage.setUpgradeKeySets(upgradeKeySets);
-        } else {
-            return parseInput.error(
-                    PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
-                    "Package" + packageName + " AndroidManifest.xml "
-                            + "does not define all 'upgrade-key-set's ."
-            );
-        }
-
-        return parseInput.success(parsingPackage);
-    }
-
-    public static boolean parsePackageItemInfo(String packageName, PackageItemInfo outInfo,
-            String[] outError, String tag, TypedArray sa, boolean nameRequired,
-            int nameRes, int labelRes, int iconRes, int roundIconRes, int logoRes, int bannerRes) {
-        // This case can only happen in unit tests where we sometimes need to create fakes
-        // of various package parser data structures.
-        if (sa == null) {
-            outError[0] = tag + " does not contain any attributes";
-            return false;
-        }
-
-        String name = sa.getNonConfigurationString(nameRes, 0);
-        if (name == null) {
-            if (nameRequired) {
-                outError[0] = tag + " does not specify android:name";
-                return false;
-            }
-        } else {
-            String outInfoName = buildClassName(packageName, name);
-            if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(outInfoName)) {
-                outError[0] = tag + " invalid android:name";
-                return false;
-            }
-            outInfo.name = outInfoName;
-            if (outInfoName == null) {
-                return false;
-            }
-        }
-
-        int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId(roundIconRes, 0) : 0;
-        if (roundIconVal != 0) {
-            outInfo.icon = roundIconVal;
-            outInfo.nonLocalizedLabel = null;
-        } else {
-            int iconVal = sa.getResourceId(iconRes, 0);
-            if (iconVal != 0) {
-                outInfo.icon = iconVal;
-                outInfo.nonLocalizedLabel = null;
-            }
-        }
-
-        int logoVal = sa.getResourceId(logoRes, 0);
-        if (logoVal != 0) {
-            outInfo.logo = logoVal;
-        }
-
-        int bannerVal = sa.getResourceId(bannerRes, 0);
-        if (bannerVal != 0) {
-            outInfo.banner = bannerVal;
-        }
-
-        TypedValue v = sa.peekValue(labelRes);
-        if (v != null && (outInfo.labelRes = v.resourceId) == 0) {
-            outInfo.nonLocalizedLabel = v.coerceToString();
-        }
-
-        outInfo.packageName = packageName;
-
-        return true;
-    }
-
-    private static ParseResult parsePackageItemInfo(
-            ParseInput parseInput,
-            ParsingPackage parsingPackage,
-            String tag,
-            TypedArray sa,
-            boolean nameRequired,
-            int nameRes,
-            int labelRes,
-            int iconRes,
-            int roundIconRes,
-            int logoRes,
-            int bannerRes
-    ) {
-        // This case can only happen in unit tests where we sometimes need to create fakes
-        // of various package parser data structures.
-        if (sa == null) {
-            return parseInput.error(
-                    PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
-                    tag + " does not contain any attributes"
-            );
-        }
-
-        String name = sa.getNonConfigurationString(nameRes, 0);
-        if (name == null) {
-            if (nameRequired) {
-                return parseInput.error(
-                        PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
-                        tag + " does not specify android:name"
-                );
-            }
-        } else {
-            String packageName = parsingPackage.getPackageName();
-            String outInfoName = buildClassName(packageName, name);
-            if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(outInfoName)) {
-                return parseInput.error(
-                        PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
-                        tag + " invalid android:name"
-                );
-            } else if (outInfoName == null) {
-                return parseInput.error(
-                        PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
-                        "Empty class name in package " + packageName
-                );
-            }
-
-            parsingPackage.setName(outInfoName);
-        }
-
-        int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId(roundIconRes, 0) : 0;
-        if (roundIconVal != 0) {
-            parsingPackage.setIcon(roundIconVal)
-                    .setNonLocalizedLabel(null);
-        } else {
-            int iconVal = sa.getResourceId(iconRes, 0);
-            if (iconVal != 0) {
-                parsingPackage.setIcon(iconVal)
-                        .setNonLocalizedLabel(null);
-            }
-        }
-
-        int logoVal = sa.getResourceId(logoRes, 0);
-        if (logoVal != 0) {
-            parsingPackage.setLogo(logoVal);
-        }
-
-        int bannerVal = sa.getResourceId(bannerRes, 0);
-        if (bannerVal != 0) {
-            parsingPackage.setBanner(bannerVal);
-        }
-
-        TypedValue v = sa.peekValue(labelRes);
-        if (v != null) {
-            parsingPackage.setLabelRes(v.resourceId);
-            if (v.resourceId == 0) {
-                parsingPackage.setNonLocalizedLabel(v.coerceToString());
-            }
-        }
-
-        return parseInput.success(parsingPackage);
-    }
-
-    private static ParseResult parseFeature(
-            ParseInput parseInput,
-            ParsingPackage parsingPackage,
-            Resources res,
-            XmlResourceParser parser
-    ) throws IOException, XmlPullParserException {
-        // TODO(b/135203078): Remove, replace with ParseResult
-        String[] outError = new String[1];
-
-        ComponentParseUtils.ParsedFeature parsedFeature =
-                ComponentParseUtils.parseFeature(res, parser, outError);
-
-        if (parsedFeature == null || outError[0] != null) {
-            return parseInput.error(
-                    PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
-                    outError[0]
-            );
-        }
-
-        parsingPackage.addFeature(parsedFeature);
-
-        return parseInput.success(parsingPackage);
-    }
-
-
-    private static ParseResult parsePermissionGroup(
-            ParseInput parseInput,
-            ParsingPackage parsingPackage,
-            Resources res,
-            XmlResourceParser parser
-    ) throws XmlPullParserException, IOException {
-        // TODO(b/135203078): Remove, replace with ParseResult
-        String[] outError = new String[1];
-
-        ComponentParseUtils.ParsedPermissionGroup parsedPermissionGroup =
-                ComponentParseUtils.parsePermissionGroup(parsingPackage,
-                        res, parser, outError);
-
-        if (parsedPermissionGroup == null || outError[0] != null) {
-            return parseInput.error(
-                    PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
-                    outError[0]
-            );
-        }
-
-        parsingPackage.addPermissionGroup(parsedPermissionGroup);
-
-        return parseInput.success(parsingPackage);
-    }
-
-    private static ParseResult parsePermission(
-            ParseInput parseInput,
-            ParsingPackage parsingPackage,
-            Resources res,
-            XmlResourceParser parser
-    ) throws XmlPullParserException, IOException {
-        // TODO(b/135203078): Remove, replace with ParseResult
-        String[] outError = new String[1];
-
-        ComponentParseUtils.ParsedPermission parsedPermission =
-                ComponentParseUtils.parsePermission(parsingPackage,
-                        res, parser, outError);
-
-        if (parsedPermission == null || outError[0] != null) {
-            return parseInput.error(
-                    PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
-                    outError[0]
-            );
-        }
-
-        parsingPackage.addPermission(parsedPermission);
-
-        return parseInput.success(parsingPackage);
-    }
-
-    private static ParseResult parsePermissionTree(
-            ParseInput parseInput,
-            ParsingPackage parsingPackage,
-            Resources res,
-            XmlResourceParser parser
-    ) throws XmlPullParserException, IOException {
-        // TODO(b/135203078): Remove, replace with ParseResult
-        String[] outError = new String[1];
-
-        ComponentParseUtils.ParsedPermission parsedPermission =
-                ComponentParseUtils.parsePermissionTree(parsingPackage,
-                        res, parser, outError);
-
-        if (parsedPermission == null || outError[0] != null) {
-            return parseInput.error(
-                    PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
-                    outError[0]
-            );
-        }
-
-        parsingPackage.addPermission(parsedPermission);
-
-        return parseInput.success(parsingPackage);
-    }
-
-    private static ParseResult parseUsesPermission(
-            ParseInput parseInput,
-            ParsingPackage parsingPackage,
-            Resources res,
-            XmlResourceParser parser,
-            PackageParser.Callback callback
-    )
-            throws XmlPullParserException, IOException {
-        TypedArray sa = res.obtainAttributes(parser,
-                R.styleable.AndroidManifestUsesPermission);
-
-        // Note: don't allow this value to be a reference to a resource
-        // that may change.
-        String name = sa.getNonResourceString(
-                R.styleable.AndroidManifestUsesPermission_name);
-
-        int maxSdkVersion = 0;
-        TypedValue val = sa.peekValue(
-                R.styleable.AndroidManifestUsesPermission_maxSdkVersion);
-        if (val != null) {
-            if (val.type >= TypedValue.TYPE_FIRST_INT && val.type <= TypedValue.TYPE_LAST_INT) {
-                maxSdkVersion = val.data;
-            }
-        }
-
-        final String requiredFeature = sa.getNonConfigurationString(
-                R.styleable.AndroidManifestUsesPermission_requiredFeature, 0);
-
-        final String requiredNotfeature = sa.getNonConfigurationString(
-                R.styleable.AndroidManifestUsesPermission_requiredNotFeature,
-                0);
-
-        sa.recycle();
-
-        XmlUtils.skipCurrentTag(parser);
-
-        // Can only succeed from here on out
-        ParseResult success = parseInput.success(parsingPackage);
-
-        if (name == null) {
-            return success;
-        }
-
-        if ((maxSdkVersion != 0) && (maxSdkVersion < Build.VERSION.RESOURCES_SDK_INT)) {
-            return success;
-        }
-
-        // Only allow requesting this permission if the platform supports the given feature.
-        if (requiredFeature != null && callback != null && !callback.hasFeature(requiredFeature)) {
-            return success;
-        }
-
-        // Only allow requesting this permission if the platform doesn't support the given feature.
-        if (requiredNotfeature != null && callback != null
-                && callback.hasFeature(requiredNotfeature)) {
-            return success;
-        }
-
-        if (!parsingPackage.getRequestedPermissions().contains(name)) {
-            parsingPackage.addRequestedPermission(name.intern());
-        } else {
-            Slog.w(TAG, "Ignoring duplicate uses-permissions/uses-permissions-sdk-m: "
-                    + name + " in package: " + parsingPackage.getPackageName() + " at: "
-                    + parser.getPositionDescription());
-        }
-
-        return success;
-    }
-
-    private static boolean parseUsesConfiguration(
-            ParsingPackage parsingPackage,
-            Resources res,
-            XmlResourceParser parser
-    ) throws IOException, XmlPullParserException {
-        ConfigurationInfo cPref = new ConfigurationInfo();
-        TypedArray sa = res.obtainAttributes(parser,
-                R.styleable.AndroidManifestUsesConfiguration);
-        cPref.reqTouchScreen = sa.getInt(
-                R.styleable.AndroidManifestUsesConfiguration_reqTouchScreen,
-                Configuration.TOUCHSCREEN_UNDEFINED);
-        cPref.reqKeyboardType = sa.getInt(
-                R.styleable.AndroidManifestUsesConfiguration_reqKeyboardType,
-                Configuration.KEYBOARD_UNDEFINED);
-        if (sa.getBoolean(
-                R.styleable.AndroidManifestUsesConfiguration_reqHardKeyboard,
-                false)) {
-            cPref.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD;
-        }
-        cPref.reqNavigation = sa.getInt(
-                R.styleable.AndroidManifestUsesConfiguration_reqNavigation,
-                Configuration.NAVIGATION_UNDEFINED);
-        if (sa.getBoolean(
-                R.styleable.AndroidManifestUsesConfiguration_reqFiveWayNav,
-                false)) {
-            cPref.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV;
-        }
-        sa.recycle();
-        parsingPackage.addConfigPreference(cPref);
-
-        XmlUtils.skipCurrentTag(parser);
-        return true;
-    }
-
-    private static boolean parseUsesFeature(
-            ParsingPackage parsingPackage,
-            Resources res,
-            XmlResourceParser parser
-    ) throws IOException, XmlPullParserException {
-        FeatureInfo fi = parseFeatureInfo(res, parser);
-        parsingPackage.addReqFeature(fi);
-
-        if (fi.name == null) {
-            ConfigurationInfo cPref = new ConfigurationInfo();
-            cPref.reqGlEsVersion = fi.reqGlEsVersion;
-            parsingPackage.addConfigPreference(cPref);
-        }
-
-        XmlUtils.skipCurrentTag(parser);
-        return true;
-    }
-
-    private static FeatureInfo parseFeatureInfo(Resources res, AttributeSet attrs) {
-        FeatureInfo fi = new FeatureInfo();
-        TypedArray sa = res.obtainAttributes(attrs,
-                R.styleable.AndroidManifestUsesFeature);
-        // Note: don't allow this value to be a reference to a resource
-        // that may change.
-        fi.name = sa.getNonResourceString(R.styleable.AndroidManifestUsesFeature_name);
-        fi.version = sa.getInt(R.styleable.AndroidManifestUsesFeature_version, 0);
-        if (fi.name == null) {
-            fi.reqGlEsVersion = sa.getInt(R.styleable.AndroidManifestUsesFeature_glEsVersion,
-                    FeatureInfo.GL_ES_VERSION_UNDEFINED);
-        }
-        if (sa.getBoolean(R.styleable.AndroidManifestUsesFeature_required, true)) {
-            fi.flags |= FeatureInfo.FLAG_REQUIRED;
-        }
-        sa.recycle();
-        return fi;
-    }
-
-    private static boolean parseFeatureGroup(
-            ParsingPackage parsingPackage,
-            Resources res,
-            XmlResourceParser parser
-    ) throws IOException, XmlPullParserException {
-        FeatureGroupInfo group = new FeatureGroupInfo();
-        ArrayList<FeatureInfo> features = null;
-        final int innerDepth = parser.getDepth();
-        int type;
-        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
-                && (type != XmlPullParser.END_TAG
-                || parser.getDepth() > innerDepth)) {
-            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
-                continue;
-            }
-
-            final String innerTagName = parser.getName();
-            if (innerTagName.equals("uses-feature")) {
-                FeatureInfo featureInfo = parseFeatureInfo(res, parser);
-                // FeatureGroups are stricter and mandate that
-                // any <uses-feature> declared are mandatory.
-                featureInfo.flags |= FeatureInfo.FLAG_REQUIRED;
-                features = ArrayUtils.add(features, featureInfo);
-            } else {
-                Slog.w(TAG,
-                        "Unknown element under <feature-group>: " + innerTagName +
-                                " at " + parsingPackage.getBaseCodePath() + " " +
-                                parser.getPositionDescription());
-            }
-            XmlUtils.skipCurrentTag(parser);
-        }
-
-        if (features != null) {
-            group.features = new FeatureInfo[features.size()];
-            group.features = features.toArray(group.features);
-        }
-
-        parsingPackage.addFeatureGroup(group);
-        return true;
-    }
-
-    private static ParseResult parseUsesSdk(
-            ParseInput parseInput,
-            ParsingPackage parsingPackage,
-            Resources res,
-            XmlResourceParser parser
-    ) throws IOException, XmlPullParserException {
-        if (PackageParser.SDK_VERSION > 0) {
-            TypedArray sa = res.obtainAttributes(parser,
-                    R.styleable.AndroidManifestUsesSdk);
-
-            int minVers = 1;
-            String minCode = null;
-            int targetVers = 0;
-            String targetCode = null;
-
-            TypedValue val = sa.peekValue(R.styleable.AndroidManifestUsesSdk_minSdkVersion);
-            if (val != null) {
-                if (val.type == TypedValue.TYPE_STRING && val.string != null) {
-                    minCode = val.string.toString();
-                } else {
-                    // If it's not a string, it's an integer.
-                    minVers = val.data;
-                }
-            }
-
-            val = sa.peekValue(R.styleable.AndroidManifestUsesSdk_targetSdkVersion);
-            if (val != null) {
-                if (val.type == TypedValue.TYPE_STRING && val.string != null) {
-                    targetCode = val.string.toString();
-                    if (minCode == null) {
-                        minCode = targetCode;
-                    }
-                } else {
-                    // If it's not a string, it's an integer.
-                    targetVers = val.data;
-                }
-            } else {
-                targetVers = minVers;
-                targetCode = minCode;
-            }
-
-            sa.recycle();
-
-            // TODO(b/135203078): Remove, replace with ParseResult
-            String[] outError = new String[1];
-            final int minSdkVersion = PackageParser.computeMinSdkVersion(minVers,
-                    minCode,
-                    PackageParser.SDK_VERSION, PackageParser.SDK_CODENAMES, outError);
-            if (minSdkVersion < 0) {
-                return parseInput.error(
-                        PackageManager.INSTALL_FAILED_OLDER_SDK
-                );
-            }
-
-            final int targetSdkVersion = PackageParser.computeTargetSdkVersion(
-                    targetVers,
-                    targetCode, PackageParser.SDK_CODENAMES, outError);
-            if (targetSdkVersion < 0) {
-                return parseInput.error(
-                        PackageManager.INSTALL_FAILED_OLDER_SDK
-                );
-            }
-
-            int type;
-            final int innerDepth = parser.getDepth();
-            while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
-                    && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
-                if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
-                    continue;
-                }
-                if (parser.getName().equals("extension-sdk")) {
-                    final ParseResult result =
-                            parseExtensionSdk(parseInput, parsingPackage, res, parser);
-                    if (!result.isSuccess()) {
-                        return result;
-                    }
-                } else {
-                    Slog.w(TAG, "Unknown element under <uses-sdk>: " + parser.getName()
-                            + " at " + parsingPackage.getBaseCodePath() + " "
-                            + parser.getPositionDescription());
-                }
-                XmlUtils.skipCurrentTag(parser);
-            }
-
-            parsingPackage.setMinSdkVersion(minSdkVersion)
-                    .setTargetSdkVersion(targetSdkVersion);
-        }
-        return parseInput.success(parsingPackage);
-    }
-
-    private static ParseResult parseExtensionSdk(
-            ParseInput parseInput,
-            ParsingPackage parsingPackage,
-            Resources res,
-            XmlResourceParser parser
-    ) throws IOException, XmlPullParserException {
-        TypedArray sa = res.obtainAttributes(parser,
-                com.android.internal.R.styleable.AndroidManifestExtensionSdk);
-        int sdkVersion = sa.getInt(
-                com.android.internal.R.styleable.AndroidManifestExtensionSdk_sdkVersion, -1);
-        int minVersion = sa.getInt(
-                com.android.internal.R.styleable.AndroidManifestExtensionSdk_minExtensionVersion,
-                -1);
-        sa.recycle();
-
-        if (sdkVersion < 0) {
-            return parseInput.error(
-                PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
-                "<extension-sdk> must specify an sdkVersion >= 0");
-        }
-        if (minVersion < 0) {
-            return parseInput.error(
-                PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
-                "<extension-sdk> must specify minExtensionVersion >= 0");
-        }
-
-        try {
-            int version = SdkExtensions.getExtensionVersion(sdkVersion);
-            if (version < minVersion) {
-                return parseInput.error(
-                        PackageManager.INSTALL_FAILED_OLDER_SDK,
-                        "Package requires " + sdkVersion + " extension version " + minVersion
-                                + " which exceeds device version " + version);
-            }
-        } catch (RuntimeException e) {
-            return parseInput.error(
-                    PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
-                    "Specified sdkVersion " + sdkVersion + " is not valid");
-        }
-        return parseInput.success(parsingPackage);
-    }
-
-    private static boolean parseRestrictUpdateHash(
-            int flags,
-            ParsingPackage parsingPackage,
-            Resources res,
-            XmlResourceParser parser
-    ) throws IOException, XmlPullParserException {
-        if ((flags & PackageParser.PARSE_IS_SYSTEM_DIR) != 0) {
-            TypedArray sa = res.obtainAttributes(parser,
-                    R.styleable.AndroidManifestRestrictUpdate);
-            final String hash = sa.getNonConfigurationString(
-                    R.styleable.AndroidManifestRestrictUpdate_hash,
-                    0);
-            sa.recycle();
-
-            if (hash != null) {
-                final int hashLength = hash.length();
-                final byte[] hashBytes = new byte[hashLength / 2];
-                for (int i = 0; i < hashLength; i += 2) {
-                    hashBytes[i / 2] = (byte) ((Character.digit(hash.charAt(i), 16)
-                            << 4)
-                            + Character.digit(hash.charAt(i + 1), 16));
-                }
-                parsingPackage.setRestrictUpdateHash(hashBytes);
-            } else {
-                parsingPackage.setRestrictUpdateHash(null);
-            }
-        }
-
-        XmlUtils.skipCurrentTag(parser);
-        return true;
-    }
-
-    private static ParseResult parseQueries(
-            ParseInput parseInput,
-            ParsingPackage parsingPackage,
-            Resources res,
-            XmlResourceParser parser
-    ) throws IOException, XmlPullParserException {
-
-        final int outerDepth = parser.getDepth();
-        int type;
-        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
-                && (type != XmlPullParser.END_TAG
-                || parser.getDepth() > outerDepth)) {
-            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
-                continue;
-            }
-            if (parser.getName().equals("intent")) {
-                String[] outError = new String[1];
-                ComponentParseUtils.ParsedQueriesIntentInfo intentInfo =
-                        ComponentParseUtils.parsedParsedQueriesIntentInfo(
-                                parsingPackage, res, parser, outError
-                        );
-                if (intentInfo == null) {
-                    return parseInput.error(
-                            PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
-                            outError[0]
-                    );
-                }
-
-                Uri data = null;
-                String dataType = null;
-                String host = "";
-                final int numActions = intentInfo.countActions();
-                final int numSchemes = intentInfo.countDataSchemes();
-                final int numTypes = intentInfo.countDataTypes();
-                final int numHosts = intentInfo.getHosts().length;
-                if ((numSchemes == 0 && numTypes == 0 && numActions == 0)) {
-                    outError[0] = "intent tags must contain either an action or data.";
-                    return parseInput.error(
-                            PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
-                            outError[0]
-                    );
-                }
-                if (numActions > 1) {
-                    outError[0] = "intent tag may have at most one action.";
-                    return parseInput.error(
-                            PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
-                            outError[0]
-                    );
-                }
-                if (numTypes > 1) {
-                    outError[0] = "intent tag may have at most one data type.";
-                    return parseInput.error(
-                            PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
-                            outError[0]
-                    );
-                }
-                if (numSchemes > 1) {
-                    outError[0] = "intent tag may have at most one data scheme.";
-                    return parseInput.error(
-                            PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
-                            outError[0]
-                    );
-                }
-                if (numHosts > 1) {
-                    outError[0] = "intent tag may have at most one data host.";
-                    return parseInput.error(
-                            PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
-                            outError[0]
-                    );
-                }
-                Intent intent = new Intent();
-                for (int i = 0, max = intentInfo.countCategories(); i < max; i++) {
-                    intent.addCategory(intentInfo.getCategory(i));
-                }
-                if (numHosts == 1) {
-                    host = intentInfo.getHosts()[0];
-                }
-                if (numSchemes == 1) {
-                    data = new Uri.Builder()
-                            .scheme(intentInfo.getDataScheme(0))
-                            .authority(host)
-                            .build();
-                }
-                if (numTypes == 1) {
-                    dataType = intentInfo.getDataType(0);
-                }
-                intent.setDataAndType(data, dataType);
-                if (numActions == 1) {
-                    intent.setAction(intentInfo.getAction(0));
-                }
-                parsingPackage.addQueriesIntent(intent);
-            } else if (parser.getName().equals("package")) {
-                final TypedArray sa = res.obtainAttributes(parser,
-                        R.styleable.AndroidManifestQueriesPackage);
-                final String packageName =
-                        sa.getString(R.styleable.AndroidManifestQueriesPackage_name);
-                if (TextUtils.isEmpty(packageName)) {
-                    return parseInput.error(
-                            PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
-                            "Package name is missing from package tag."
-                    );
-                }
-                parsingPackage.addQueriesPackage(packageName.intern());
-            } else if (parser.getName().equals("provider")) {
-                final TypedArray sa = res.obtainAttributes(parser,
-                        R.styleable.AndroidManifestQueriesProvider);
-                try {
-                    final String authorities =
-                            sa.getString(R.styleable.AndroidManifestQueriesProvider_authorities);
-                    if (TextUtils.isEmpty(authorities)) {
-                        return parseInput.error(
-                                PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
-                                "Authority missing from provider tag."
-                        );
-                    }
-                    StringTokenizer authoritiesTokenizer = new StringTokenizer(authorities, ";");
-                    while (authoritiesTokenizer.hasMoreElements()) {
-                        parsingPackage.addQueriesProvider(authoritiesTokenizer.nextToken());
-                    }
-                } finally {
-                    sa.recycle();
-                }
-            }
-        }
-        return parseInput.success(parsingPackage);
-    }
-
-    /**
-     * Parse the {@code application} XML tree at the current parse location in a
-     * <em>base APK</em> manifest.
-     * <p>
-     * When adding new features, carefully consider if they should also be
-     * supported by split APKs.
-     *
-     * @hide
-     */
-    public static ParseResult parseBaseApplication(
-            ParseInput parseInput,
-            String[] separateProcesses,
-            PackageParser.Callback callback,
-            ParsingPackage parsingPackage,
-            Resources res,
-            XmlResourceParser parser,
-            int flags
-    ) throws XmlPullParserException, IOException {
-        final String pkgName = parsingPackage.getPackageName();
-
-        // TODO(b/135203078): Remove, replace with ParseResult
-        String[] outError = new String[1];
-        TypedArray sa = null;
-
-        try {
-            sa = res.obtainAttributes(parser,
-                    R.styleable.AndroidManifestApplication);
-
-
-            parsingPackage
-                    .setIconRes(
-                            sa.getResourceId(R.styleable.AndroidManifestApplication_icon, 0))
-                    .setRoundIconRes(
-                            sa.getResourceId(R.styleable.AndroidManifestApplication_roundIcon, 0));
-
-            ParseResult result = parsePackageItemInfo(
-                    parseInput,
-                    parsingPackage,
-                    "<application>",
-                    sa, false /*nameRequired*/,
-                    R.styleable.AndroidManifestApplication_name,
-                    R.styleable.AndroidManifestApplication_label,
-                    R.styleable.AndroidManifestApplication_icon,
-                    R.styleable.AndroidManifestApplication_roundIcon,
-                    R.styleable.AndroidManifestApplication_logo,
-                    R.styleable.AndroidManifestApplication_banner
-            );
-            if (!result.isSuccess()) {
-                return result;
-            }
-
-            String name = parsingPackage.getName();
-            if (name != null) {
-                parsingPackage.setClassName(name);
-            }
-
-            String manageSpaceActivity = sa.getNonConfigurationString(
-                    R.styleable.AndroidManifestApplication_manageSpaceActivity,
-                    Configuration.NATIVE_CONFIG_VERSION);
-            if (manageSpaceActivity != null) {
-                String manageSpaceActivityName = buildClassName(pkgName, manageSpaceActivity);
-
-                if (manageSpaceActivityName == null) {
-                    return parseInput.error(
-                            PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
-                            "Empty class name in package " + pkgName
-                    );
-                }
-
-                parsingPackage.setManageSpaceActivityName(manageSpaceActivityName);
-            }
-
-            boolean allowBackup = sa.getBoolean(
-                    R.styleable.AndroidManifestApplication_allowBackup, true);
-            parsingPackage.setAllowBackup(allowBackup);
-
-            if (allowBackup) {
-                // backupAgent, killAfterRestore, fullBackupContent, backupInForeground,
-                // and restoreAnyVersion are only relevant if backup is possible for the
-                // given application.
-                String backupAgent = sa.getNonConfigurationString(
-                        R.styleable.AndroidManifestApplication_backupAgent,
-                        Configuration.NATIVE_CONFIG_VERSION);
-                if (backupAgent != null) {
-                    String backupAgentName = buildClassName(pkgName, backupAgent);
-                    if (backupAgentName == null) {
-                        return parseInput.error(
-                                PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
-                                "Empty class name in package " + pkgName
-                        );
-                    }
-
-                    if (PackageParser.DEBUG_BACKUP) {
-                        Slog.v(TAG, "android:backupAgent = " + backupAgentName
-                                + " from " + pkgName + "+" + backupAgent);
-                    }
-
-                    parsingPackage.setBackupAgentName(backupAgentName);
-
-                    parsingPackage.setKillAfterRestore(sa.getBoolean(
-                            R.styleable.AndroidManifestApplication_killAfterRestore, true));
-
-                    parsingPackage.setRestoreAnyVersion(sa.getBoolean(
-                            R.styleable.AndroidManifestApplication_restoreAnyVersion, false));
-
-                    parsingPackage.setFullBackupOnly(sa.getBoolean(
-                            R.styleable.AndroidManifestApplication_fullBackupOnly, false));
-
-                    parsingPackage.setBackupInForeground(sa.getBoolean(
-                            R.styleable.AndroidManifestApplication_backupInForeground,
-                            false));
-                }
-
-                TypedValue v = sa.peekValue(
-                        R.styleable.AndroidManifestApplication_fullBackupContent);
-                int fullBackupContent = 0;
-
-                if (v != null) {
-                    fullBackupContent = v.resourceId;
-
-                    if (v.resourceId == 0) {
-                        if (PackageParser.DEBUG_BACKUP) {
-                            Slog.v(TAG, "fullBackupContent specified as boolean=" +
-                                    (v.data == 0 ? "false" : "true"));
-                        }
-                        // "false" => -1, "true" => 0
-                        fullBackupContent = v.data == 0 ? -1 : 0;
-                    }
-
-                    parsingPackage.setFullBackupContent(fullBackupContent);
-                }
-                if (PackageParser.DEBUG_BACKUP) {
-                    Slog.v(TAG, "fullBackupContent=" + fullBackupContent + " for " + pkgName);
-                }
-            }
-
-            parsingPackage
-                    .setTheme(
-                            sa.getResourceId(R.styleable.AndroidManifestApplication_theme, 0))
-                    .setDescriptionRes(
-                            sa.getResourceId(R.styleable.AndroidManifestApplication_description,
-                                    0));
-
-            if (sa.getBoolean(
-                    R.styleable.AndroidManifestApplication_persistent,
-                    false)) {
-                // Check if persistence is based on a feature being present
-                final String requiredFeature = sa.getNonResourceString(R.styleable
-                        .AndroidManifestApplication_persistentWhenFeatureAvailable);
-                parsingPackage.setPersistent(requiredFeature == null
-                        || callback.hasFeature(requiredFeature));
-            }
-
-            boolean requiredForAllUsers = sa.getBoolean(
-                    R.styleable.AndroidManifestApplication_requiredForAllUsers,
-                    false);
-            parsingPackage.setRequiredForAllUsers(requiredForAllUsers);
-
-            String restrictedAccountType = sa.getString(R.styleable
-                    .AndroidManifestApplication_restrictedAccountType);
-            if (restrictedAccountType != null && restrictedAccountType.length() > 0) {
-                parsingPackage.setRestrictedAccountType(restrictedAccountType);
-            }
-
-            String requiredAccountType = sa.getString(R.styleable
-                    .AndroidManifestApplication_requiredAccountType);
-            if (requiredAccountType != null && requiredAccountType.length() > 0) {
-                parsingPackage.setRequiredAccountType(requiredAccountType);
-            }
-
-            parsingPackage.setForceQueryable(
-                    sa.getBoolean(R.styleable.AndroidManifestApplication_forceQueryable, false)
-            );
-
-            boolean debuggable = sa.getBoolean(
-                    R.styleable.AndroidManifestApplication_debuggable,
-                    false
-            );
-
-            parsingPackage.setDebuggable(debuggable);
-
-            if (debuggable) {
-                // Debuggable implies profileable
-                parsingPackage.setProfileableByShell(true);
-            }
-
-            parsingPackage.setVmSafeMode(sa.getBoolean(
-                    R.styleable.AndroidManifestApplication_vmSafeMode, false));
-
-            boolean baseHardwareAccelerated = sa.getBoolean(
-                    R.styleable.AndroidManifestApplication_hardwareAccelerated,
-                    parsingPackage.getTargetSdkVersion()
-                            >= Build.VERSION_CODES.ICE_CREAM_SANDWICH);
-            parsingPackage.setBaseHardwareAccelerated(baseHardwareAccelerated);
-
-            parsingPackage.setHasCode(sa.getBoolean(
-                    R.styleable.AndroidManifestApplication_hasCode, true));
-
-            parsingPackage.setAllowTaskReparenting(sa.getBoolean(
-                    R.styleable.AndroidManifestApplication_allowTaskReparenting, false));
-
-            parsingPackage.setAllowClearUserData(sa.getBoolean(
-                    R.styleable.AndroidManifestApplication_allowClearUserData, true));
-
-            parsingPackage.setTestOnly(sa.getBoolean(
-                    com.android.internal.R.styleable.AndroidManifestApplication_testOnly,
-                    false));
-
-            parsingPackage.setLargeHeap(sa.getBoolean(
-                    R.styleable.AndroidManifestApplication_largeHeap, false));
-
-            parsingPackage.setUsesCleartextTraffic(sa.getBoolean(
-                    R.styleable.AndroidManifestApplication_usesCleartextTraffic,
-                    parsingPackage.getTargetSdkVersion() < Build.VERSION_CODES.P));
-
-            parsingPackage.setSupportsRtl(sa.getBoolean(
-                    R.styleable.AndroidManifestApplication_supportsRtl,
-                    false /* default is no RTL support*/));
-
-            parsingPackage.setMultiArch(sa.getBoolean(
-                    R.styleable.AndroidManifestApplication_multiArch, false));
-
-            parsingPackage.setExtractNativeLibs(sa.getBoolean(
-                    R.styleable.AndroidManifestApplication_extractNativeLibs, true));
-
-            parsingPackage.setUseEmbeddedDex(sa.getBoolean(
-                    R.styleable.AndroidManifestApplication_useEmbeddedDex, false));
-
-            parsingPackage.setDefaultToDeviceProtectedStorage(sa.getBoolean(
-                    R.styleable.AndroidManifestApplication_defaultToDeviceProtectedStorage,
-                    false));
-
-            parsingPackage.setDirectBootAware(sa.getBoolean(
-                    R.styleable.AndroidManifestApplication_directBootAware, false));
-
-            if (sa.hasValueOrEmpty(R.styleable.AndroidManifestApplication_resizeableActivity)) {
-                parsingPackage.setActivitiesResizeModeResizeable(sa.getBoolean(
-                        R.styleable.AndroidManifestApplication_resizeableActivity, true));
-            } else {
-                parsingPackage.setActivitiesResizeModeResizeableViaSdkVersion(
-                        parsingPackage.getTargetSdkVersion() >= Build.VERSION_CODES.N);
-            }
-
-            parsingPackage.setAllowClearUserDataOnFailedRestore(sa.getBoolean(
-                    R.styleable.AndroidManifestApplication_allowClearUserDataOnFailedRestore,
-                    true));
-
-
-            parsingPackage.setAllowAudioPlaybackCapture(sa.getBoolean(
-                    R.styleable.AndroidManifestApplication_allowAudioPlaybackCapture,
-                    parsingPackage.getTargetSdkVersion() >= Build.VERSION_CODES.Q));
-
-            parsingPackage.setRequestLegacyExternalStorage(sa.getBoolean(
-                    R.styleable.AndroidManifestApplication_requestLegacyExternalStorage,
-                    parsingPackage.getTargetSdkVersion() < Build.VERSION_CODES.Q));
-
-            parsingPackage.setAllowNativeHeapPointerTagging(sa.getBoolean(
-                    R.styleable.AndroidManifestApplication_allowNativeHeapPointerTagging, true));
-
-            parsingPackage.setPreserveLegacyExternalStorage(sa.getBoolean(
-                            R.styleable.AndroidManifestApplication_preserveLegacyExternalStorage,
-                            false));
-
-            parsingPackage
-                    .setMaxAspectRatio(
-                            sa.getFloat(R.styleable.AndroidManifestApplication_maxAspectRatio, 0))
-                    .setMinAspectRatio(
-                            sa.getFloat(R.styleable.AndroidManifestApplication_minAspectRatio, 0))
-                    .setNetworkSecurityConfigRes(sa.getResourceId(
-                            R.styleable.AndroidManifestApplication_networkSecurityConfig, 0))
-                    .setCategory(sa.getInt(R.styleable.AndroidManifestApplication_appCategory,
-                            ApplicationInfo.CATEGORY_UNDEFINED));
-
-            String str;
-            str = sa.getNonConfigurationString(
-                    R.styleable.AndroidManifestApplication_permission, 0);
-            parsingPackage.setPermission((str != null && str.length() > 0) ? str.intern() : null);
-
-            if (parsingPackage.getTargetSdkVersion() >= Build.VERSION_CODES.FROYO) {
-                str = sa.getNonConfigurationString(
-                        R.styleable.AndroidManifestApplication_taskAffinity,
-                        Configuration.NATIVE_CONFIG_VERSION);
-            } else {
-                // Some older apps have been seen to use a resource reference
-                // here that on older builds was ignored (with a warning).  We
-                // need to continue to do this for them so they don't break.
-                str = sa.getNonResourceString(
-                        R.styleable.AndroidManifestApplication_taskAffinity);
-            }
-            String packageName = parsingPackage.getPackageName();
-            String taskAffinity = PackageParser.buildTaskAffinityName(packageName,
-                    packageName,
-                    str, outError);
-
-            if (outError[0] != null) {
-                return parseInput.error(
-                        PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
-                        outError[0]
-                );
-            }
-
-            parsingPackage.setTaskAffinity(taskAffinity);
-            String factory = sa.getNonResourceString(
-                    R.styleable.AndroidManifestApplication_appComponentFactory);
-            if (factory != null) {
-                String appComponentFactory = buildClassName(packageName, factory);
-                if (appComponentFactory == null) {
-                    return parseInput.error(
-                            PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
-                            "Empty class name in package " + pkgName
-                    );
-                }
-
-                parsingPackage.setAppComponentFactory(appComponentFactory);
-            }
-
-            parsingPackage.setUsesNonSdkApi(sa.getBoolean(
-                    R.styleable.AndroidManifestApplication_usesNonSdkApi, false));
-
-            parsingPackage.setHasFragileUserData(sa.getBoolean(
-                    R.styleable.AndroidManifestApplication_hasFragileUserData, false));
-
-            CharSequence pname;
-            if (parsingPackage.getTargetSdkVersion() >= Build.VERSION_CODES.FROYO) {
-                pname = sa.getNonConfigurationString(
-                        R.styleable.AndroidManifestApplication_process,
-                        Configuration.NATIVE_CONFIG_VERSION);
-            } else {
-                // Some older apps have been seen to use a resource reference
-                // here that on older builds was ignored (with a warning).  We
-                // need to continue to do this for them so they don't break.
-                pname = sa.getNonResourceString(
-                        R.styleable.AndroidManifestApplication_process);
-            }
-            String processName = PackageParser.buildProcessName(packageName, null, pname, flags,
-                    separateProcesses, outError);
-
-            if (outError[0] != null) {
-                return parseInput.error(
-                        PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
-                        outError[0]
-                );
-            }
-
-            parsingPackage
-                    .setProcessName(processName)
-                    .setEnabled(
-                            sa.getBoolean(R.styleable.AndroidManifestApplication_enabled,
-                                    true));
-
-            parsingPackage.setCrossProfile(
-                    sa.getBoolean(R.styleable.AndroidManifestApplication_crossProfile, false));
-
-            parsingPackage.setIsGame(sa.getBoolean(
-                    R.styleable.AndroidManifestApplication_isGame, false));
-
-            boolean cantSaveState = sa.getBoolean(
-                    R.styleable.AndroidManifestApplication_cantSaveState, false);
-            parsingPackage.setCantSaveState(cantSaveState);
-            if (cantSaveState) {
-                // A heavy-weight application can not be in a custom process.
-                // We can do direct compare because we intern all strings.
-                if (processName != null && !processName.equals(packageName)) {
-                    return parseInput.error(
-                            PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
-                            "cantSaveState applications can not use custom processes"
-                    );
-                }
-            }
-
-            String classLoaderName = sa.getString(
-                    R.styleable.AndroidManifestApplication_classLoader);
-            parsingPackage
-                    .setUiOptions(sa.getInt(R.styleable.AndroidManifestApplication_uiOptions, 0))
-                    .setClassLoaderName(classLoaderName)
-                    .setZygotePreloadName(
-                            sa.getString(R.styleable.AndroidManifestApplication_zygotePreloadName));
-
-            if (classLoaderName != null
-                    && !ClassLoaderFactory.isValidClassLoaderName(classLoaderName)) {
-                return parseInput.error(
-                        PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
-                        "Invalid class loader name: " + classLoaderName
-                );
-            }
-        } finally {
-            if (sa != null) {
-                sa.recycle();
-            }
-        }
-
-        final int innerDepth = parser.getDepth();
-        int type;
-        boolean hasActivityOrder = false;
-        boolean hasReceiverOrder = false;
-        boolean hasServiceOrder = false;
-
-        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
-                && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
-            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
-                continue;
-            }
-
-            String tagName = parser.getName();
-            switch (tagName) {
-                case "activity":
-                    ComponentParseUtils.ParsedActivity activity =
-                            ComponentParseUtils.parseActivity(separateProcesses,
-                                    parsingPackage,
-                                    res, parser, flags,
-                                    outError, false,
-                                    parsingPackage.isBaseHardwareAccelerated());
-                    if (activity == null) {
-                        return parseInput.error(
-                                PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
-                                outError[0]
-                        );
-                    }
-
-                    hasActivityOrder |= (activity.order != 0);
-                    parsingPackage.addActivity(activity);
-                    break;
-                case "receiver":
-                    activity = ComponentParseUtils.parseActivity(separateProcesses,
-                            parsingPackage,
-                            res, parser,
-                            flags, outError,
-                            true, false);
-                    if (activity == null) {
-                        return parseInput.error(
-                                PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
-                                outError[0]
-                        );
-                    }
-
-                    hasReceiverOrder |= (activity.order != 0);
-                    parsingPackage.addReceiver(activity);
-                    break;
-                case "service":
-                    ComponentParseUtils.ParsedService s = ComponentParseUtils.parseService(
-                            separateProcesses,
-                            parsingPackage,
-                            res, parser, flags,
-                            outError);
-                    if (s == null) {
-                        return parseInput.error(
-                                PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
-                                outError[0]
-                        );
-                    }
-
-                    hasServiceOrder |= (s.order != 0);
-                    parsingPackage.addService(s);
-                    break;
-                case "provider":
-                    ComponentParseUtils.ParsedProvider p = ComponentParseUtils.parseProvider(
-                            separateProcesses,
-                            parsingPackage,
-                            res, parser, flags,
-                            outError
-                    );
-                    if (p == null) {
-                        return parseInput.error(
-                                PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
-                                outError[0]
-                        );
-                    }
-
-                    parsingPackage.addProvider(p);
-                    break;
-                case "activity-alias":
-                    activity = ComponentParseUtils.parseActivityAlias(
-                            parsingPackage,
-                            res,
-                            parser,
-                            outError
-                    );
-                    if (activity == null) {
-                        return parseInput.error(
-                                PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
-                                outError[0]
-                        );
-                    }
-
-                    hasActivityOrder |= (activity.order != 0);
-                    parsingPackage.addActivity(activity);
-                    break;
-                case "meta-data":
-                    // note: application meta-data is stored off to the side, so it can
-                    // remain null in the primary copy (we like to avoid extra copies because
-                    // it can be large)
-                    Bundle appMetaData = parseMetaData(parsingPackage, res, parser,
-                            parsingPackage.getAppMetaData(),
-                            outError);
-                    if (appMetaData == null) {
-                        return parseInput.error(
-                                PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
-                                outError[0]
-                        );
-                    }
-
-                    parsingPackage.setAppMetaData(appMetaData);
-                    break;
-                case "static-library":
-                    sa = res.obtainAttributes(parser,
-                            R.styleable.AndroidManifestStaticLibrary);
-
-                    // Note: don't allow this value to be a reference to a resource
-                    // that may change.
-                    String lname = sa.getNonResourceString(
-                            R.styleable.AndroidManifestStaticLibrary_name);
-                    final int version = sa.getInt(
-                            R.styleable.AndroidManifestStaticLibrary_version, -1);
-                    final int versionMajor = sa.getInt(
-                            R.styleable.AndroidManifestStaticLibrary_versionMajor,
-                            0);
-
-                    sa.recycle();
-
-                    // Since the app canot run without a static lib - fail if malformed
-                    if (lname == null || version < 0) {
-                        return parseInput.error(
-                                PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
-                                "Bad static-library declaration name: " + lname
-                                        + " version: " + version
-                        );
-                    }
-
-                    if (parsingPackage.getSharedUserId() != null) {
-                        return parseInput.error(
-                                PackageManager.INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID,
-                                "sharedUserId not allowed in static shared library"
-                        );
-                    }
-
-                    if (parsingPackage.getStaticSharedLibName() != null) {
-                        return parseInput.error(
-                                PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
-                                "Multiple static-shared libs for package " + pkgName
-                        );
-                    }
-
-                    parsingPackage.setStaticSharedLibName(lname.intern());
-                    if (version >= 0) {
-                        parsingPackage.setStaticSharedLibVersion(
-                                PackageInfo.composeLongVersionCode(versionMajor, version));
-                    } else {
-                        parsingPackage.setStaticSharedLibVersion(version);
-                    }
-                    parsingPackage.setStaticSharedLibrary(true);
-
-                    XmlUtils.skipCurrentTag(parser);
-
-                    break;
-                case "library":
-                    sa = res.obtainAttributes(parser,
-                            R.styleable.AndroidManifestLibrary);
-
-                    // Note: don't allow this value to be a reference to a resource
-                    // that may change.
-                    lname = sa.getNonResourceString(
-                            R.styleable.AndroidManifestLibrary_name);
-
-                    sa.recycle();
-
-                    if (lname != null) {
-                        lname = lname.intern();
-                        if (!ArrayUtils.contains(parsingPackage.getLibraryNames(), lname)) {
-                            parsingPackage.addLibraryName(lname);
-                        }
-                    }
-
-                    XmlUtils.skipCurrentTag(parser);
-
-                    break;
-                case "uses-static-library":
-                    ParseResult parseResult = parseUsesStaticLibrary(parseInput, parsingPackage,
-                            res, parser);
-                    if (!parseResult.isSuccess()) {
-                        return parseResult;
-                    }
-                    break;
-                case "uses-library":
-                    sa = res.obtainAttributes(parser,
-                            R.styleable.AndroidManifestUsesLibrary);
-
-                    // Note: don't allow this value to be a reference to a resource
-                    // that may change.
-                    lname = sa.getNonResourceString(
-                            R.styleable.AndroidManifestUsesLibrary_name);
-                    boolean req = sa.getBoolean(
-                            R.styleable.AndroidManifestUsesLibrary_required,
-                            true);
-
-                    sa.recycle();
-
-                    if (lname != null) {
-                        lname = lname.intern();
-                        if (req) {
-                            parsingPackage.addUsesLibrary(lname);
-                        } else {
-                            parsingPackage.addUsesOptionalLibrary(lname);
-                        }
-                    }
-
-                    XmlUtils.skipCurrentTag(parser);
-
-                    break;
-                case "processes":
-                    ArrayMap<String, ComponentParseUtils.ParsedProcess> processes =
-                            ComponentParseUtils.parseProcesses(separateProcesses,
-                                    parsingPackage,
-                                    res, parser, flags,
-                                    outError);
-                    if (processes == null) {
-                        return parseInput.error(
-                                PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
-                                outError[0]
-                        );
-                    }
-
-                    parsingPackage.setProcesses(processes);
-                    break;
-                case "uses-package":
-                    // Dependencies for app installers; we don't currently try to
-                    // enforce this.
-                    XmlUtils.skipCurrentTag(parser);
-                    break;
-                case "profileable":
-                    sa = res.obtainAttributes(parser,
-                            R.styleable.AndroidManifestProfileable);
-                    if (sa.getBoolean(
-                            R.styleable.AndroidManifestProfileable_shell, false)) {
-                        parsingPackage.setProfileableByShell(true);
-                    }
-                    XmlUtils.skipCurrentTag(parser);
-                    break;
-                default:
-                    if (!PackageParser.RIGID_PARSER) {
-                        Slog.w(TAG, "Unknown element under <application>: " + tagName
-                                + " at " + parsingPackage.getBaseCodePath() + " "
-                                + parser.getPositionDescription());
-                        XmlUtils.skipCurrentTag(parser);
-                        continue;
-                    } else {
-                        return parseInput.error(
-                                PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
-                                "Bad element under <application>: " + tagName
-                        );
-                    }
-            }
-        }
-
-        if (TextUtils.isEmpty(parsingPackage.getStaticSharedLibName())) {
-            // Add a hidden app detail activity to normal apps which forwards user to App Details
-            // page.
-            ComponentParseUtils.ParsedActivity a = generateAppDetailsHiddenActivity(
-                    parsingPackage,
-                    outError
-            );
-            // Ignore errors here
-            parsingPackage.addActivity(a);
-        }
-
-        if (hasActivityOrder) {
-            parsingPackage.sortActivities();
-        }
-        if (hasReceiverOrder) {
-            parsingPackage.sortReceivers();
-        }
-        if (hasServiceOrder) {
-            parsingPackage.sortServices();
-        }
-        // Must be ran after the entire {@link ApplicationInfo} has been fully processed and after
-        // every activity info has had a chance to set it from its attributes.
-        setMaxAspectRatio(parsingPackage);
-        setMinAspectRatio(parsingPackage, callback);
-
-        parsingPackage.setHasDomainUrls(hasDomainURLs(parsingPackage));
-
-        return parseInput.success(parsingPackage);
-    }
-
-    private static ParseResult parseUsesStaticLibrary(
-            ParseInput parseInput,
-            ParsingPackage parsingPackage,
-            Resources res,
-            XmlResourceParser parser
-    ) throws XmlPullParserException, IOException {
-        TypedArray sa = res.obtainAttributes(parser,
-                R.styleable.AndroidManifestUsesStaticLibrary);
-
-        // Note: don't allow this value to be a reference to a resource that may change.
-        String lname = sa.getNonResourceString(
-                R.styleable.AndroidManifestUsesLibrary_name);
-        final int version = sa.getInt(
-                R.styleable.AndroidManifestUsesStaticLibrary_version, -1);
-        String certSha256Digest = sa.getNonResourceString(com.android.internal.R.styleable
-                .AndroidManifestUsesStaticLibrary_certDigest);
-        sa.recycle();
-
-        // Since an APK providing a static shared lib can only provide the lib - fail if malformed
-        if (lname == null || version < 0 || certSha256Digest == null) {
-            return parseInput.error(
-                    PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
-                    "Bad uses-static-library declaration name: " + lname + " version: "
-                            + version + " certDigest" + certSha256Digest
-            );
-        }
-
-        // Can depend only on one version of the same library
-        List<String> usesStaticLibraries = parsingPackage.getUsesStaticLibraries();
-        if (usesStaticLibraries != null && usesStaticLibraries.contains(lname)) {
-            return parseInput.error(
-                    PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
-                    "Depending on multiple versions of static library " + lname
-            );
-        }
-
-        lname = lname.intern();
-        // We allow ":" delimiters in the SHA declaration as this is the format
-        // emitted by the certtool making it easy for developers to copy/paste.
-        certSha256Digest = certSha256Digest.replace(":", "").toLowerCase();
-
-        // Fot apps targeting O-MR1 we require explicit enumeration of all certs.
-        String[] additionalCertSha256Digests = EmptyArray.STRING;
-        if (parsingPackage.getTargetSdkVersion() >= Build.VERSION_CODES.O_MR1) {
-            // TODO(b/135203078): Remove, replace with ParseResult
-            String[] outError = new String[1];
-            additionalCertSha256Digests = parseAdditionalCertificates(res, parser, outError);
-            if (additionalCertSha256Digests == null || outError[0] != null) {
-                return parseInput.error(
-                        PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
-                        outError[0]
-                );
-            }
-        } else {
-            XmlUtils.skipCurrentTag(parser);
-        }
-
-        final String[] certSha256Digests = new String[additionalCertSha256Digests.length + 1];
-        certSha256Digests[0] = certSha256Digest;
-        System.arraycopy(additionalCertSha256Digests, 0, certSha256Digests,
-                1, additionalCertSha256Digests.length);
-
-        parsingPackage.addUsesStaticLibrary(lname)
-                .addUsesStaticLibraryVersion(version)
-                .addUsesStaticLibraryCertDigests(certSha256Digests);
-
-        return parseInput.success(parsingPackage);
-    }
-
-    private static String[] parseAdditionalCertificates(
-            Resources resources,
-            XmlResourceParser parser,
-            String[] outError
-    ) throws XmlPullParserException, IOException {
-        String[] certSha256Digests = EmptyArray.STRING;
-
-        int outerDepth = parser.getDepth();
-        int type;
-        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
-                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
-            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
-                continue;
-            }
-
-            final String nodeName = parser.getName();
-            if (nodeName.equals("additional-certificate")) {
-                final TypedArray sa = resources.obtainAttributes(parser, com.android.internal.
-                        R.styleable.AndroidManifestAdditionalCertificate);
-                String certSha256Digest = sa.getNonResourceString(com.android.internal.
-                        R.styleable.AndroidManifestAdditionalCertificate_certDigest);
-                sa.recycle();
-
-                if (TextUtils.isEmpty(certSha256Digest)) {
-                    outError[0] = "Bad additional-certificate declaration with empty"
-                            + " certDigest:" + certSha256Digest;
-                    XmlUtils.skipCurrentTag(parser);
-                    sa.recycle();
-                    return null;
-                }
-
-                // We allow ":" delimiters in the SHA declaration as this is the format
-                // emitted by the certtool making it easy for developers to copy/paste.
-                certSha256Digest = certSha256Digest.replace(":", "").toLowerCase();
-                certSha256Digests = ArrayUtils.appendElement(String.class,
-                        certSha256Digests, certSha256Digest);
-            } else {
-                XmlUtils.skipCurrentTag(parser);
-            }
-        }
-
-        return certSha256Digests;
-    }
-
-    /**
-     * Generate activity object that forwards user to App Details page automatically.
-     * This activity should be invisible to user and user should not know or see it.
-     *
-     * @hide
-     */
-    @NonNull
-    private static ComponentParseUtils.ParsedActivity generateAppDetailsHiddenActivity(
-            ParsingPackage parsingPackage,
-            String[] outError
-    ) {
-        String packageName = parsingPackage.getPackageName();
-        String processName = parsingPackage.getProcessName();
-        boolean hardwareAccelerated = parsingPackage.isBaseHardwareAccelerated();
-        int uiOptions = parsingPackage.getUiOptions();
-
-        // Build custom App Details activity info instead of parsing it from xml
-        ComponentParseUtils.ParsedActivity activity = new ComponentParseUtils.ParsedActivity();
-        activity.setPackageName(packageName);
-
-        activity.theme = android.R.style.Theme_NoDisplay;
-        activity.exported = true;
-        activity.className = PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME;
-        activity.setProcessName(processName, processName);
-        activity.uiOptions = uiOptions;
-        activity.taskAffinity = PackageParser.buildTaskAffinityName(packageName,
-                packageName,
-                ":app_details", outError);
-        activity.enabled = true;
-        activity.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
-        activity.documentLaunchMode = ActivityInfo.DOCUMENT_LAUNCH_NONE;
-        activity.maxRecents = ActivityTaskManager.getDefaultAppRecentsLimitStatic();
-        activity.configChanges = PackageParser.getActivityConfigChanges(0, 0);
-        activity.softInputMode = 0;
-        activity.persistableMode = ActivityInfo.PERSIST_NEVER;
-        activity.screenOrientation = SCREEN_ORIENTATION_UNSPECIFIED;
-        activity.resizeMode = RESIZE_MODE_FORCE_RESIZEABLE;
-        activity.lockTaskLaunchMode = 0;
-        activity.directBootAware = false;
-        activity.rotationAnimation = ROTATION_ANIMATION_UNSPECIFIED;
-        activity.colorMode = ActivityInfo.COLOR_MODE_DEFAULT;
-        activity.preferMinimalPostProcessing = ActivityInfo.MINIMAL_POST_PROCESSING_DEFAULT;
-        if (hardwareAccelerated) {
-            activity.flags |= ActivityInfo.FLAG_HARDWARE_ACCELERATED;
-        }
-
-        return activity;
-    }
-
-    /**
-     * Check if one of the IntentFilter as both actions DEFAULT / VIEW and a HTTP/HTTPS data URI
-     */
-    private static boolean hasDomainURLs(
-            ParsingPackage parsingPackage) {
-        final List<ComponentParseUtils.ParsedActivity> activities = parsingPackage.getActivities();
-        final int countActivities = activities.size();
-        for (int n = 0; n < countActivities; n++) {
-            ComponentParseUtils.ParsedActivity activity = activities.get(n);
-            List<ComponentParseUtils.ParsedActivityIntentInfo> filters = activity.intents;
-            if (filters == null) continue;
-            final int countFilters = filters.size();
-            for (int m = 0; m < countFilters; m++) {
-                ComponentParseUtils.ParsedActivityIntentInfo aii = filters.get(m);
-                if (!aii.hasAction(Intent.ACTION_VIEW)) continue;
-                if (!aii.hasAction(Intent.ACTION_DEFAULT)) continue;
-                if (aii.hasDataScheme(IntentFilter.SCHEME_HTTP) ||
-                        aii.hasDataScheme(IntentFilter.SCHEME_HTTPS)) {
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
-
-    /**
-     * Sets the max aspect ratio of every child activity that doesn't already have an aspect
-     * ratio set.
-     */
-    private static void setMaxAspectRatio(
-            ParsingPackage parsingPackage) {
-        // Default to (1.86) 16.7:9 aspect ratio for pre-O apps and unset for O and greater.
-        // NOTE: 16.7:9 was the max aspect ratio Android devices can support pre-O per the CDD.
-        float maxAspectRatio = parsingPackage.getTargetSdkVersion() < O
-                ? PackageParser.DEFAULT_PRE_O_MAX_ASPECT_RATIO : 0;
-
-        float packageMaxAspectRatio = parsingPackage.getMaxAspectRatio();
-        if (packageMaxAspectRatio != 0) {
-            // Use the application max aspect ration as default if set.
-            maxAspectRatio = packageMaxAspectRatio;
-        } else {
-            Bundle appMetaData = parsingPackage.getAppMetaData();
-            if (appMetaData != null && appMetaData.containsKey(
-                    PackageParser.METADATA_MAX_ASPECT_RATIO)) {
-                maxAspectRatio = appMetaData.getFloat(PackageParser.METADATA_MAX_ASPECT_RATIO,
-                        maxAspectRatio);
-            }
-        }
-
-        if (parsingPackage.getActivities() != null) {
-            for (ComponentParseUtils.ParsedActivity activity : parsingPackage.getActivities()) {
-                // If the max aspect ratio for the activity has already been set, skip.
-                if (activity.hasMaxAspectRatio()) {
-                    continue;
-                }
-
-                // By default we prefer to use a values defined on the activity directly than values
-                // defined on the application. We do not check the styled attributes on the activity
-                // as it would have already been set when we processed the activity. We wait to
-                // process the meta data here since this method is called at the end of processing
-                // the application and all meta data is guaranteed.
-                final float activityAspectRatio = activity.metaData != null
-                        ? activity.metaData.getFloat(PackageParser.METADATA_MAX_ASPECT_RATIO,
-                        maxAspectRatio)
-                        : maxAspectRatio;
-
-                activity.setMaxAspectRatio(activity.resizeMode, activityAspectRatio);
-            }
-        }
-    }
-
-    /**
-     * Sets the min aspect ratio of every child activity that doesn't already have an aspect
-     * ratio set.
-     */
-    private static void setMinAspectRatio(
-            ParsingPackage parsingPackage,
-            PackageParser.Callback callback
-    ) {
-        final float minAspectRatio;
-        float packageMinAspectRatio = parsingPackage.getMinAspectRatio();
-        if (packageMinAspectRatio != 0) {
-            // Use the application max aspect ration as default if set.
-            minAspectRatio = packageMinAspectRatio;
-        } else {
-            // Default to (1.33) 4:3 aspect ratio for pre-Q apps and unset for Q and greater.
-            // NOTE: 4:3 was the min aspect ratio Android devices can support pre-Q per the CDD,
-            // except for watches which always supported 1:1.
-            minAspectRatio = parsingPackage.getTargetSdkVersion() >= Build.VERSION_CODES.Q
-                    ? 0
-                    : (callback != null && callback.hasFeature(FEATURE_WATCH))
-                            ? PackageParser.DEFAULT_PRE_Q_MIN_ASPECT_RATIO_WATCH
-                            : PackageParser.DEFAULT_PRE_Q_MIN_ASPECT_RATIO;
-        }
-
-        if (parsingPackage.getActivities() != null) {
-            for (ComponentParseUtils.ParsedActivity activity : parsingPackage.getActivities()) {
-                if (activity.hasMinAspectRatio()) {
-                    continue;
-                }
-                activity.setMinAspectRatio(activity.resizeMode, minAspectRatio);
-            }
-        }
-    }
-
-    private static ParseResult parseOverlay(
-            ParseInput parseInput,
-            ParsingPackage parsingPackage,
-            Resources res,
-            XmlResourceParser parser
-    ) throws IOException, XmlPullParserException {
-
-        TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestResourceOverlay);
-        String target = sa.getString(
-                R.styleable.AndroidManifestResourceOverlay_targetPackage);
-        String targetName = sa.getString(
-                R.styleable.AndroidManifestResourceOverlay_targetName);
-        String category = sa.getString(
-                R.styleable.AndroidManifestResourceOverlay_category);
-        int priority = sa.getInt(R.styleable.AndroidManifestResourceOverlay_priority,
-                0);
-        boolean isStatic = sa.getBoolean(
-                R.styleable.AndroidManifestResourceOverlay_isStatic, false);
-
-        if (target == null) {
-            return parseInput.error(
-                    PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
-                    "<overlay> does not specify a target package"
-            );
-        }
-
-        if (priority < 0 || priority > 9999) {
-            return parseInput.error(
-                    PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
-                    "<overlay> priority must be between 0 and 9999"
-            );
-        }
-
-        // check to see if overlay should be excluded based on system property condition
-        String propName = sa.getString(
-                R.styleable.AndroidManifestResourceOverlay_requiredSystemPropertyName);
-        String propValue = sa.getString(
-                R.styleable.AndroidManifestResourceOverlay_requiredSystemPropertyValue);
-        if (!checkOverlayRequiredSystemProperty(propName, propValue)) {
-            Slog.i(TAG, "Skipping target and overlay pair " + target + " and "
-                    + parsingPackage.getBaseCodePath()
-                    + ": overlay ignored due to required system property: "
-                    + propName + " with value: " + propValue);
-            return parseInput.error(
-                    PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
-                    "Skipping target and overlay pair " + target + " and "
-                            + parsingPackage.getBaseCodePath()
-                            + ": overlay ignored due to required system property: "
-                            + propName + " with value: " + propValue
-            );
-        }
-
-        parsingPackage
-                .setIsOverlay(true)
-                .setOverlayTarget(target)
-                .setOverlayTargetName(targetName)
-                .setOverlayCategory(category)
-                .setOverlayPriority(priority)
-                .setOverlayIsStatic(isStatic);
-
-        sa.recycle();
-
-        XmlUtils.skipCurrentTag(parser);
-        return parseInput.success(parsingPackage);
-    }
-
-    private static boolean parseProtectedBroadcast(
-            ParsingPackage parsingPackage,
-            Resources res,
-            XmlResourceParser parser
-    ) throws IOException, XmlPullParserException {
-        TypedArray sa = res.obtainAttributes(parser,
-                R.styleable.AndroidManifestProtectedBroadcast);
-
-        // Note: don't allow this value to be a reference to a resource
-        // that may change.
-        String name = sa.getNonResourceString(R.styleable.AndroidManifestProtectedBroadcast_name);
-
-        sa.recycle();
-
-        if (name != null) {
-            parsingPackage.addProtectedBroadcast(name);
-        }
-
-        XmlUtils.skipCurrentTag(parser);
-        return true;
-    }
-
-    private static boolean parseSupportScreens(
-            ParsingPackage parsingPackage,
-            Resources res,
-            XmlResourceParser parser
-    ) throws IOException, XmlPullParserException {
-        TypedArray sa = res.obtainAttributes(parser,
-                R.styleable.AndroidManifestSupportsScreens);
-
-        int requiresSmallestWidthDp = sa.getInteger(
-                R.styleable.AndroidManifestSupportsScreens_requiresSmallestWidthDp,
-                0);
-        int compatibleWidthLimitDp = sa.getInteger(
-                R.styleable.AndroidManifestSupportsScreens_compatibleWidthLimitDp,
-                0);
-        int largestWidthLimitDp = sa.getInteger(
-                R.styleable.AndroidManifestSupportsScreens_largestWidthLimitDp,
-                0);
-
-        // This is a trick to get a boolean and still able to detect
-        // if a value was actually set.
-        parsingPackage
-                .setSupportsSmallScreens(
-                        sa.getInteger(R.styleable.AndroidManifestSupportsScreens_smallScreens, 1))
-                .setSupportsNormalScreens(
-                        sa.getInteger(R.styleable.AndroidManifestSupportsScreens_normalScreens, 1))
-                .setSupportsLargeScreens(
-                        sa.getInteger(R.styleable.AndroidManifestSupportsScreens_largeScreens, 1))
-                .setSupportsXLargeScreens(
-                        sa.getInteger(R.styleable.AndroidManifestSupportsScreens_xlargeScreens, 1))
-                .setResizeable(
-                        sa.getInteger(R.styleable.AndroidManifestSupportsScreens_resizeable, 1))
-                .setAnyDensity(
-                        sa.getInteger(R.styleable.AndroidManifestSupportsScreens_anyDensity, 1))
-                .setRequiresSmallestWidthDp(requiresSmallestWidthDp)
-                .setCompatibleWidthLimitDp(compatibleWidthLimitDp)
-                .setLargestWidthLimitDp(largestWidthLimitDp);
-
-        sa.recycle();
-
-        XmlUtils.skipCurrentTag(parser);
-        return true;
-    }
-
-    private static ParseResult parseInstrumentation(
-            ParseInput parseInput,
-            ParsingPackage parsingPackage,
-            Resources res,
-            XmlResourceParser parser
-    ) throws XmlPullParserException, IOException {
-        // TODO(b/135203078): Remove, replace with ParseResult
-        String[] outError = new String[1];
-
-        ComponentParseUtils.ParsedInstrumentation parsedInstrumentation =
-                ComponentParseUtils.parseInstrumentation(parsingPackage,
-                        res, parser, outError);
-
-        if (parsedInstrumentation == null || outError[0] != null) {
-            return parseInput.error(
-                    PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
-                    outError[0]
-            );
-        }
-
-        parsingPackage.addInstrumentation(parsedInstrumentation);
-
-        return parseInput.success(parsingPackage);
-    }
-
-    private static boolean parseOriginalPackage(
-            ParsingPackage parsingPackage,
-            Resources res,
-            XmlResourceParser parser
-    ) throws IOException, XmlPullParserException {
-        TypedArray sa = res.obtainAttributes(parser,
-                R.styleable.AndroidManifestOriginalPackage);
-
-        String orig = sa.getNonConfigurationString(
-                R.styleable.AndroidManifestOriginalPackage_name,
-                0);
-        if (!parsingPackage.getPackageName().equals(orig)) {
-            if (parsingPackage.getOriginalPackages() == null) {
-                parsingPackage.setRealPackage(parsingPackage.getPackageName());
-            }
-            parsingPackage.addOriginalPackage(orig);
-        }
-
-        sa.recycle();
-
-        XmlUtils.skipCurrentTag(parser);
-        return true;
-    }
-
-    private static boolean parseAdoptPermissions(
-            ParsingPackage parsingPackage,
-            Resources res,
-            XmlResourceParser parser
-    ) throws IOException, XmlPullParserException {
-        TypedArray sa = res.obtainAttributes(parser,
-                R.styleable.AndroidManifestOriginalPackage);
-
-        String name = sa.getNonConfigurationString(
-                R.styleable.AndroidManifestOriginalPackage_name,
-                0);
-
-        sa.recycle();
-
-        if (name != null) {
-            parsingPackage.addAdoptPermission(name);
-        }
-
-        XmlUtils.skipCurrentTag(parser);
-        return true;
-    }
-
-    private static void convertNewPermissions(
-            ParsingPackage packageToParse) {
-        final int NP = PackageParser.NEW_PERMISSIONS.length;
-        StringBuilder newPermsMsg = null;
-        for (int ip = 0; ip < NP; ip++) {
-            final PackageParser.NewPermissionInfo npi
-                    = PackageParser.NEW_PERMISSIONS[ip];
-            if (packageToParse.getTargetSdkVersion() >= npi.sdkVersion) {
-                break;
-            }
-            if (!packageToParse.getRequestedPermissions().contains(npi.name)) {
-                if (newPermsMsg == null) {
-                    newPermsMsg = new StringBuilder(128);
-                    newPermsMsg.append(packageToParse.getPackageName());
-                    newPermsMsg.append(": compat added ");
-                } else {
-                    newPermsMsg.append(' ');
-                }
-                newPermsMsg.append(npi.name);
-                packageToParse.addRequestedPermission(npi.name);
-                packageToParse.addImplicitPermission(npi.name);
-            }
-        }
-        if (newPermsMsg != null) {
-            Slog.i(TAG, newPermsMsg.toString());
-        }
-    }
-
-    private static void convertSplitPermissions(ParsingPackage packageToParse) {
-        List<SplitPermissionInfoParcelable> splitPermissions;
-
-        try {
-            splitPermissions = ActivityThread.getPermissionManager().getSplitPermissions();
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-
-        final int listSize = splitPermissions.size();
-        for (int is = 0; is < listSize; is++) {
-            final SplitPermissionInfoParcelable spi = splitPermissions.get(is);
-            List<String> requestedPermissions = packageToParse.getRequestedPermissions();
-            if (packageToParse.getTargetSdkVersion() >= spi.getTargetSdk()
-                    || !requestedPermissions.contains(spi.getSplitPermission())) {
-                continue;
-            }
-            final List<String> newPerms = spi.getNewPermissions();
-            for (int in = 0; in < newPerms.size(); in++) {
-                final String perm = newPerms.get(in);
-                if (!requestedPermissions.contains(perm)) {
-                    packageToParse.addRequestedPermission(perm);
-                    packageToParse.addImplicitPermission(perm);
-                }
-            }
-        }
-    }
-
-    private static boolean checkOverlayRequiredSystemProperty(String propName, String propValue) {
-        if (TextUtils.isEmpty(propName) || TextUtils.isEmpty(propValue)) {
-            if (!TextUtils.isEmpty(propName) || !TextUtils.isEmpty(propValue)) {
-                // malformed condition - incomplete
-                Slog.w(TAG, "Disabling overlay - incomplete property :'" + propName
-                        + "=" + propValue + "' - require both requiredSystemPropertyName"
-                        + " AND requiredSystemPropertyValue to be specified.");
-                return false;
-            }
-            // no valid condition set - so no exclusion criteria, overlay will be included.
-            return true;
-        }
-
-        // check property value - make sure it is both set and equal to expected value
-        final String currValue = SystemProperties.get(propName);
-        return (currValue != null && currValue.equals(propValue));
-    }
-
-    /**
-     * This is a pre-density application which will get scaled - instead of being pixel perfect.
-     * This type of application is not resizable.
-     *
-     * @param parsingPackage The package which needs to be marked as unresizable.
-     */
-    private static void adjustPackageToBeUnresizeableAndUnpipable(
-            ParsingPackage parsingPackage) {
-        if (parsingPackage.getActivities() != null) {
-            for (ComponentParseUtils.ParsedActivity a : parsingPackage.getActivities()) {
-                a.resizeMode = RESIZE_MODE_UNRESIZEABLE;
-                a.flags &= ~FLAG_SUPPORTS_PICTURE_IN_PICTURE;
-            }
-        }
-    }
-
-    private static String validateName(String name, boolean requireSeparator,
-            boolean requireFilename) {
-        final int N = name.length();
-        boolean hasSep = false;
-        boolean front = true;
-        for (int i = 0; i < N; i++) {
-            final char c = name.charAt(i);
-            if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
-                front = false;
-                continue;
-            }
-            if (!front) {
-                if ((c >= '0' && c <= '9') || c == '_') {
-                    continue;
-                }
-            }
-            if (c == '.') {
-                hasSep = true;
-                front = true;
-                continue;
-            }
-            return "bad character '" + c + "'";
-        }
-        if (requireFilename && !FileUtils.isValidExtFilename(name)) {
-            return "Invalid filename";
-        }
-        return hasSep || !requireSeparator
-                ? null : "must have at least one '.' separator";
-    }
-
-    public static Bundle parseMetaData(
-            ParsingPackage parsingPackage,
-            Resources res,
-            XmlResourceParser parser, Bundle data, String[] outError)
-            throws XmlPullParserException, IOException {
-
-        TypedArray sa = res.obtainAttributes(parser,
-                R.styleable.AndroidManifestMetaData);
-
-        if (data == null) {
-            data = new Bundle();
-        }
-
-        String name = sa.getNonConfigurationString(
-                R.styleable.AndroidManifestMetaData_name, 0);
-        if (name == null) {
-            outError[0] = "<meta-data> requires an android:name attribute";
-            sa.recycle();
-            return null;
-        }
-
-        name = name.intern();
-
-        TypedValue v = sa.peekValue(
-                R.styleable.AndroidManifestMetaData_resource);
-        if (v != null && v.resourceId != 0) {
-            //Slog.i(TAG, "Meta data ref " + name + ": " + v);
-            data.putInt(name, v.resourceId);
-        } else {
-            v = sa.peekValue(
-                    R.styleable.AndroidManifestMetaData_value);
-            //Slog.i(TAG, "Meta data " + name + ": " + v);
-            if (v != null) {
-                if (v.type == TypedValue.TYPE_STRING) {
-                    CharSequence cs = v.coerceToString();
-                    data.putString(name, cs != null ? cs.toString() : null);
-                } else if (v.type == TypedValue.TYPE_INT_BOOLEAN) {
-                    data.putBoolean(name, v.data != 0);
-                } else if (v.type >= TypedValue.TYPE_FIRST_INT
-                        && v.type <= TypedValue.TYPE_LAST_INT) {
-                    data.putInt(name, v.data);
-                } else if (v.type == TypedValue.TYPE_FLOAT) {
-                    data.putFloat(name, v.getFloat());
-                } else {
-                    if (!PackageParser.RIGID_PARSER) {
-                        Slog.w(TAG,
-                                "<meta-data> only supports string, integer, float, color, "
-                                        + "boolean, and resource reference types: "
-                                        + parser.getName() + " at "
-                                        + parsingPackage.getBaseCodePath() + " "
-                                        + parser.getPositionDescription());
-                    } else {
-                        outError[0] =
-                                "<meta-data> only supports string, integer, float, color, "
-                                        + "boolean, and resource reference types";
-                        data = null;
-                    }
-                }
-            } else {
-                outError[0] = "<meta-data> requires an android:value or android:resource attribute";
-                data = null;
-            }
-        }
-
-        sa.recycle();
-
-        XmlUtils.skipCurrentTag(parser);
-
-        return data;
-    }
-
-    /**
-     * Collect certificates from all the APKs described in the given package,
-     * populating {@link AndroidPackageWrite#setSigningDetails(SigningDetails)}. Also asserts that
-     * all APK contents are signed correctly and consistently.
-     */
-    public static void collectCertificates(AndroidPackage pkg, boolean skipVerify)
-            throws PackageParserException {
-        pkg.mutate().setSigningDetails(SigningDetails.UNKNOWN);
-
-        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates");
-        try {
-            pkg.mutate().setSigningDetails(collectCertificates(
-                    pkg.getBaseCodePath(),
-                    skipVerify,
-                    pkg.isStaticSharedLibrary(),
-                    pkg.getSigningDetails(),
-                    pkg.getTargetSdkVersion()
-            ));
-
-            String[] splitCodePaths = pkg.getSplitCodePaths();
-            if (!ArrayUtils.isEmpty(splitCodePaths)) {
-                for (int i = 0; i < splitCodePaths.length; i++) {
-                    pkg.mutate().setSigningDetails(collectCertificates(
-                            splitCodePaths[i],
-                            skipVerify,
-                            pkg.isStaticSharedLibrary(),
-                            pkg.getSigningDetails(),
-                            pkg.getTargetSdkVersion()
-                    ));
-                }
-            }
-        } finally {
-            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
-        }
-    }
-
-    public static SigningDetails collectCertificates(
-            String baseCodePath,
-            boolean skipVerify,
-            boolean isStaticSharedLibrary,
-            @NonNull SigningDetails existingSigningDetails,
-            int targetSdk
-    ) throws PackageParserException {
-        int minSignatureScheme = ApkSignatureVerifier.getMinimumSignatureSchemeVersionForTargetSdk(
-                targetSdk);
-        if (isStaticSharedLibrary) {
-            // must use v2 signing scheme
-            minSignatureScheme = SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V2;
-        }
-        SigningDetails verified;
-        if (skipVerify) {
-            // systemDir APKs are already trusted, save time by not verifying
-            verified = ApkSignatureVerifier.unsafeGetCertsWithoutVerification(
-                    baseCodePath, minSignatureScheme);
-        } else {
-            verified = ApkSignatureVerifier.verify(baseCodePath, minSignatureScheme);
-        }
-
-        // Verify that entries are signed consistently with the first pkg
-        // we encountered. Note that for splits, certificates may have
-        // already been populated during an earlier parse of a base APK.
-        if (existingSigningDetails == SigningDetails.UNKNOWN) {
-            return verified;
-        } else {
-            if (!Signature.areExactMatch(existingSigningDetails.signatures, verified.signatures)) {
-                throw new PackageParserException(
-                        INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES,
-                        baseCodePath + " has mismatched certificates");
-            }
-
-            return existingSigningDetails;
-        }
-    }
-
-    @Nullable
-    public static String buildClassName(String pkg, CharSequence clsSeq) {
-        if (clsSeq == null || clsSeq.length() <= 0) {
-            return null;
-        }
-        String cls = clsSeq.toString();
-        char c = cls.charAt(0);
-        if (c == '.') {
-            return pkg + cls;
-        }
-        if (cls.indexOf('.') < 0) {
-            StringBuilder b = new StringBuilder(pkg);
-            b.append('.');
-            b.append(cls);
-            return b.toString();
-        }
-        return cls;
-    }
-
-    public interface ParseInput {
-        ParseResult success(ParsingPackage result);
-
-        ParseResult error(int parseError);
-
-        ParseResult error(int parseError, String errorMessage);
-    }
-
-    public static class ParseResult implements ParseInput {
-
-        private static final boolean DEBUG_FILL_STACK_TRACE = false;
-
-        private ParsingPackage result;
-
-        private int parseError;
-        private String errorMessage;
-
-        public ParseInput reset() {
-            this.result = null;
-            this.parseError = PackageManager.INSTALL_SUCCEEDED;
-            this.errorMessage = null;
-            return this;
-        }
-
-        @Override
-        public ParseResult success(ParsingPackage result) {
-            if (parseError != PackageManager.INSTALL_SUCCEEDED || errorMessage != null) {
-                throw new IllegalStateException("Cannot set to success after set to error");
-            }
-            this.result = result;
-            return this;
-        }
-
-        @Override
-        public ParseResult error(int parseError) {
-            return error(parseError, null);
-        }
-
-        @Override
-        public ParseResult error(int parseError, String errorMessage) {
-            this.parseError = parseError;
-            this.errorMessage = errorMessage;
-
-            if (DEBUG_FILL_STACK_TRACE) {
-                this.errorMessage += Arrays.toString(new Exception().getStackTrace());
-            }
-
-            return this;
-        }
-
-        public ParsingPackage getResultAndNull() {
-            ParsingPackage result = this.result;
-            this.result = null;
-            return result;
-        }
-
-        public boolean isSuccess() {
-            return parseError == PackageManager.INSTALL_SUCCEEDED;
-        }
-
-        public int getParseError() {
-            return parseError;
-        }
-
-        public String getErrorMessage() {
-            return errorMessage;
-        }
-    }
-}
diff --git a/core/java/android/content/pm/parsing/ComponentParseUtils.java b/core/java/android/content/pm/parsing/ComponentParseUtils.java
deleted file mode 100644
index 6852a8c..0000000
--- a/core/java/android/content/pm/parsing/ComponentParseUtils.java
+++ /dev/null
@@ -1,3793 +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 static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE;
-import static android.content.pm.ActivityInfo.FLAG_SUPPORTS_PICTURE_IN_PICTURE;
-import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
-import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
-import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
-import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_UNSPECIFIED;
-
-import android.annotation.CallSuper;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.StringRes;
-import android.app.ActivityTaskManager;
-import android.compat.annotation.UnsupportedAppUsage;
-import android.content.ComponentName;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.ActivityInfo;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageParser;
-import android.content.pm.PathPermission;
-import android.content.pm.PermissionInfo;
-import android.content.pm.ProviderInfo;
-import android.content.pm.ServiceInfo;
-import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.content.res.TypedArray;
-import android.content.res.XmlResourceParser;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.os.PatternMatcher;
-import android.text.TextUtils;
-import android.util.ArrayMap;
-import android.util.ArraySet;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.util.Slog;
-import android.util.TypedValue;
-import android.view.Gravity;
-
-import com.android.internal.R;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.DataClass;
-import com.android.internal.util.XmlUtils;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
-import java.io.IOException;
-import java.lang.reflect.Constructor;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Objects;
-
-/**
- * TODO(b/135203078): Move the inner classes out to separate files.
- * TODO(b/135203078): Expose inner classes as immutable through interface methods.
- *
- * @hide
- */
-public class ComponentParseUtils {
-
-    private static final String TAG = ApkParseUtils.TAG;
-
-    // TODO(b/135203078): None of this class's subclasses do anything. Remove in favor of base?
-    public static class ParsedIntentInfo extends IntentFilter {
-
-        /**
-         * <p>
-         * Implementation note: The serialized form for the intent list also contains the name
-         * of the concrete class that's stored in the list, and assumes that every element of the
-         * list is of the same type. This is very similar to the original parcelable mechanism.
-         * We cannot use that directly because IntentInfo extends IntentFilter, which is parcelable
-         * and is public API. It also declares Parcelable related methods as final which means
-         * we can't extend them. The approach of using composition instead of inheritance leads to
-         * a large set of cascading changes in the PackageManagerService, which seem undesirable.
-         *
-         * <p>
-         * <b>WARNING: </b> The list of objects returned by this function might need to be fixed up
-         * to make sure their owner fields are consistent. See {@code fixupOwner}.
-         */
-        public static void writeIntentsList(List<? extends ParsedIntentInfo> list, Parcel out,
-                int flags) {
-            if (list == null) {
-                out.writeInt(-1);
-                return;
-            }
-
-            final int size = list.size();
-            out.writeInt(size);
-
-            // Don't bother writing the component name if the list is empty.
-            if (size > 0) {
-                ParsedIntentInfo info = list.get(0);
-                out.writeString(info.getClass().getName());
-
-                for (int i = 0; i < size; i++) {
-                    list.get(i).writeIntentInfoToParcel(out, flags);
-                }
-            }
-        }
-
-        public static <T extends ParsedIntentInfo> ArrayList<T> createIntentsList(Parcel in) {
-            int size = in.readInt();
-            if (size == -1) {
-                return null;
-            }
-
-            if (size == 0) {
-                return new ArrayList<>(0);
-            }
-
-            String className = in.readString();
-            final ArrayList<T> intentsList;
-            try {
-                final Class<T> cls = (Class<T>) Class.forName(className);
-                final Constructor<T> cons = cls.getConstructor(Parcel.class);
-
-                intentsList = new ArrayList<>(size);
-                for (int i = 0; i < size; ++i) {
-                    intentsList.add(cons.newInstance(in));
-                }
-            } catch (ReflectiveOperationException ree) {
-                throw new AssertionError("Unable to construct intent list for: "
-                        + className, ree);
-            }
-
-            return intentsList;
-        }
-
-        protected String packageName;
-        protected final String className;
-
-        public boolean hasDefault;
-        public int labelRes;
-        public CharSequence nonLocalizedLabel;
-        public int icon;
-
-        protected List<String> rawDataTypes;
-
-        public void addRawDataType(String dataType) throws MalformedMimeTypeException {
-            if (rawDataTypes == null) {
-                rawDataTypes = new ArrayList<>();
-            }
-
-            rawDataTypes.add(dataType);
-            addDataType(dataType);
-        }
-
-        public ParsedIntentInfo(String packageName, String className) {
-            this.packageName = packageName;
-            this.className = className;
-        }
-
-        public ParsedIntentInfo(Parcel in) {
-            super(in);
-            packageName = in.readString();
-            className = in.readString();
-            hasDefault = (in.readInt() == 1);
-            labelRes = in.readInt();
-            nonLocalizedLabel = in.readCharSequence();
-            icon = in.readInt();
-        }
-
-        public void writeIntentInfoToParcel(Parcel dest, int flags) {
-            super.writeToParcel(dest, flags);
-            dest.writeString(packageName);
-            dest.writeString(className);
-            dest.writeInt(hasDefault ? 1 : 0);
-            dest.writeInt(labelRes);
-            dest.writeCharSequence(nonLocalizedLabel);
-            dest.writeInt(icon);
-        }
-
-        public String getPackageName() {
-            return packageName;
-        }
-
-        public String getClassName() {
-            return className;
-        }
-    }
-
-    public static class ParsedActivityIntentInfo extends ParsedIntentInfo {
-
-        public ParsedActivityIntentInfo(String packageName, String className) {
-            super(packageName, className);
-        }
-
-        public ParsedActivityIntentInfo(Parcel in) {
-            super(in);
-        }
-
-        public static final Creator<ParsedActivityIntentInfo> CREATOR =
-                new Creator<ParsedActivityIntentInfo>() {
-                    @Override
-                    public ParsedActivityIntentInfo createFromParcel(Parcel source) {
-                        return new ParsedActivityIntentInfo(source);
-                    }
-
-                    @Override
-                    public ParsedActivityIntentInfo[] newArray(int size) {
-                        return new ParsedActivityIntentInfo[size];
-                    }
-                };
-    }
-
-    public static class ParsedServiceIntentInfo extends ParsedIntentInfo {
-
-        public ParsedServiceIntentInfo(String packageName, String className) {
-            super(packageName, className);
-        }
-
-        public ParsedServiceIntentInfo(Parcel in) {
-            super(in);
-        }
-
-        public static final Creator<ParsedServiceIntentInfo> CREATOR =
-                new Creator<ParsedServiceIntentInfo>() {
-                    @Override
-                    public ParsedServiceIntentInfo createFromParcel(Parcel source) {
-                        return new ParsedServiceIntentInfo(source);
-                    }
-
-                    @Override
-                    public ParsedServiceIntentInfo[] newArray(int size) {
-                        return new ParsedServiceIntentInfo[size];
-                    }
-                };
-    }
-
-    public static class ParsedProviderIntentInfo extends ParsedIntentInfo {
-
-        public ParsedProviderIntentInfo(String packageName, String className) {
-            super(packageName, className);
-        }
-
-        public ParsedProviderIntentInfo(Parcel in) {
-            super(in);
-        }
-
-        public static final Creator<ParsedProviderIntentInfo> CREATOR =
-                new Creator<ParsedProviderIntentInfo>() {
-                    @Override
-                    public ParsedProviderIntentInfo createFromParcel(Parcel source) {
-                        return new ParsedProviderIntentInfo(source);
-                    }
-
-                    @Override
-                    public ParsedProviderIntentInfo[] newArray(int size) {
-                        return new ParsedProviderIntentInfo[size];
-                    }
-                };
-    }
-
-    public static class ParsedQueriesIntentInfo extends ParsedIntentInfo {
-
-        public ParsedQueriesIntentInfo(String packageName, String className) {
-            super(packageName, className);
-        }
-
-        public ParsedQueriesIntentInfo(Parcel in) {
-            super(in);
-        }
-
-        public static final Creator<ParsedQueriesIntentInfo> CREATOR =
-                new Creator<ParsedQueriesIntentInfo>() {
-                    @Override
-                    public ParsedQueriesIntentInfo createFromParcel(Parcel source) {
-                        return new ParsedQueriesIntentInfo(source);
-                    }
-
-                    @Override
-                    public ParsedQueriesIntentInfo[] newArray(int size) {
-                        return new ParsedQueriesIntentInfo[size];
-                    }
-                };
-    }
-
-    public static class ParsedComponent<IntentInfoType extends ParsedIntentInfo> implements
-            Parcelable {
-
-        // TODO(b/135203078): Replace with "name", as not all usages are an actual class
-        public String className;
-        public int icon;
-        public int labelRes;
-        public CharSequence nonLocalizedLabel;
-        public int logo;
-        public int banner;
-
-        public int descriptionRes;
-
-        // TODO(b/135203078): Make subclass that contains these fields only for the necessary
-        //  subtypes
-        protected boolean enabled = true;
-        protected boolean directBootAware;
-        public int flags;
-
-        private String packageName;
-        private String splitName;
-
-        // TODO(b/135203078): Make nullable
-        public List<IntentInfoType> intents = new ArrayList<>();
-
-        private transient ComponentName componentName;
-
-        protected Bundle metaData;
-
-        public void setSplitName(String splitName) {
-            this.splitName = splitName;
-        }
-
-        public String getSplitName() {
-            return splitName;
-        }
-
-        @CallSuper
-        public void setPackageName(String packageName) {
-            this.packageName = packageName;
-            this.componentName = null;
-        }
-
-        void setPackageNameInternal(String packageName) {
-            this.packageName = packageName;
-            this.componentName = null;
-        }
-
-        public void setEnabled(boolean enabled) {
-            this.enabled = enabled;
-        }
-
-        public String getPackageName() {
-            return packageName;
-        }
-
-        public final boolean isDirectBootAware() {
-            return directBootAware;
-        }
-
-        public final boolean isEnabled() {
-            return enabled;
-        }
-
-        public final String getName() {
-            return className;
-        }
-
-        public final Bundle getMetaData() {
-            return metaData;
-        }
-
-        @UnsupportedAppUsage
-        public ComponentName getComponentName() {
-            if (componentName != null) {
-                return componentName;
-            }
-            if (className != null) {
-                componentName = new ComponentName(getPackageName(),
-                        className);
-            }
-            return componentName;
-        }
-
-        public void setFrom(ParsedComponent other) {
-            this.metaData = other.metaData;
-            this.className = other.className;
-            this.icon = other.icon;
-            this.labelRes = other.labelRes;
-            this.nonLocalizedLabel = other.nonLocalizedLabel;
-            this.logo = other.logo;
-            this.banner = other.banner;
-
-            this.descriptionRes = other.descriptionRes;
-
-            this.enabled = other.enabled;
-            this.directBootAware = other.directBootAware;
-            this.flags = other.flags;
-
-            this.setPackageName(other.packageName);
-            this.setSplitName(other.getSplitName());
-        }
-
-        @Override
-        public int describeContents() {
-            return 0;
-        }
-
-        @Override
-        public void writeToParcel(Parcel dest, int flags) {
-            dest.writeString(this.className);
-            dest.writeInt(this.icon);
-            dest.writeInt(this.labelRes);
-            dest.writeCharSequence(this.nonLocalizedLabel);
-            dest.writeInt(this.logo);
-            dest.writeInt(this.banner);
-            dest.writeInt(this.descriptionRes);
-            dest.writeBoolean(this.enabled);
-            dest.writeBoolean(this.directBootAware);
-            dest.writeInt(this.flags);
-            dest.writeString(this.packageName);
-            dest.writeString(this.splitName);
-            ParsedIntentInfo.writeIntentsList(this.intents, dest, flags);
-            dest.writeBundle(this.metaData);
-        }
-
-        public ParsedComponent() {
-        }
-
-        protected ParsedComponent(Parcel in) {
-            // We use the boot classloader for all classes that we load.
-            final ClassLoader boot = Object.class.getClassLoader();
-            this.className = in.readString();
-            this.icon = in.readInt();
-            this.labelRes = in.readInt();
-            this.nonLocalizedLabel = in.readCharSequence();
-            this.logo = in.readInt();
-            this.banner = in.readInt();
-            this.descriptionRes = in.readInt();
-            this.enabled = in.readByte() != 0;
-            this.directBootAware = in.readByte() != 0;
-            this.flags = in.readInt();
-            this.packageName = in.readString();
-            this.splitName = in.readString();
-            this.intents = ParsedIntentInfo.createIntentsList(in);
-            this.metaData = in.readBundle(boot);
-        }
-    }
-
-    // TODO(b/135203078): Document this. Maybe split out ParsedComponent to be actual components
-    //  that can have their own processes, rather than something like permission which cannot.
-    public static class ParsedMainComponent<IntentInfoType extends ParsedIntentInfo> extends
-            ParsedComponent<IntentInfoType> {
-
-        private String processName;
-        private String permission;
-
-        public void setProcessName(String appProcessName, String processName) {
-            // TODO(b/135203078): Is this even necessary anymore?
-            this.processName = TextUtils.safeIntern(
-                    processName == null ? appProcessName : processName);
-        }
-
-        public String getProcessName() {
-            return processName;
-        }
-
-        public void setPermission(String permission) {
-            // Empty string must be converted to null
-            this.permission = TextUtils.isEmpty(permission) ? null : permission.intern();
-        }
-
-        public String getPermission() {
-            return permission;
-        }
-
-        @Override
-        public void setFrom(ParsedComponent other) {
-            super.setFrom(other);
-            if (other instanceof ParsedMainComponent) {
-                ParsedMainComponent otherMainComponent = (ParsedMainComponent) other;
-                this.setProcessName(otherMainComponent.getProcessName(),
-                        otherMainComponent.getProcessName());
-                this.setPermission(otherMainComponent.getPermission());
-            }
-        }
-
-        @Override
-        public int describeContents() {
-            return 0;
-        }
-
-        @Override
-        public void writeToParcel(Parcel dest, int flags) {
-            super.writeToParcel(dest, flags);
-            dest.writeString(this.processName);
-            dest.writeString(this.permission);
-        }
-
-        public ParsedMainComponent() {
-        }
-
-        protected ParsedMainComponent(Parcel in) {
-            super(in);
-            this.processName = TextUtils.safeIntern(in.readString());
-            this.permission = TextUtils.safeIntern(in.readString());
-        }
-
-        public static final Creator<ParsedMainComponent> CREATOR =
-                new Creator<ParsedMainComponent>() {
-                    @Override
-                    public ParsedMainComponent createFromParcel(Parcel source) {
-                        return new ParsedMainComponent(source);
-                    }
-
-                    @Override
-                    public ParsedMainComponent[] newArray(int size) {
-                        return new ParsedMainComponent[size];
-                    }
-                };
-    }
-
-    public static class ParsedActivity extends ParsedMainComponent<ParsedActivityIntentInfo>
-            implements Parcelable {
-
-        public boolean exported;
-        public int theme;
-        public int uiOptions;
-
-        public String targetActivity;
-
-        public String parentActivityName;
-        public String taskAffinity;
-        public int privateFlags;
-
-        public int launchMode;
-        public int documentLaunchMode;
-        public int maxRecents;
-        public int configChanges;
-        public int softInputMode;
-        public int persistableMode;
-        public int lockTaskLaunchMode;
-
-        public int screenOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
-        public int resizeMode = ActivityInfo.RESIZE_MODE_RESIZEABLE;
-
-        public float maxAspectRatio;
-        public boolean hasMaxAspectRatio;
-
-        public float minAspectRatio;
-        public boolean hasMinAspectRatio;
-
-        public String requestedVrComponent;
-        public int rotationAnimation = -1;
-        public int colorMode;
-        public boolean preferMinimalPostProcessing;
-        public int order;
-
-        public ActivityInfo.WindowLayout windowLayout;
-
-        @Override
-        public void setPackageName(String packageName) {
-            super.setPackageName(packageName);
-            for (ParsedIntentInfo intent : this.intents) {
-                intent.packageName = packageName;
-            }
-        }
-
-        public boolean hasMaxAspectRatio() {
-            return hasMaxAspectRatio;
-        }
-
-        public boolean hasMinAspectRatio() {
-            return hasMinAspectRatio;
-        }
-
-        public void setMaxAspectRatio(int resizeMode, float maxAspectRatio) {
-            if (resizeMode == ActivityInfo.RESIZE_MODE_RESIZEABLE
-                    || resizeMode == ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION) {
-                // Resizeable activities can be put in any aspect ratio.
-                return;
-            }
-
-            if (maxAspectRatio < 1.0f && maxAspectRatio != 0) {
-                // Ignore any value lesser than 1.0.
-                return;
-            }
-
-            this.maxAspectRatio = maxAspectRatio;
-            hasMaxAspectRatio = true;
-        }
-
-        public void setMinAspectRatio(int resizeMode, float minAspectRatio) {
-            if (resizeMode == RESIZE_MODE_RESIZEABLE
-                    || resizeMode == RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION) {
-                // Resizeable activities can be put in any aspect ratio.
-                return;
-            }
-
-            if (minAspectRatio < 1.0f && minAspectRatio != 0) {
-                // Ignore any value lesser than 1.0.
-                return;
-            }
-
-            this.minAspectRatio = minAspectRatio;
-            hasMinAspectRatio = true;
-        }
-
-        public void addIntent(ParsedActivityIntentInfo intent) {
-            this.intents.add(intent);
-        }
-
-        @Override
-        public int describeContents() {
-            return 0;
-        }
-
-        @Override
-        public void writeToParcel(Parcel dest, int flags) {
-            super.writeToParcel(dest, flags);
-            dest.writeBoolean(this.exported);
-            dest.writeInt(this.theme);
-            dest.writeInt(this.uiOptions);
-            dest.writeString(this.targetActivity);
-            dest.writeString(this.parentActivityName);
-            dest.writeString(this.taskAffinity);
-            dest.writeInt(this.privateFlags);
-            dest.writeInt(this.launchMode);
-            dest.writeInt(this.documentLaunchMode);
-            dest.writeInt(this.maxRecents);
-            dest.writeInt(this.configChanges);
-            dest.writeInt(this.softInputMode);
-            dest.writeInt(this.persistableMode);
-            dest.writeInt(this.lockTaskLaunchMode);
-            dest.writeInt(this.screenOrientation);
-            dest.writeInt(this.resizeMode);
-            dest.writeFloat(this.maxAspectRatio);
-            dest.writeBoolean(this.hasMaxAspectRatio);
-            dest.writeFloat(this.minAspectRatio);
-            dest.writeBoolean(this.hasMinAspectRatio);
-            dest.writeString(this.requestedVrComponent);
-            dest.writeInt(this.rotationAnimation);
-            dest.writeInt(this.colorMode);
-            dest.writeBoolean(this.preferMinimalPostProcessing);
-            dest.writeInt(this.order);
-            dest.writeBundle(this.metaData);
-
-            if (windowLayout != null) {
-                dest.writeInt(1);
-                dest.writeInt(windowLayout.width);
-                dest.writeFloat(windowLayout.widthFraction);
-                dest.writeInt(windowLayout.height);
-                dest.writeFloat(windowLayout.heightFraction);
-                dest.writeInt(windowLayout.gravity);
-                dest.writeInt(windowLayout.minWidth);
-                dest.writeInt(windowLayout.minHeight);
-            } else {
-                dest.writeInt(0);
-            }
-        }
-
-        public ParsedActivity() {
-        }
-
-        protected ParsedActivity(Parcel in) {
-            super(in);
-            this.exported = in.readByte() != 0;
-            this.theme = in.readInt();
-            this.uiOptions = in.readInt();
-            this.targetActivity = in.readString();
-            this.parentActivityName = in.readString();
-            this.taskAffinity = in.readString();
-            this.privateFlags = in.readInt();
-            this.launchMode = in.readInt();
-            this.documentLaunchMode = in.readInt();
-            this.maxRecents = in.readInt();
-            this.configChanges = in.readInt();
-            this.softInputMode = in.readInt();
-            this.persistableMode = in.readInt();
-            this.lockTaskLaunchMode = in.readInt();
-            this.screenOrientation = in.readInt();
-            this.resizeMode = in.readInt();
-            this.maxAspectRatio = in.readFloat();
-            this.hasMaxAspectRatio = in.readByte() != 0;
-            this.minAspectRatio = in.readFloat();
-            this.hasMinAspectRatio = in.readByte() != 0;
-            this.requestedVrComponent = in.readString();
-            this.rotationAnimation = in.readInt();
-            this.colorMode = in.readInt();
-            this.preferMinimalPostProcessing = in.readByte() != 0;
-            this.order = in.readInt();
-            this.metaData = in.readBundle();
-            if (in.readInt() == 1) {
-                windowLayout = new ActivityInfo.WindowLayout(in);
-            }
-        }
-
-        public static final Creator<ParsedActivity> CREATOR = new Creator<ParsedActivity>() {
-            @Override
-            public ParsedActivity createFromParcel(Parcel source) {
-                return new ParsedActivity(source);
-            }
-
-            @Override
-            public ParsedActivity[] newArray(int size) {
-                return new ParsedActivity[size];
-            }
-        };
-    }
-
-    public static class ParsedService extends ParsedMainComponent<ParsedServiceIntentInfo> {
-
-        public boolean exported;
-        public int flags;
-        public int foregroundServiceType;
-        public int order;
-
-        @Override
-        public void setPackageName(String packageName) {
-            super.setPackageName(packageName);
-            for (ParsedIntentInfo intent : this.intents) {
-                intent.packageName = packageName;
-            }
-        }
-
-        @Override
-        public int describeContents() {
-            return 0;
-        }
-
-        @Override
-        public void writeToParcel(Parcel dest, int flags) {
-            super.writeToParcel(dest, flags);
-            dest.writeBoolean(this.exported);
-            dest.writeBundle(this.metaData);
-            dest.writeInt(this.flags);
-            dest.writeInt(this.foregroundServiceType);
-            dest.writeInt(this.order);
-        }
-
-        public ParsedService() {
-        }
-
-        protected ParsedService(Parcel in) {
-            super(in);
-            this.exported = in.readByte() != 0;
-            this.metaData = in.readBundle();
-            this.flags = in.readInt();
-            this.foregroundServiceType = in.readInt();
-            this.order = in.readInt();
-        }
-
-        public static final Creator<ParsedService> CREATOR = new Creator<ParsedService>() {
-            @Override
-            public ParsedService createFromParcel(Parcel source) {
-                return new ParsedService(source);
-            }
-
-            @Override
-            public ParsedService[] newArray(int size) {
-                return new ParsedService[size];
-            }
-        };
-    }
-
-    public static class ParsedProvider extends ParsedMainComponent<ParsedProviderIntentInfo> {
-
-        protected boolean exported;
-        protected int flags;
-        protected int order;
-        private String authority;
-        protected boolean isSyncable;
-        private String readPermission;
-        private String writePermission;
-        protected boolean grantUriPermissions;
-        protected boolean forceUriPermissions;
-        protected boolean multiProcess;
-        protected int initOrder;
-        protected PatternMatcher[] uriPermissionPatterns;
-        protected PathPermission[] pathPermissions;
-
-        public ParsedProvider(ParsedProvider other) {
-            this.setFrom(other);
-        }
-
-        protected void setFrom(ParsedProvider other) {
-            super.setFrom(other);
-            this.exported = other.exported;
-
-            this.intents.clear();
-            if (other.intents != null) {
-                this.intents.addAll(other.intents);
-            }
-
-            this.flags = other.flags;
-            this.order = other.order;
-            this.setAuthority(other.getAuthority());
-            this.isSyncable = other.isSyncable;
-            this.setReadPermission(other.getReadPermission());
-            this.setWritePermission(other.getWritePermission());
-            this.grantUriPermissions = other.grantUriPermissions;
-            this.forceUriPermissions = other.forceUriPermissions;
-            this.multiProcess = other.multiProcess;
-            this.initOrder = other.initOrder;
-            this.uriPermissionPatterns = other.uriPermissionPatterns;
-            this.pathPermissions = other.pathPermissions;
-        }
-
-        @Override
-        public void setPackageName(String packageName) {
-            super.setPackageName(packageName);
-            for (ParsedIntentInfo intent : this.intents) {
-                intent.packageName = packageName;
-            }
-        }
-
-        public boolean isExported() {
-            return exported;
-        }
-
-        @VisibleForTesting
-        public void setExported(boolean exported) {
-            this.exported = exported;
-        }
-
-        public List<ParsedProviderIntentInfo> getIntents() {
-            return intents;
-        }
-
-        public int getFlags() {
-            return flags;
-        }
-
-        public int getOrder() {
-            return order;
-        }
-
-        public void setAuthority(String authority) {
-            this.authority = TextUtils.safeIntern(authority);
-        }
-
-        public String getAuthority() {
-            return authority;
-        }
-
-        public void setSyncable(boolean isSyncable) {
-            this.isSyncable = isSyncable;
-        }
-
-        public boolean isSyncable() {
-            return isSyncable;
-        }
-
-        public void setReadPermission(String readPermission) {
-            // Empty string must be converted to null
-            this.readPermission = TextUtils.isEmpty(readPermission)
-                    ? null : readPermission.intern();
-        }
-
-        public String getReadPermission() {
-            return readPermission;
-        }
-
-        public void setWritePermission(String writePermission) {
-            // Empty string must be converted to null
-            this.writePermission = TextUtils.isEmpty(writePermission)
-                    ? null : writePermission.intern();
-        }
-
-        public String getWritePermission() {
-            return writePermission;
-        }
-
-        public boolean isGrantUriPermissions() {
-            return grantUriPermissions;
-        }
-
-        public boolean isForceUriPermissions() {
-            return forceUriPermissions;
-        }
-
-        public boolean isMultiProcess() {
-            return multiProcess;
-        }
-
-        public int getInitOrder() {
-            return initOrder;
-        }
-
-        public PatternMatcher[] getUriPermissionPatterns() {
-            return uriPermissionPatterns;
-        }
-
-        public PathPermission[] getPathPermissions() {
-            return pathPermissions;
-        }
-
-        @Override
-        public int describeContents() {
-            return 0;
-        }
-
-        @Override
-        public void writeToParcel(Parcel dest, int flags) {
-            super.writeToParcel(dest, flags);
-            dest.writeBoolean(this.exported);
-            dest.writeInt(this.flags);
-            dest.writeInt(this.order);
-            dest.writeString(this.authority);
-            dest.writeBoolean(this.isSyncable);
-            dest.writeString(this.readPermission);
-            dest.writeString(this.writePermission);
-            dest.writeBoolean(this.grantUriPermissions);
-            dest.writeBoolean(this.forceUriPermissions);
-            dest.writeBoolean(this.multiProcess);
-            dest.writeInt(this.initOrder);
-            dest.writeTypedArray(this.uriPermissionPatterns, flags);
-            dest.writeTypedArray(this.pathPermissions, flags);
-        }
-
-        public ParsedProvider() {
-        }
-
-        protected ParsedProvider(Parcel in) {
-            super(in);
-            this.exported = in.readByte() != 0;
-            this.flags = in.readInt();
-            this.order = in.readInt();
-            this.authority = TextUtils.safeIntern(in.readString());
-            this.isSyncable = in.readByte() != 0;
-            this.readPermission = TextUtils.safeIntern(in.readString());
-            this.writePermission = TextUtils.safeIntern(in.readString());
-            this.grantUriPermissions = in.readByte() != 0;
-            this.forceUriPermissions = in.readByte() != 0;
-            this.multiProcess = in.readByte() != 0;
-            this.initOrder = in.readInt();
-            this.uriPermissionPatterns = in.createTypedArray(PatternMatcher.CREATOR);
-            this.pathPermissions = in.createTypedArray(PathPermission.CREATOR);
-        }
-
-        public static final Creator<ParsedProvider> CREATOR = new Creator<ParsedProvider>() {
-            @Override
-            public ParsedProvider createFromParcel(Parcel source) {
-                return new ParsedProvider(source);
-            }
-
-            @Override
-            public ParsedProvider[] newArray(int size) {
-                return new ParsedProvider[size];
-            }
-        };
-    }
-
-    /**
-     * A {@link android.R.styleable#AndroidManifestFeature &lt;feature&gt;} tag parsed from the
-     * manifest.
-     */
-    // @DataClass verifier is broken, hence comment out for now
-    public static class ParsedFeature implements Parcelable {
-        /** Maximum length of featureId */
-        public static final int MAX_FEATURE_ID_LEN = 50;
-
-        /** Maximum amount of features per package */
-        private static final int MAX_NUM_FEATURES = 1000;
-
-        /** Id of the feature */
-        public final @NonNull String id;
-
-        /** User visible label fo the feature */
-        public final @StringRes int label;
-
-        /** Ids of previously declared features this feature inherits from */
-        public final @NonNull List<String> inheritFrom;
-
-        /**
-         * @return Is this set of features a valid combination for a single package?
-         */
-        public static boolean isCombinationValid(@Nullable List<ParsedFeature> features) {
-            if (features == null) {
-                return true;
-            }
-
-            ArraySet<String> featureIds = new ArraySet<>(features.size());
-            ArraySet<String> inheritFromFeatureIds = new ArraySet<>();
-
-            int numFeatures = features.size();
-            if (numFeatures > MAX_NUM_FEATURES) {
-                return false;
-            }
-
-            for (int featureNum = 0; featureNum < numFeatures; featureNum++) {
-                boolean wasAdded = featureIds.add(features.get(featureNum).id);
-                if (!wasAdded) {
-                    // feature id is not unique
-                    return false;
-                }
-            }
-
-            for (int featureNum = 0; featureNum < numFeatures; featureNum++) {
-                ParsedFeature feature = features.get(featureNum);
-
-                int numInheritFrom = feature.inheritFrom.size();
-                for (int inheritFromNum = 0; inheritFromNum < numInheritFrom; inheritFromNum++) {
-                    String inheritFrom = feature.inheritFrom.get(inheritFromNum);
-
-                    if (featureIds.contains(inheritFrom)) {
-                        // Cannot inherit from a feature that is still defined
-                        return false;
-                    }
-
-                    boolean wasAdded = inheritFromFeatureIds.add(inheritFrom);
-                    if (!wasAdded) {
-                        // inheritFrom is not unique
-                        return false;
-                    }
-                }
-            }
-
-            return true;
-        }
-
-
-
-        // Code below generated by codegen v1.0.14.
-        //
-        // DO NOT MODIFY!
-        // CHECKSTYLE:OFF Generated code
-        //
-        // To regenerate run:
-        // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/parsing/ComponentParseUtils.java
-        //
-        // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
-        //   Settings > Editor > Code Style > Formatter Control
-        //@formatter:off
-
-
-        /**
-         * Creates a new ParsedFeature.
-         *
-         * @param id
-         *   Id of the feature
-         * @param label
-         *   User visible label fo the feature (if defined as resource)
-         * @param inheritFrom
-         *   Ids of previously declared features this feature inherits from
-         */
-        @DataClass.Generated.Member
-        public ParsedFeature(
-                @NonNull String id,
-                @StringRes int label,
-                @NonNull List<String> inheritFrom) {
-            this.id = id;
-            com.android.internal.util.AnnotationValidations.validate(
-                    NonNull.class, null, id);
-            this.label = label;
-            com.android.internal.util.AnnotationValidations.validate(
-                    StringRes.class, null, label);
-            this.inheritFrom = inheritFrom;
-            com.android.internal.util.AnnotationValidations.validate(
-                    NonNull.class, null, inheritFrom);
-
-            // onConstructed(); // You can define this method to get a callback
-        }
-
-        @Override
-        @DataClass.Generated.Member
-        public void writeToParcel(@NonNull Parcel dest, int flags) {
-            // You can override field parcelling by defining methods like:
-            // void parcelFieldName(Parcel dest, int flags) { ... }
-
-            dest.writeString(id);
-            dest.writeInt(label);
-            dest.writeStringList(inheritFrom);
-        }
-
-        @Override
-        @DataClass.Generated.Member
-        public int describeContents() { return 0; }
-
-        /** @hide */
-        @SuppressWarnings({"unchecked", "RedundantCast"})
-        @DataClass.Generated.Member
-        protected ParsedFeature(@NonNull Parcel in) {
-            // You can override field unparcelling by defining methods like:
-            // static FieldType unparcelFieldName(Parcel in) { ... }
-
-            String _id = in.readString();
-            int _label = in.readInt();
-            List<String> _inheritFrom = new ArrayList<>();
-            in.readStringList(_inheritFrom);
-
-            this.id = _id;
-            com.android.internal.util.AnnotationValidations.validate(
-                    NonNull.class, null, id);
-            this.label = _label;
-            com.android.internal.util.AnnotationValidations.validate(
-                    StringRes.class, null, label);
-            this.inheritFrom = _inheritFrom;
-            com.android.internal.util.AnnotationValidations.validate(
-                    NonNull.class, null, inheritFrom);
-
-            // onConstructed(); // You can define this method to get a callback
-        }
-
-        @DataClass.Generated.Member
-        public static final @NonNull Parcelable.Creator<ParsedFeature> CREATOR
-                = new Parcelable.Creator<ParsedFeature>() {
-            @Override
-            public ParsedFeature[] newArray(int size) {
-                return new ParsedFeature[size];
-            }
-
-            @Override
-            public ParsedFeature createFromParcel(@NonNull Parcel in) {
-                return new ParsedFeature(in);
-            }
-        };
-
-        /*@DataClass.Generated(
-                time = 1576783172965L,
-                codegenVersion = "1.0.14",
-                sourceFile = "frameworks/base/core/java/android/content/pm/parsing/ComponentParseUtils.java",
-                inputSignatures = "public final @android.annotation.NonNull java.lang.String id\npublic final @android.annotation.StringRes int label\npublic final @android.annotation.NonNull java.util.List<java.lang.String> inheritFrom\npublic static  boolean isCombinationValid(java.util.List<android.content.pm.parsing.ParsedFeature>)\nclass ParsedFeature extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass")
-         */
-        @Deprecated
-        private void __metadata() {}
-
-
-        //@formatter:on
-        // End of generated code
-
-    }
-
-    public static class ParsedPermission extends ParsedComponent<ParsedIntentInfo> {
-
-        public String backgroundPermission;
-        private String group;
-        public int requestRes;
-        public int protectionLevel;
-        public boolean tree;
-
-        public ParsedPermissionGroup parsedPermissionGroup;
-
-        public void setName(String className) {
-            this.className = className;
-        }
-
-        public void setGroup(String group) {
-            this.group = TextUtils.safeIntern(group);
-        }
-
-        public String getGroup() {
-            return group;
-        }
-
-        public boolean isRuntime() {
-            return getProtection() == PermissionInfo.PROTECTION_DANGEROUS;
-        }
-
-        public boolean isAppOp() {
-            return (protectionLevel & PermissionInfo.PROTECTION_FLAG_APPOP) != 0;
-        }
-
-        @PermissionInfo.Protection
-        public int getProtection() {
-            return protectionLevel & PermissionInfo.PROTECTION_MASK_BASE;
-        }
-
-        public int getProtectionFlags() {
-            return protectionLevel & ~PermissionInfo.PROTECTION_MASK_BASE;
-        }
-
-        public int calculateFootprint() {
-            int size = getName().length();
-            if (nonLocalizedLabel != null) {
-                size += nonLocalizedLabel.length();
-            }
-            return size;
-        }
-
-        public ParsedPermission() {
-        }
-
-        public ParsedPermission(ParsedPermission other) {
-            // TODO(b/135203078): Better way to copy this? Maybe refactor to the point where copy
-            //  isn't needed.
-            this.className = other.className;
-            this.icon = other.icon;
-            this.labelRes = other.labelRes;
-            this.nonLocalizedLabel = other.nonLocalizedLabel;
-            this.logo = other.logo;
-            this.banner = other.banner;
-            this.descriptionRes = other.descriptionRes;
-            this.enabled = other.enabled;
-            this.directBootAware = other.directBootAware;
-            this.flags = other.flags;
-            this.setSplitName(other.getSplitName());
-            this.setPackageName(other.getPackageName());
-
-            this.intents.addAll(other.intents);
-
-            if (other.metaData != null) {
-                this.metaData = new Bundle();
-                this.metaData.putAll(other.metaData);
-            }
-
-            this.backgroundPermission = other.backgroundPermission;
-            this.setGroup(other.group);
-            this.requestRes = other.requestRes;
-            this.protectionLevel = other.protectionLevel;
-            this.tree = other.tree;
-
-            this.parsedPermissionGroup = other.parsedPermissionGroup;
-        }
-
-        @Override
-        public int describeContents() {
-            return 0;
-        }
-
-        @Override
-        public void writeToParcel(Parcel dest, int flags) {
-            super.writeToParcel(dest, flags);
-            dest.writeString(this.backgroundPermission);
-            dest.writeString(this.group);
-            dest.writeInt(this.requestRes);
-            dest.writeInt(this.protectionLevel);
-            dest.writeBoolean(this.tree);
-            dest.writeParcelable(this.parsedPermissionGroup, flags);
-        }
-
-        protected ParsedPermission(Parcel in) {
-            super(in);
-            // We use the boot classloader for all classes that we load.
-            final ClassLoader boot = Object.class.getClassLoader();
-            this.backgroundPermission = in.readString();
-            this.group = TextUtils.safeIntern(in.readString());
-            this.requestRes = in.readInt();
-            this.protectionLevel = in.readInt();
-            this.tree = in.readBoolean();
-            this.parsedPermissionGroup = in.readParcelable(boot);
-        }
-
-        public static final Creator<ParsedPermission> CREATOR = new Creator<ParsedPermission>() {
-            @Override
-            public ParsedPermission createFromParcel(Parcel source) {
-                return new ParsedPermission(source);
-            }
-
-            @Override
-            public ParsedPermission[] newArray(int size) {
-                return new ParsedPermission[size];
-            }
-        };
-    }
-
-    public static class ParsedPermissionGroup extends ParsedComponent<ParsedIntentInfo> {
-
-        public int requestDetailResourceId;
-        public int backgroundRequestResourceId;
-        public int backgroundRequestDetailResourceId;
-
-        public int requestRes;
-        public int priority;
-
-        @Override
-        public int describeContents() {
-            return 0;
-        }
-
-        @Override
-        public void writeToParcel(Parcel dest, int flags) {
-            super.writeToParcel(dest, flags);
-            dest.writeInt(this.requestDetailResourceId);
-            dest.writeInt(this.backgroundRequestResourceId);
-            dest.writeInt(this.backgroundRequestDetailResourceId);
-            dest.writeInt(this.requestRes);
-            dest.writeInt(this.priority);
-        }
-
-        public ParsedPermissionGroup() {
-        }
-
-        protected ParsedPermissionGroup(Parcel in) {
-            super(in);
-            this.requestDetailResourceId = in.readInt();
-            this.backgroundRequestResourceId = in.readInt();
-            this.backgroundRequestDetailResourceId = in.readInt();
-            this.requestRes = in.readInt();
-            this.priority = in.readInt();
-        }
-
-        public static final Creator<ParsedPermissionGroup> CREATOR =
-                new Creator<ParsedPermissionGroup>() {
-                    @Override
-                    public ParsedPermissionGroup createFromParcel(Parcel source) {
-                        return new ParsedPermissionGroup(source);
-                    }
-
-                    @Override
-                    public ParsedPermissionGroup[] newArray(int size) {
-                        return new ParsedPermissionGroup[size];
-                    }
-                };
-    }
-
-    public static class ParsedInstrumentation extends ParsedComponent<ParsedIntentInfo> {
-
-        private String targetPackage;
-        private String targetProcesses;
-        public boolean handleProfiling;
-        public boolean functionalTest;
-
-        public ParsedInstrumentation() {
-        }
-
-        public void setTargetPackage(String targetPackage) {
-            this.targetPackage = TextUtils.safeIntern(targetPackage);
-        }
-
-        public String getTargetPackage() {
-            return targetPackage;
-        }
-
-        public void setTargetProcesses(String targetProcesses) {
-            this.targetProcesses = TextUtils.safeIntern(targetProcesses);
-        }
-
-        public String getTargetProcesses() {
-            return targetProcesses;
-        }
-
-        @Override
-        public int describeContents() {
-            return 0;
-        }
-
-        @Override
-        public void writeToParcel(Parcel dest, int flags) {
-            super.writeToParcel(dest, flags);
-            dest.writeString(this.targetPackage);
-            dest.writeString(this.targetProcesses);
-            dest.writeBoolean(this.handleProfiling);
-            dest.writeBoolean(this.functionalTest);
-        }
-
-        protected ParsedInstrumentation(Parcel in) {
-            super(in);
-            this.targetPackage = TextUtils.safeIntern(in.readString());
-            this.targetProcesses = TextUtils.safeIntern(in.readString());
-            this.handleProfiling = in.readByte() != 0;
-            this.functionalTest = in.readByte() != 0;
-        }
-
-        public static final Creator<ParsedInstrumentation> CREATOR =
-                new Creator<ParsedInstrumentation>() {
-                    @Override
-                    public ParsedInstrumentation createFromParcel(Parcel source) {
-                        return new ParsedInstrumentation(source);
-                    }
-
-                    @Override
-                    public ParsedInstrumentation[] newArray(int size) {
-                        return new ParsedInstrumentation[size];
-                    }
-                };
-    }
-
-    public static class ParsedProcess implements Parcelable {
-
-        public String name;
-        @Nullable
-        public ArraySet<String> deniedPermissions;
-
-        @Override
-        public int describeContents() {
-            return 0;
-        }
-
-        @Override
-        public void writeToParcel(Parcel dest, int flags) {
-            dest.writeString(this.name);
-            final int numDenied = this.deniedPermissions != null
-                    ? this.deniedPermissions.size() : 0;
-            dest.writeInt(numDenied);
-            for (int i = 0; i < numDenied; i++) {
-                dest.writeString(this.deniedPermissions.valueAt(i));
-            }
-        }
-
-        public ParsedProcess() {
-        }
-
-        public ParsedProcess(@NonNull ParsedProcess other) {
-            name = other.name;
-            if (other.deniedPermissions != null) {
-                deniedPermissions = new ArraySet<>(other.deniedPermissions);
-            }
-        }
-
-        public void addStateFrom(@NonNull ParsedProcess other) {
-            if (other.deniedPermissions != null) {
-                for (int i = other.deniedPermissions.size() - 1; i >= 0; i--) {
-                    if (deniedPermissions == null) {
-                        deniedPermissions = new ArraySet<>(other.deniedPermissions.size());
-                    }
-                    deniedPermissions.add(other.deniedPermissions.valueAt(i));
-                }
-            }
-        }
-
-        protected ParsedProcess(Parcel in) {
-            this.name = TextUtils.safeIntern(in.readString());
-            final int numDenied = in.readInt();
-            if (numDenied > 0) {
-                this.deniedPermissions = new ArraySet<>(numDenied);
-                this.deniedPermissions.add(TextUtils.safeIntern(in.readString()));
-            }
-        }
-
-        public static final Creator<ParsedProcess> CREATOR =
-                new Creator<ParsedProcess>() {
-                    @Override
-                    public ParsedProcess createFromParcel(Parcel source) {
-                        return new ParsedProcess(source);
-                    }
-
-                    @Override
-                    public ParsedProcess[] newArray(int size) {
-                        return new ParsedProcess[size];
-                    }
-                };
-    }
-
-    public static ParsedActivity parseActivity(
-            String[] separateProcesses,
-            ParsingPackage parsingPackage,
-            Resources res,
-            XmlResourceParser parser, int flags, String[] outError,
-            boolean receiver, boolean hardwareAccelerated)
-            throws XmlPullParserException, IOException {
-
-        TypedArray sa = null;
-        boolean visibleToEphemeral;
-        boolean setExported;
-
-        int targetSdkVersion = parsingPackage.getTargetSdkVersion();
-        String packageName = parsingPackage.getPackageName();
-        String packageProcessName = parsingPackage.getProcessName();
-        ParsedActivity result = new ParsedActivity();
-
-        try {
-            sa = res.obtainAttributes(parser, R.styleable.AndroidManifestActivity);
-
-            String tag = receiver ? "<receiver>" : "<activity>";
-
-            String name = sa.getNonConfigurationString(R.styleable.AndroidManifestActivity_name, 0);
-            if (name == null) {
-                outError[0] = tag + " does not specify android:name";
-                return null;
-            } else {
-                String className = ApkParseUtils.buildClassName(packageName, name);
-                if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) {
-                    outError[0] = tag + " invalid android:name";
-                    return null;
-                } else if (className == null) {
-                    outError[0] = "Empty class name in package " + packageName;
-                    return null;
-                }
-
-                result.className = className;
-            }
-
-            int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId(
-                    R.styleable.AndroidManifestActivity_roundIcon, 0) : 0;
-            if (roundIconVal != 0) {
-                result.icon = roundIconVal;
-                result.nonLocalizedLabel = null;
-            } else {
-                int iconVal = sa.getResourceId(R.styleable.AndroidManifestActivity_icon, 0);
-                if (iconVal != 0) {
-                    result.icon = iconVal;
-                    result.nonLocalizedLabel = null;
-                }
-            }
-
-            int logoVal = sa.getResourceId(R.styleable.AndroidManifestActivity_logo, 0);
-            if (logoVal != 0) {
-                result.logo = logoVal;
-            }
-
-            int bannerVal = sa.getResourceId(R.styleable.AndroidManifestActivity_banner, 0);
-            if (bannerVal != 0) {
-                result.banner = bannerVal;
-            }
-
-            TypedValue v = sa.peekValue(R.styleable.AndroidManifestActivity_label);
-            if (v != null && (result.labelRes = v.resourceId) == 0) {
-                result.nonLocalizedLabel = v.coerceToString();
-            }
-
-            result.setPackageNameInternal(packageName);
-
-            CharSequence pname;
-            if (parsingPackage.getTargetSdkVersion() >= Build.VERSION_CODES.FROYO) {
-                pname = sa.getNonConfigurationString(R.styleable.AndroidManifestActivity_process,
-                        Configuration.NATIVE_CONFIG_VERSION);
-            } else {
-                // Some older apps have been seen to use a resource reference
-                // here that on older builds was ignored (with a warning).  We
-                // need to continue to do this for them so they don't break.
-                pname = sa.getNonResourceString(R.styleable.AndroidManifestActivity_process);
-            }
-
-            result.setProcessName(packageProcessName, PackageParser.buildProcessName(packageName,
-                    packageProcessName, pname,
-                    flags, separateProcesses, outError));
-
-            result.descriptionRes = sa.getResourceId(
-                    R.styleable.AndroidManifestActivity_description, 0);
-
-            result.enabled = sa.getBoolean(R.styleable.AndroidManifestActivity_enabled, true);
-
-            setExported = sa.hasValue(R.styleable.AndroidManifestActivity_exported);
-            if (setExported) {
-                result.exported = sa.getBoolean(R.styleable.AndroidManifestActivity_exported,
-                        false);
-            }
-
-            result.theme = sa.getResourceId(R.styleable.AndroidManifestActivity_theme, 0);
-
-            result.uiOptions = sa.getInt(R.styleable.AndroidManifestActivity_uiOptions,
-                    parsingPackage.getUiOptions());
-
-            String parentName = sa.getNonConfigurationString(
-                    R.styleable.AndroidManifestActivity_parentActivityName,
-                    Configuration.NATIVE_CONFIG_VERSION);
-            if (parentName != null) {
-                String parentClassName = ApkParseUtils.buildClassName(packageName, parentName);
-                if (parentClassName == null) {
-                    Log.e(TAG,
-                            "Activity " + result.className
-                                    + " specified invalid parentActivityName " +
-                                    parentName);
-                } else {
-                    result.parentActivityName = parentClassName;
-                }
-            }
-
-            String str;
-            str = sa.getNonConfigurationString(R.styleable.AndroidManifestActivity_permission, 0);
-            if (str == null) {
-                result.setPermission(parsingPackage.getPermission());
-            } else {
-                result.setPermission(str);
-            }
-
-            str = sa.getNonConfigurationString(
-                    R.styleable.AndroidManifestActivity_taskAffinity,
-                    Configuration.NATIVE_CONFIG_VERSION);
-            result.taskAffinity = PackageParser.buildTaskAffinityName(
-                    packageName,
-                    parsingPackage.getTaskAffinity(), str, outError);
-
-            result.setSplitName(
-                    sa.getNonConfigurationString(R.styleable.AndroidManifestActivity_splitName, 0));
-
-            result.flags = 0;
-            if (sa.getBoolean(
-                    R.styleable.AndroidManifestActivity_multiprocess, false)) {
-                result.flags |= ActivityInfo.FLAG_MULTIPROCESS;
-            }
-
-            if (sa.getBoolean(R.styleable.AndroidManifestActivity_finishOnTaskLaunch, false)) {
-                result.flags |= ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH;
-            }
-
-            if (sa.getBoolean(R.styleable.AndroidManifestActivity_clearTaskOnLaunch, false)) {
-                result.flags |= ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH;
-            }
-
-            if (sa.getBoolean(R.styleable.AndroidManifestActivity_noHistory, false)) {
-                result.flags |= ActivityInfo.FLAG_NO_HISTORY;
-            }
-
-            if (sa.getBoolean(R.styleable.AndroidManifestActivity_alwaysRetainTaskState, false)) {
-                result.flags |= ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE;
-            }
-
-            if (sa.getBoolean(R.styleable.AndroidManifestActivity_stateNotNeeded, false)) {
-                result.flags |= ActivityInfo.FLAG_STATE_NOT_NEEDED;
-            }
-
-            if (sa.getBoolean(R.styleable.AndroidManifestActivity_excludeFromRecents, false)) {
-                result.flags |= ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS;
-            }
-
-            if (sa.getBoolean(R.styleable.AndroidManifestActivity_allowTaskReparenting,
-                    (parsingPackage.getFlags() & ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING)
-                            != 0)) {
-                result.flags |= ActivityInfo.FLAG_ALLOW_TASK_REPARENTING;
-            }
-
-            if (sa.getBoolean(R.styleable.AndroidManifestActivity_finishOnCloseSystemDialogs,
-                    false)) {
-                result.flags |= ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS;
-            }
-
-            if (sa.getBoolean(R.styleable.AndroidManifestActivity_showOnLockScreen, false)
-                    || sa.getBoolean(R.styleable.AndroidManifestActivity_showForAllUsers, false)) {
-                result.flags |= ActivityInfo.FLAG_SHOW_FOR_ALL_USERS;
-            }
-
-            if (sa.getBoolean(R.styleable.AndroidManifestActivity_immersive, false)) {
-                result.flags |= ActivityInfo.FLAG_IMMERSIVE;
-            }
-
-            if (sa.getBoolean(R.styleable.AndroidManifestActivity_systemUserOnly, false)) {
-                result.flags |= ActivityInfo.FLAG_SYSTEM_USER_ONLY;
-            }
-
-            boolean directBootAware;
-
-            if (!receiver) {
-                if (sa.getBoolean(R.styleable.AndroidManifestActivity_hardwareAccelerated,
-                        hardwareAccelerated)) {
-                    result.flags |= ActivityInfo.FLAG_HARDWARE_ACCELERATED;
-                }
-
-                result.launchMode = sa.getInt(
-                        R.styleable.AndroidManifestActivity_launchMode,
-                        ActivityInfo.LAUNCH_MULTIPLE);
-                result.documentLaunchMode = sa.getInt(
-                        R.styleable.AndroidManifestActivity_documentLaunchMode,
-                        ActivityInfo.DOCUMENT_LAUNCH_NONE);
-                result.maxRecents = sa.getInt(
-                        R.styleable.AndroidManifestActivity_maxRecents,
-                        ActivityTaskManager.getDefaultAppRecentsLimitStatic());
-                result.configChanges = PackageParser.getActivityConfigChanges(
-                        sa.getInt(R.styleable.AndroidManifestActivity_configChanges, 0),
-                        sa.getInt(R.styleable.AndroidManifestActivity_recreateOnConfigChanges, 0));
-                result.softInputMode = sa.getInt(
-                        R.styleable.AndroidManifestActivity_windowSoftInputMode, 0);
-
-                result.persistableMode = sa.getInteger(
-                        R.styleable.AndroidManifestActivity_persistableMode,
-                        ActivityInfo.PERSIST_ROOT_ONLY);
-
-                if (sa.getBoolean(R.styleable.AndroidManifestActivity_allowEmbedded, false)) {
-                    result.flags |= ActivityInfo.FLAG_ALLOW_EMBEDDED;
-                }
-
-                if (sa.getBoolean(R.styleable.AndroidManifestActivity_autoRemoveFromRecents,
-                        false)) {
-                    result.flags |= ActivityInfo.FLAG_AUTO_REMOVE_FROM_RECENTS;
-                }
-
-                if (sa.getBoolean(R.styleable.AndroidManifestActivity_relinquishTaskIdentity,
-                        false)) {
-                    result.flags |= ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY;
-                }
-
-                if (sa.getBoolean(R.styleable.AndroidManifestActivity_resumeWhilePausing, false)) {
-                    result.flags |= ActivityInfo.FLAG_RESUME_WHILE_PAUSING;
-                }
-
-                int screenOrientation = sa.getInt(
-                        R.styleable.AndroidManifestActivity_screenOrientation,
-                        SCREEN_ORIENTATION_UNSPECIFIED);
-                result.screenOrientation = screenOrientation;
-
-                int resizeMode = getActivityResizeMode(parsingPackage, sa, screenOrientation);
-                result.resizeMode = resizeMode;
-
-                if (sa.getBoolean(R.styleable.AndroidManifestActivity_supportsPictureInPicture,
-                        false)) {
-                    result.flags |= FLAG_SUPPORTS_PICTURE_IN_PICTURE;
-                }
-
-                if (sa.getBoolean(R.styleable.AndroidManifestActivity_alwaysFocusable, false)) {
-                    result.flags |= FLAG_ALWAYS_FOCUSABLE;
-                }
-
-                if (sa.hasValue(R.styleable.AndroidManifestActivity_maxAspectRatio)
-                        && sa.getType(R.styleable.AndroidManifestActivity_maxAspectRatio)
-                        == TypedValue.TYPE_FLOAT) {
-                    result.setMaxAspectRatio(resizeMode,
-                            sa.getFloat(R.styleable.AndroidManifestActivity_maxAspectRatio,
-                                    0 /*default*/));
-                }
-
-                if (sa.hasValue(R.styleable.AndroidManifestActivity_minAspectRatio)
-                        && sa.getType(R.styleable.AndroidManifestActivity_minAspectRatio)
-                        == TypedValue.TYPE_FLOAT) {
-                    result.setMinAspectRatio(resizeMode,
-                            sa.getFloat(R.styleable.AndroidManifestActivity_minAspectRatio,
-                                    0 /*default*/));
-                }
-
-                result.lockTaskLaunchMode =
-                        sa.getInt(R.styleable.AndroidManifestActivity_lockTaskMode, 0);
-
-                directBootAware = sa.getBoolean(
-                        R.styleable.AndroidManifestActivity_directBootAware,
-                        false);
-
-                result.requestedVrComponent =
-                        sa.getString(R.styleable.AndroidManifestActivity_enableVrMode);
-
-                result.rotationAnimation =
-                        sa.getInt(R.styleable.AndroidManifestActivity_rotationAnimation,
-                                ROTATION_ANIMATION_UNSPECIFIED);
-
-                result.colorMode = sa.getInt(R.styleable.AndroidManifestActivity_colorMode,
-                        ActivityInfo.COLOR_MODE_DEFAULT);
-
-                result.preferMinimalPostProcessing = sa.getBoolean(
-                        R.styleable.AndroidManifestActivity_preferMinimalPostProcessing,
-                        ActivityInfo.MINIMAL_POST_PROCESSING_DEFAULT);
-
-                if (sa.getBoolean(R.styleable.AndroidManifestActivity_showWhenLocked, false)) {
-                    result.flags |= ActivityInfo.FLAG_SHOW_WHEN_LOCKED;
-                }
-
-                if (sa.getBoolean(R.styleable.AndroidManifestActivity_turnScreenOn, false)) {
-                    result.flags |= ActivityInfo.FLAG_TURN_SCREEN_ON;
-                }
-
-                if (sa.getBoolean(R.styleable.AndroidManifestActivity_inheritShowWhenLocked,
-                        false)) {
-                    result.privateFlags |= ActivityInfo.FLAG_INHERIT_SHOW_WHEN_LOCKED;
-                }
-            } else {
-                result.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
-                result.configChanges = 0;
-
-                if (sa.getBoolean(R.styleable.AndroidManifestActivity_singleUser, false)) {
-                    result.flags |= ActivityInfo.FLAG_SINGLE_USER;
-                }
-                directBootAware = sa.getBoolean(
-                        R.styleable.AndroidManifestActivity_directBootAware,
-                        false);
-            }
-
-            result.directBootAware = directBootAware;
-
-            if (directBootAware) {
-                parsingPackage.setPartiallyDirectBootAware(true);
-            }
-
-            // can't make this final; we may set it later via meta-data
-            visibleToEphemeral = sa.getBoolean(
-                    R.styleable.AndroidManifestActivity_visibleToInstantApps, false);
-            if (visibleToEphemeral) {
-                result.flags |= ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP;
-                parsingPackage.setVisibleToInstantApps(true);
-            }
-        } finally {
-            if (sa != null) {
-                sa.recycle();
-            }
-        }
-
-
-        if (receiver && (parsingPackage.getPrivateFlags()
-                & ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0) {
-            // A heavy-weight application can not have receives in its main process
-            if (result.getProcessName().equals(packageName)) {
-                outError[0] = "Heavy-weight applications can not have receivers in main process";
-                return null;
-            }
-        }
-
-        if (outError[0] != null) {
-            return null;
-        }
-
-        int outerDepth = parser.getDepth();
-        int type;
-        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
-                && (type != XmlPullParser.END_TAG
-                || parser.getDepth() > outerDepth)) {
-            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
-                continue;
-            }
-
-            if (parser.getName().equals("intent-filter")) {
-                ParsedActivityIntentInfo intentInfo = new ParsedActivityIntentInfo(packageName,
-                        result.className);
-                if (!parseIntentInfo(intentInfo, parsingPackage, res, parser,
-                        true /*allowGlobs*/,
-                        true /*allowAutoVerify*/, outError)) {
-                    return null;
-                }
-                if (intentInfo.countActions() == 0) {
-                    Slog.w(TAG, "No actions in intent filter at "
-                            + parsingPackage.getBaseCodePath() + " "
-                            + parser.getPositionDescription());
-                } else {
-                    result.order = Math.max(intentInfo.getOrder(), result.order);
-                    result.addIntent(intentInfo);
-                }
-                // adjust activity flags when we implicitly expose it via a browsable filter
-                final int visibility = visibleToEphemeral
-                        ? IntentFilter.VISIBILITY_EXPLICIT
-                        : !receiver && isImplicitlyExposedIntent(intentInfo)
-                                ? IntentFilter.VISIBILITY_IMPLICIT
-                                : IntentFilter.VISIBILITY_NONE;
-                intentInfo.setVisibilityToInstantApp(visibility);
-                if (intentInfo.isVisibleToInstantApp()) {
-                    result.flags |= ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP;
-                }
-                if (intentInfo.isImplicitlyVisibleToInstantApp()) {
-                    result.flags |= ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP;
-                }
-                if (PackageParser.LOG_UNSAFE_BROADCASTS && receiver
-                        && (targetSdkVersion >= Build.VERSION_CODES.O)) {
-                    for (int i = 0; i < intentInfo.countActions(); i++) {
-                        final String action = intentInfo.getAction(i);
-                        if (action == null || !action.startsWith("android.")) continue;
-                        if (!PackageParser.SAFE_BROADCASTS.contains(action)) {
-                            Slog.w(TAG, "Broadcast " + action + " may never be delivered to "
-                                    + packageName + " as requested at: "
-                                    + parser.getPositionDescription());
-                        }
-                    }
-                }
-            } else if (!receiver && parser.getName().equals("preferred")) {
-                ParsedActivityIntentInfo intentInfo = new ParsedActivityIntentInfo(packageName,
-                        result.className);
-                if (!parseIntentInfo(intentInfo, parsingPackage, res, parser,
-                        false /*allowGlobs*/,
-                        false /*allowAutoVerify*/, outError)) {
-                    return null;
-                }
-                // adjust activity flags when we implicitly expose it via a browsable filter
-                final int visibility = visibleToEphemeral
-                        ? IntentFilter.VISIBILITY_EXPLICIT
-                        : !receiver && isImplicitlyExposedIntent(intentInfo)
-                                ? IntentFilter.VISIBILITY_IMPLICIT
-                                : IntentFilter.VISIBILITY_NONE;
-                intentInfo.setVisibilityToInstantApp(visibility);
-                if (intentInfo.isVisibleToInstantApp()) {
-                    result.flags |= ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP;
-                }
-                if (intentInfo.isImplicitlyVisibleToInstantApp()) {
-                    result.flags |= ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP;
-                }
-
-                if (intentInfo.countActions() == 0) {
-                    Slog.w(TAG, "No actions in preferred at "
-                            + parsingPackage.getBaseCodePath() + " "
-                            + parser.getPositionDescription());
-                } else {
-                    parsingPackage.addPreferredActivityFilter(intentInfo);
-                }
-            } else if (parser.getName().equals("meta-data")) {
-                if ((result.metaData = ApkParseUtils.parseMetaData(parsingPackage, res, parser,
-                        result.metaData,
-                        outError)) == null) {
-                    return null;
-                }
-            } else if (!receiver && parser.getName().equals("layout")) {
-                result.windowLayout = parseLayout(res, parser);
-            } else {
-                if (!PackageParser.RIGID_PARSER) {
-                    Slog.w(TAG, "Problem in package " + parsingPackage.getBaseCodePath() + ":");
-                    if (receiver) {
-                        Slog.w(TAG, "Unknown element under <receiver>: " + parser.getName()
-                                + " at " + parsingPackage.getBaseCodePath() + " "
-                                + parser.getPositionDescription());
-                    } else {
-                        Slog.w(TAG, "Unknown element under <activity>: " + parser.getName()
-                                + " at " + parsingPackage.getBaseCodePath() + " "
-                                + parser.getPositionDescription());
-                    }
-                    XmlUtils.skipCurrentTag(parser);
-                    continue;
-                } else {
-                    if (receiver) {
-                        outError[0] = "Bad element under <receiver>: " + parser.getName();
-                    } else {
-                        outError[0] = "Bad element under <activity>: " + parser.getName();
-                    }
-                    return null;
-                }
-            }
-        }
-
-        if (!setExported) {
-            result.exported = result.intents.size() > 0;
-        }
-
-        return result;
-    }
-
-    public static boolean isImplicitlyExposedIntent(ParsedIntentInfo intentInfo) {
-        return intentInfo.hasCategory(Intent.CATEGORY_BROWSABLE)
-                || intentInfo.hasAction(Intent.ACTION_SEND)
-                || intentInfo.hasAction(Intent.ACTION_SENDTO)
-                || intentInfo.hasAction(Intent.ACTION_SEND_MULTIPLE);
-    }
-
-    public static int getActivityResizeMode(
-            ParsingPackage parsingPackage,
-            TypedArray sa,
-            int screenOrientation
-    ) {
-        int privateFlags = parsingPackage.getPrivateFlags();
-        final boolean appExplicitDefault = (privateFlags
-                & (ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE
-                | ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_UNRESIZEABLE)) != 0;
-
-        if (sa.hasValue(R.styleable.AndroidManifestActivity_resizeableActivity)
-                || appExplicitDefault) {
-            // Activity or app explicitly set if it is resizeable or not;
-            final boolean appResizeable = (privateFlags
-                    & ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE) != 0;
-            if (sa.getBoolean(R.styleable.AndroidManifestActivity_resizeableActivity,
-                    appResizeable)) {
-                return ActivityInfo.RESIZE_MODE_RESIZEABLE;
-            } else {
-                return ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
-            }
-        }
-
-        if ((privateFlags
-                & ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION)
-                != 0) {
-            // The activity or app didn't explicitly set the resizing option, however we want to
-            // make it resize due to the sdk version it is targeting.
-            return ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
-        }
-
-        // resize preference isn't set and target sdk version doesn't support resizing apps by
-        // default. For the app to be resizeable if it isn't fixed orientation or immersive.
-        if (ActivityInfo.isFixedOrientationPortrait(screenOrientation)) {
-            return ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY;
-        } else if (ActivityInfo.isFixedOrientationLandscape(screenOrientation)) {
-            return ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY;
-        } else if (screenOrientation == ActivityInfo.SCREEN_ORIENTATION_LOCKED) {
-            return ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION;
-        } else {
-            return ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE;
-        }
-    }
-
-    public static ParsedService parseService(
-            String[] separateProcesses,
-            ParsingPackage parsingPackage,
-            Resources res,
-            XmlResourceParser parser, int flags, String[] outError
-    ) throws XmlPullParserException, IOException {
-        TypedArray sa = null;
-        boolean visibleToEphemeral;
-        boolean setExported;
-
-        String packageName = parsingPackage.getPackageName();
-        String packageProcessName = parsingPackage.getProcessName();
-        ParsedService result = new ParsedService();
-
-        try {
-            sa = res.obtainAttributes(parser,
-                    R.styleable.AndroidManifestService);
-
-            String name = sa.getNonConfigurationString(R.styleable.AndroidManifestService_name, 0);
-            if (name == null) {
-                outError[0] = "<service> does not specify android:name";
-                return null;
-            } else {
-                String className = ApkParseUtils.buildClassName(packageName, name);
-                if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) {
-                    outError[0] = "<service> invalid android:name";
-                    return null;
-                } else if (className == null) {
-                    outError[0] = "Empty class name in package " + packageName;
-                    return null;
-                }
-
-                result.className = className;
-            }
-
-            int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId(
-                    R.styleable.AndroidManifestService_roundIcon, 0) : 0;
-            if (roundIconVal != 0) {
-                result.icon = roundIconVal;
-                result.nonLocalizedLabel = null;
-            } else {
-                int iconVal = sa.getResourceId(R.styleable.AndroidManifestService_icon, 0);
-                if (iconVal != 0) {
-                    result.icon = iconVal;
-                    result.nonLocalizedLabel = null;
-                }
-            }
-
-            int logoVal = sa.getResourceId(R.styleable.AndroidManifestService_logo, 0);
-            if (logoVal != 0) {
-                result.logo = logoVal;
-            }
-
-            int bannerVal = sa.getResourceId(R.styleable.AndroidManifestService_banner, 0);
-            if (bannerVal != 0) {
-                result.banner = bannerVal;
-            }
-
-            TypedValue v = sa.peekValue(R.styleable.AndroidManifestService_label);
-            if (v != null && (result.labelRes = v.resourceId) == 0) {
-                result.nonLocalizedLabel = v.coerceToString();
-            }
-
-            result.setPackageNameInternal(packageName);
-
-            CharSequence pname;
-            if (parsingPackage.getTargetSdkVersion() >= Build.VERSION_CODES.FROYO) {
-                pname = sa.getNonConfigurationString(R.styleable.AndroidManifestService_process,
-                        Configuration.NATIVE_CONFIG_VERSION);
-            } else {
-                // Some older apps have been seen to use a resource reference
-                // here that on older builds was ignored (with a warning).  We
-                // need to continue to do this for them so they don't break.
-                pname = sa.getNonResourceString(R.styleable.AndroidManifestService_process);
-            }
-
-            result.setProcessName(packageProcessName, PackageParser.buildProcessName(packageName,
-                    packageProcessName, pname,
-                    flags, separateProcesses, outError));
-
-            result.descriptionRes = sa.getResourceId(
-                    R.styleable.AndroidManifestService_description, 0);
-
-            result.enabled = sa.getBoolean(R.styleable.AndroidManifestService_enabled, true);
-
-            setExported = sa.hasValue(
-                    R.styleable.AndroidManifestService_exported);
-            if (setExported) {
-                result.exported = sa.getBoolean(
-                        R.styleable.AndroidManifestService_exported, false);
-            }
-
-            String str = sa.getNonConfigurationString(
-                    R.styleable.AndroidManifestService_permission, 0);
-            if (str == null) {
-                result.setPermission(parsingPackage.getPermission());
-            } else {
-                result.setPermission(str);
-            }
-
-            result.setSplitName(
-                    sa.getNonConfigurationString(R.styleable.AndroidManifestService_splitName, 0));
-
-            result.foregroundServiceType = sa.getInt(
-                    R.styleable.AndroidManifestService_foregroundServiceType,
-                    ServiceInfo.FOREGROUND_SERVICE_TYPE_NONE);
-
-            result.flags = 0;
-            if (sa.getBoolean(
-                    R.styleable.AndroidManifestService_stopWithTask,
-                    false)) {
-                result.flags |= ServiceInfo.FLAG_STOP_WITH_TASK;
-            }
-            if (sa.getBoolean(
-                    R.styleable.AndroidManifestService_isolatedProcess,
-                    false)) {
-                result.flags |= ServiceInfo.FLAG_ISOLATED_PROCESS;
-            }
-            if (sa.getBoolean(
-                    R.styleable.AndroidManifestService_externalService,
-                    false)) {
-                result.flags |= ServiceInfo.FLAG_EXTERNAL_SERVICE;
-            }
-            if (sa.getBoolean(
-                    R.styleable.AndroidManifestService_useAppZygote,
-                    false)) {
-                result.flags |= ServiceInfo.FLAG_USE_APP_ZYGOTE;
-            }
-            if (sa.getBoolean(
-                    R.styleable.AndroidManifestService_singleUser,
-                    false)) {
-                result.flags |= ServiceInfo.FLAG_SINGLE_USER;
-            }
-
-            result.directBootAware = sa.getBoolean(
-                    R.styleable.AndroidManifestService_directBootAware,
-                    false);
-            if (result.directBootAware) {
-                parsingPackage.setPartiallyDirectBootAware(true);
-            }
-
-            visibleToEphemeral = sa.getBoolean(
-                    R.styleable.AndroidManifestService_visibleToInstantApps, false);
-            if (visibleToEphemeral) {
-                result.flags |= ServiceInfo.FLAG_VISIBLE_TO_INSTANT_APP;
-                parsingPackage.setVisibleToInstantApps(true);
-            }
-        } finally {
-            if (sa != null) {
-                sa.recycle();
-            }
-        }
-
-        if (parsingPackage.cantSaveState()) {
-            // A heavy-weight application can not have services in its main process
-            // We can do direct compare because we intern all strings.
-            if (Objects.equals(result.getProcessName(), parsingPackage.getPackageName())) {
-                outError[0] = "Heavy-weight applications can not have services in main process";
-                return null;
-            }
-        }
-
-        int outerDepth = parser.getDepth();
-        int type;
-        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
-                && (type != XmlPullParser.END_TAG
-                || parser.getDepth() > outerDepth)) {
-            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
-                continue;
-            }
-
-            if (parser.getName().equals("intent-filter")) {
-                ParsedServiceIntentInfo intent = new ParsedServiceIntentInfo(packageName,
-                        result.className);
-                if (!parseIntentInfo(intent, parsingPackage, res, parser, true /*allowGlobs*/,
-                        false /*allowAutoVerify*/,
-                        outError)) {
-                    return null;
-                }
-                if (visibleToEphemeral) {
-                    intent.setVisibilityToInstantApp(IntentFilter.VISIBILITY_EXPLICIT);
-                    result.flags |= ServiceInfo.FLAG_VISIBLE_TO_INSTANT_APP;
-                }
-                result.order = Math.max(intent.getOrder(), result.order);
-                result.intents.add(intent);
-            } else if (parser.getName().equals("meta-data")) {
-                if ((result.metaData = ApkParseUtils.parseMetaData(parsingPackage, res, parser,
-                        result.metaData,
-                        outError)) == null) {
-                    return null;
-                }
-            } else {
-                if (!PackageParser.RIGID_PARSER) {
-                    Slog.w(TAG, "Unknown element under <service>: "
-                            + parser.getName() + " at " + parsingPackage.getBaseCodePath() + " "
-                            + parser.getPositionDescription());
-                    XmlUtils.skipCurrentTag(parser);
-                    continue;
-                } else {
-                    outError[0] = "Bad element under <service>: " + parser.getName();
-                    return null;
-                }
-            }
-        }
-
-        if (!setExported) {
-            result.exported = result.intents.size() > 0;
-        }
-
-        return result;
-    }
-
-    public static ParsedProvider parseProvider(
-            String[] separateProcesses,
-            ParsingPackage parsingPackage,
-            Resources res,
-            XmlResourceParser parser, int flags, String[] outError)
-            throws XmlPullParserException, IOException {
-        TypedArray sa = null;
-        String cpname;
-        boolean visibleToEphemeral;
-
-        int targetSdkVersion = parsingPackage.getTargetSdkVersion();
-        String packageName = parsingPackage.getPackageName();
-        String packageProcessName = parsingPackage.getProcessName();
-        ParsedProvider result = new ParsedProvider();
-
-        try {
-            sa = res.obtainAttributes(parser,
-                    R.styleable.AndroidManifestProvider);
-
-            String name = sa.getNonConfigurationString(R.styleable.AndroidManifestProvider_name, 0);
-            if (name == null) {
-                outError[0] = "<provider> does not specify android:name";
-                return null;
-            } else {
-                String className = ApkParseUtils.buildClassName(packageName, name);
-                if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) {
-                    outError[0] = "<provider> invalid android:name";
-                    return null;
-                } else if (className == null) {
-                    outError[0] = "Empty class name in package " + packageName;
-                    return null;
-                }
-
-                result.className = className;
-            }
-
-            int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId(
-                    R.styleable.AndroidManifestProvider_roundIcon, 0) : 0;
-            if (roundIconVal != 0) {
-                result.icon = roundIconVal;
-                result.nonLocalizedLabel = null;
-            } else {
-                int iconVal = sa.getResourceId(R.styleable.AndroidManifestProvider_icon, 0);
-                if (iconVal != 0) {
-                    result.icon = iconVal;
-                    result.nonLocalizedLabel = null;
-                }
-            }
-
-            int logoVal = sa.getResourceId(R.styleable.AndroidManifestProvider_logo, 0);
-            if (logoVal != 0) {
-                result.logo = logoVal;
-            }
-
-            int bannerVal = sa.getResourceId(R.styleable.AndroidManifestProvider_banner, 0);
-            if (bannerVal != 0) {
-                result.banner = bannerVal;
-            }
-
-            TypedValue v = sa.peekValue(R.styleable.AndroidManifestProvider_label);
-            if (v != null && (result.labelRes = v.resourceId) == 0) {
-                result.nonLocalizedLabel = v.coerceToString();
-            }
-
-            result.setPackageNameInternal(packageName);
-
-            CharSequence pname;
-            if (parsingPackage.getTargetSdkVersion() >= Build.VERSION_CODES.FROYO) {
-                pname = sa.getNonConfigurationString(R.styleable.AndroidManifestProvider_process,
-                        Configuration.NATIVE_CONFIG_VERSION);
-            } else {
-                // Some older apps have been seen to use a resource reference
-                // here that on older builds was ignored (with a warning).  We
-                // need to continue to do this for them so they don't break.
-                pname = sa.getNonResourceString(R.styleable.AndroidManifestProvider_process);
-            }
-
-            result.setProcessName(packageProcessName, PackageParser.buildProcessName(packageName,
-                    packageProcessName, pname,
-                    flags, separateProcesses, outError));
-
-            result.descriptionRes = sa.getResourceId(
-                    R.styleable.AndroidManifestProvider_description, 0);
-
-            result.enabled = sa.getBoolean(R.styleable.AndroidManifestProvider_enabled, true);
-
-            boolean providerExportedDefault = false;
-
-            if (targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR1) {
-                // For compatibility, applications targeting API level 16 or lower
-                // should have their content providers exported by default, unless they
-                // specify otherwise.
-                providerExportedDefault = true;
-            }
-
-            result.exported = sa.getBoolean(
-                    R.styleable.AndroidManifestProvider_exported,
-                    providerExportedDefault);
-
-            cpname = sa.getNonConfigurationString(
-                    R.styleable.AndroidManifestProvider_authorities, 0);
-
-            result.isSyncable = sa.getBoolean(
-                    R.styleable.AndroidManifestProvider_syncable,
-                    false);
-
-            String permission = sa.getNonConfigurationString(
-                    R.styleable.AndroidManifestProvider_permission, 0);
-            String str = sa.getNonConfigurationString(
-                    R.styleable.AndroidManifestProvider_readPermission, 0);
-            if (str == null) {
-                str = permission;
-            }
-            if (str == null) {
-                result.setReadPermission(parsingPackage.getPermission());
-            } else {
-                result.setReadPermission(str);
-            }
-            str = sa.getNonConfigurationString(
-                    R.styleable.AndroidManifestProvider_writePermission, 0);
-            if (str == null) {
-                str = permission;
-            }
-            if (str == null) {
-                result.setWritePermission(parsingPackage.getPermission());
-            } else {
-                result.setWritePermission(str);
-            }
-
-            result.grantUriPermissions = sa.getBoolean(
-                    R.styleable.AndroidManifestProvider_grantUriPermissions,
-                    false);
-
-            result.forceUriPermissions = sa.getBoolean(
-                    R.styleable.AndroidManifestProvider_forceUriPermissions,
-                    false);
-
-            result.multiProcess = sa.getBoolean(
-                    R.styleable.AndroidManifestProvider_multiprocess,
-                    false);
-
-            result.initOrder = sa.getInt(
-                    R.styleable.AndroidManifestProvider_initOrder,
-                    0);
-
-            result.setSplitName(
-                    sa.getNonConfigurationString(R.styleable.AndroidManifestProvider_splitName, 0));
-
-            result.flags = 0;
-
-            if (sa.getBoolean(
-                    R.styleable.AndroidManifestProvider_singleUser,
-                    false)) {
-                result.flags |= ProviderInfo.FLAG_SINGLE_USER;
-            }
-
-            result.directBootAware = sa.getBoolean(
-                    R.styleable.AndroidManifestProvider_directBootAware,
-                    false);
-            if (result.directBootAware) {
-                parsingPackage.setPartiallyDirectBootAware(true);
-            }
-
-            visibleToEphemeral =
-                    sa.getBoolean(R.styleable.AndroidManifestProvider_visibleToInstantApps, false);
-            if (visibleToEphemeral) {
-                result.flags |= ProviderInfo.FLAG_VISIBLE_TO_INSTANT_APP;
-                parsingPackage.setVisibleToInstantApps(true);
-            }
-        } finally {
-            if (sa != null) {
-                sa.recycle();
-            }
-        }
-
-        if ((parsingPackage.getPrivateFlags() & ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE)
-                != 0) {
-            // A heavy-weight application can not have providers in its main process
-            if (result.getProcessName().equals(packageName)) {
-                outError[0] = "Heavy-weight applications can not have providers in main process";
-                return null;
-            }
-        }
-
-        if (cpname == null) {
-            outError[0] = "<provider> does not include authorities attribute";
-            return null;
-        }
-        if (cpname.length() <= 0) {
-            outError[0] = "<provider> has empty authorities attribute";
-            return null;
-        }
-        result.setAuthority(cpname);
-
-        if (!parseProviderTags(parsingPackage, res, parser, visibleToEphemeral, result, outError)) {
-            return null;
-        }
-
-        return result;
-    }
-
-    public static ParsedQueriesIntentInfo parsedParsedQueriesIntentInfo(
-            ParsingPackage parsingPackage,
-            Resources res,
-            XmlResourceParser parser,
-            String[] outError
-    ) throws IOException, XmlPullParserException {
-        ParsedQueriesIntentInfo intentInfo = new ParsedQueriesIntentInfo(
-                parsingPackage.getPackageName(),
-                null
-        );
-        if (!parseIntentInfo(
-                intentInfo,
-                parsingPackage,
-                res,
-                parser,
-                true /*allowGlobs*/,
-                true /*allowAutoVerify*/,
-                outError
-        )) {
-            return null;
-        }
-        return intentInfo;
-    }
-
-    private static boolean parseProviderTags(
-            ParsingPackage parsingPackage,
-            Resources res, XmlResourceParser parser,
-            boolean visibleToEphemeral, ParsedProvider outInfo, String[] outError)
-            throws XmlPullParserException, IOException {
-        int outerDepth = parser.getDepth();
-        int type;
-        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
-                && (type != XmlPullParser.END_TAG
-                || parser.getDepth() > outerDepth)) {
-            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
-                continue;
-            }
-
-            if (parser.getName().equals("intent-filter")) {
-                ParsedProviderIntentInfo intent = new ParsedProviderIntentInfo(
-                        parsingPackage.getPackageName(), outInfo.className);
-                if (!parseIntentInfo(intent, parsingPackage, res, parser, true /*allowGlobs*/,
-                        false /*allowAutoVerify*/,
-                        outError)) {
-                    return false;
-                }
-                if (visibleToEphemeral) {
-                    intent.setVisibilityToInstantApp(IntentFilter.VISIBILITY_EXPLICIT);
-                    outInfo.flags |= ProviderInfo.FLAG_VISIBLE_TO_INSTANT_APP;
-                }
-                outInfo.order = Math.max(intent.getOrder(), outInfo.order);
-                outInfo.intents.add(intent);
-
-            } else if (parser.getName().equals("meta-data")) {
-                Bundle metaData = ApkParseUtils.parseMetaData(parsingPackage, res, parser,
-                        outInfo.metaData, outError);
-                if (metaData == null) {
-                    return false;
-                } else {
-                    outInfo.metaData = metaData;
-                }
-
-            } else if (parser.getName().equals("grant-uri-permission")) {
-                TypedArray sa = res.obtainAttributes(parser,
-                        R.styleable.AndroidManifestGrantUriPermission);
-
-                PatternMatcher pa = null;
-
-                String str = sa.getNonConfigurationString(
-                        R.styleable.AndroidManifestGrantUriPermission_path, 0);
-                if (str != null) {
-                    pa = new PatternMatcher(str, PatternMatcher.PATTERN_LITERAL);
-                }
-
-                str = sa.getNonConfigurationString(
-                        R.styleable.AndroidManifestGrantUriPermission_pathPrefix, 0);
-                if (str != null) {
-                    pa = new PatternMatcher(str, PatternMatcher.PATTERN_PREFIX);
-                }
-
-                str = sa.getNonConfigurationString(
-                        R.styleable.AndroidManifestGrantUriPermission_pathPattern, 0);
-                if (str != null) {
-                    pa = new PatternMatcher(str, PatternMatcher.PATTERN_SIMPLE_GLOB);
-                }
-
-                sa.recycle();
-
-                if (pa != null) {
-                    if (outInfo.uriPermissionPatterns == null) {
-                        outInfo.uriPermissionPatterns = new PatternMatcher[1];
-                        outInfo.uriPermissionPatterns[0] = pa;
-                    } else {
-                        final int N = outInfo.uriPermissionPatterns.length;
-                        PatternMatcher[] newp = new PatternMatcher[N + 1];
-                        System.arraycopy(outInfo.uriPermissionPatterns, 0, newp, 0, N);
-                        newp[N] = pa;
-                        outInfo.uriPermissionPatterns = newp;
-                    }
-                    outInfo.grantUriPermissions = true;
-                } else {
-                    if (!PackageParser.RIGID_PARSER) {
-                        Slog.w(TAG, "Unknown element under <path-permission>: "
-                                + parser.getName() + " at " + parsingPackage.getBaseCodePath()
-                                + " "
-                                + parser.getPositionDescription());
-                        XmlUtils.skipCurrentTag(parser);
-                        continue;
-                    } else {
-                        outError[0] = "No path, pathPrefix, or pathPattern for <path-permission>";
-                        return false;
-                    }
-                }
-                XmlUtils.skipCurrentTag(parser);
-
-            } else if (parser.getName().equals("path-permission")) {
-                TypedArray sa = res.obtainAttributes(parser,
-                        R.styleable.AndroidManifestPathPermission);
-
-                PathPermission pa = null;
-
-                String permission = sa.getNonConfigurationString(
-                        R.styleable.AndroidManifestPathPermission_permission, 0);
-                String readPermission = sa.getNonConfigurationString(
-                        R.styleable.AndroidManifestPathPermission_readPermission, 0);
-                if (readPermission == null) {
-                    readPermission = permission;
-                }
-                String writePermission = sa.getNonConfigurationString(
-                        R.styleable.AndroidManifestPathPermission_writePermission, 0);
-                if (writePermission == null) {
-                    writePermission = permission;
-                }
-
-                boolean havePerm = false;
-                if (readPermission != null) {
-                    readPermission = readPermission.intern();
-                    havePerm = true;
-                }
-                if (writePermission != null) {
-                    writePermission = writePermission.intern();
-                    havePerm = true;
-                }
-
-                if (!havePerm) {
-                    if (!PackageParser.RIGID_PARSER) {
-                        Slog.w(TAG, "No readPermission or writePermssion for <path-permission>: "
-                                + parser.getName() + " at " + parsingPackage.getBaseCodePath()
-                                + " "
-                                + parser.getPositionDescription());
-                        XmlUtils.skipCurrentTag(parser);
-                        continue;
-                    } else {
-                        outError[0] = "No readPermission or writePermssion for <path-permission>";
-                        return false;
-                    }
-                }
-
-                String path = sa.getNonConfigurationString(
-                        R.styleable.AndroidManifestPathPermission_path, 0);
-                if (path != null) {
-                    pa = new PathPermission(path,
-                            PatternMatcher.PATTERN_LITERAL, readPermission, writePermission);
-                }
-
-                path = sa.getNonConfigurationString(
-                        R.styleable.AndroidManifestPathPermission_pathPrefix, 0);
-                if (path != null) {
-                    pa = new PathPermission(path,
-                            PatternMatcher.PATTERN_PREFIX, readPermission, writePermission);
-                }
-
-                path = sa.getNonConfigurationString(
-                        R.styleable.AndroidManifestPathPermission_pathPattern, 0);
-                if (path != null) {
-                    pa = new PathPermission(path,
-                            PatternMatcher.PATTERN_SIMPLE_GLOB, readPermission, writePermission);
-                }
-
-                path = sa.getNonConfigurationString(
-                        R.styleable.AndroidManifestPathPermission_pathAdvancedPattern, 0);
-                if (path != null) {
-                    pa = new PathPermission(path,
-                            PatternMatcher.PATTERN_ADVANCED_GLOB, readPermission, writePermission);
-                }
-
-                sa.recycle();
-
-                if (pa != null) {
-                    if (outInfo.pathPermissions == null) {
-                        outInfo.pathPermissions = new PathPermission[1];
-                        outInfo.pathPermissions[0] = pa;
-                    } else {
-                        final int N = outInfo.pathPermissions.length;
-                        PathPermission[] newp = new PathPermission[N + 1];
-                        System.arraycopy(outInfo.pathPermissions, 0, newp, 0, N);
-                        newp[N] = pa;
-                        outInfo.pathPermissions = newp;
-                    }
-                } else {
-                    if (!PackageParser.RIGID_PARSER) {
-                        Slog.w(TAG, "No path, pathPrefix, or pathPattern for <path-permission>: "
-                                + parser.getName() + " at " + parsingPackage.getBaseCodePath()
-                                + " "
-                                + parser.getPositionDescription());
-                        XmlUtils.skipCurrentTag(parser);
-                        continue;
-                    }
-                    outError[0] = "No path, pathPrefix, or pathPattern for <path-permission>";
-                    return false;
-                }
-                XmlUtils.skipCurrentTag(parser);
-
-            } else {
-                if (!PackageParser.RIGID_PARSER) {
-                    Slog.w(TAG, "Unknown element under <provider>: "
-                            + parser.getName() + " at " + parsingPackage.getBaseCodePath() + " "
-                            + parser.getPositionDescription());
-                    XmlUtils.skipCurrentTag(parser);
-                    continue;
-                } else {
-                    outError[0] = "Bad element under <provider>: " + parser.getName();
-                    return false;
-                }
-            }
-        }
-        return true;
-    }
-
-    public static ParsedActivity parseActivityAlias(
-            ParsingPackage parsingPackage,
-            Resources res,
-            XmlResourceParser parser,
-            String[] outError)
-            throws XmlPullParserException, IOException {
-        TypedArray sa = res.obtainAttributes(parser,
-                R.styleable.AndroidManifestActivityAlias);
-
-        String targetActivity = sa.getNonConfigurationString(
-                R.styleable.AndroidManifestActivityAlias_targetActivity,
-                Configuration.NATIVE_CONFIG_VERSION);
-        if (targetActivity == null) {
-            outError[0] = "<activity-alias> does not specify android:targetActivity";
-            sa.recycle();
-            return null;
-        }
-
-        String packageName = parsingPackage.getPackageName();
-        targetActivity = ApkParseUtils.buildClassName(packageName, targetActivity);
-        if (targetActivity == null) {
-            outError[0] = "Empty class name in package " + packageName;
-            sa.recycle();
-            return null;
-        }
-
-        ParsedActivity target = null;
-
-        List<ParsedActivity> activities = parsingPackage.getActivities();
-        final int NA = activities.size();
-        for (int i = 0; i < NA; i++) {
-            ParsedActivity t = activities.get(i);
-            if (targetActivity.equals(t.className)) {
-                target = t;
-                break;
-            }
-        }
-
-        if (target == null) {
-            outError[0] = "<activity-alias> target activity " + targetActivity
-                    + " not found in manifest with activities = " + parsingPackage.getActivities()
-                    + ", parsedActivities = " + activities;
-            sa.recycle();
-            return null;
-        }
-
-        ParsedActivity result = new ParsedActivity();
-        result.setPackageNameInternal(target.getPackageName());
-        result.targetActivity = targetActivity;
-        result.configChanges = target.configChanges;
-        result.flags = target.flags;
-        result.privateFlags = target.privateFlags;
-        result.icon = target.icon;
-        result.logo = target.logo;
-        result.banner = target.banner;
-        result.labelRes = target.labelRes;
-        result.nonLocalizedLabel = target.nonLocalizedLabel;
-        result.launchMode = target.launchMode;
-        result.lockTaskLaunchMode = target.lockTaskLaunchMode;
-        result.descriptionRes = target.descriptionRes;
-        result.screenOrientation = target.screenOrientation;
-        result.taskAffinity = target.taskAffinity;
-        result.theme = target.theme;
-        result.softInputMode = target.softInputMode;
-        result.uiOptions = target.uiOptions;
-        result.parentActivityName = target.parentActivityName;
-        result.maxRecents = target.maxRecents;
-        result.windowLayout = target.windowLayout;
-        result.resizeMode = target.resizeMode;
-        result.maxAspectRatio = target.maxAspectRatio;
-        result.hasMaxAspectRatio = target.hasMaxAspectRatio;
-        result.minAspectRatio = target.minAspectRatio;
-        result.hasMinAspectRatio = target.hasMinAspectRatio;
-        result.requestedVrComponent = target.requestedVrComponent;
-        result.directBootAware = target.directBootAware;
-
-        result.setProcessName(parsingPackage.getAppInfoProcessName(), target.getProcessName());
-
-        // Not all attributes from the target ParsedActivity are copied to the alias.
-        // Careful when adding an attribute and determine whether or not it should be copied.
-//        result.enabled = target.enabled;
-//        result.exported = target.exported;
-//        result.permission = target.permission;
-//        result.splitName = target.splitName;
-//        result.documentLaunchMode = target.documentLaunchMode;
-//        result.persistableMode = target.persistableMode;
-//        result.rotationAnimation = target.rotationAnimation;
-//        result.colorMode = target.colorMode;
-//        result.intents.addAll(target.intents);
-//        result.order = target.order;
-//        result.metaData = target.metaData;
-
-        String name = sa.getNonConfigurationString(R.styleable.AndroidManifestActivityAlias_name,
-                0);
-        if (name == null) {
-            outError[0] = "<activity-alias> does not specify android:name";
-            return null;
-        } else {
-            String className = ApkParseUtils.buildClassName(packageName, name);
-            if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) {
-                outError[0] = "<activity-alias> invalid android:name";
-                return null;
-            } else if (className == null) {
-                outError[0] = "Empty class name in package " + packageName;
-                return null;
-            }
-
-            result.className = className;
-        }
-
-        int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId(
-                R.styleable.AndroidManifestActivityAlias_roundIcon, 0) : 0;
-        if (roundIconVal != 0) {
-            result.icon = roundIconVal;
-            result.nonLocalizedLabel = null;
-        } else {
-            int iconVal = sa.getResourceId(R.styleable.AndroidManifestActivityAlias_icon, 0);
-            if (iconVal != 0) {
-                result.icon = iconVal;
-                result.nonLocalizedLabel = null;
-            }
-        }
-
-        int logoVal = sa.getResourceId(R.styleable.AndroidManifestActivityAlias_logo, 0);
-        if (logoVal != 0) {
-            result.logo = logoVal;
-        }
-
-        int bannerVal = sa.getResourceId(R.styleable.AndroidManifestActivityAlias_banner, 0);
-        if (bannerVal != 0) {
-            result.banner = bannerVal;
-        }
-
-        TypedValue v = sa.peekValue(R.styleable.AndroidManifestActivityAlias_label);
-        if (v != null && (result.labelRes = v.resourceId) == 0) {
-            result.nonLocalizedLabel = v.coerceToString();
-        }
-
-        result.setPackageNameInternal(packageName);
-
-        result.descriptionRes = sa.getResourceId(
-                R.styleable.AndroidManifestActivityAlias_description, 0);
-
-        result.enabled = sa.getBoolean(R.styleable.AndroidManifestActivityAlias_enabled, true);
-
-        final boolean setExported = sa.hasValue(
-                R.styleable.AndroidManifestActivityAlias_exported);
-        if (setExported) {
-            result.exported = sa.getBoolean(
-                    R.styleable.AndroidManifestActivityAlias_exported, false);
-        }
-
-        String str;
-        str = sa.getNonConfigurationString(
-                R.styleable.AndroidManifestActivityAlias_permission, 0);
-        if (str != null) {
-            result.setPermission(str);
-        }
-
-        String parentName = sa.getNonConfigurationString(
-                R.styleable.AndroidManifestActivityAlias_parentActivityName,
-                Configuration.NATIVE_CONFIG_VERSION);
-        if (parentName != null) {
-            String parentClassName = ApkParseUtils.buildClassName(result.getPackageName(),
-                    parentName);
-            if (parentClassName == null) {
-                Log.e(TAG, "Activity alias " + result.className +
-                        " specified invalid parentActivityName " + parentName);
-                outError[0] = null;
-            } else {
-                result.parentActivityName = parentClassName;
-            }
-        }
-
-        // TODO add visibleToInstantApps attribute to activity alias
-        final boolean visibleToEphemeral =
-                ((result.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0);
-
-        sa.recycle();
-
-        if (outError[0] != null) {
-            return null;
-        }
-
-        int outerDepth = parser.getDepth();
-        int type;
-        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
-                && (type != XmlPullParser.END_TAG
-                || parser.getDepth() > outerDepth)) {
-            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
-                continue;
-            }
-
-            String tagName = parser.getName();
-            if (tagName.equals("intent-filter")) {
-                ParsedActivityIntentInfo intent = new ParsedActivityIntentInfo(packageName,
-                        result.className);
-                if (!parseIntentInfo(intent, parsingPackage, res, parser, true /*allowGlobs*/,
-                        true /*allowAutoVerify*/, outError)) {
-                    return null;
-                }
-                if (intent.countActions() == 0) {
-                    Slog.w(TAG, "No actions in intent filter at "
-                            + parsingPackage.getBaseCodePath() + " "
-                            + parser.getPositionDescription());
-                } else {
-                    result.order = Math.max(intent.getOrder(), result.order);
-                    result.addIntent(intent);
-                }
-                // adjust activity flags when we implicitly expose it via a browsable filter
-                final int visibility = visibleToEphemeral
-                        ? IntentFilter.VISIBILITY_EXPLICIT
-                        : isImplicitlyExposedIntent(intent)
-                                ? IntentFilter.VISIBILITY_IMPLICIT
-                                : IntentFilter.VISIBILITY_NONE;
-                intent.setVisibilityToInstantApp(visibility);
-                if (intent.isVisibleToInstantApp()) {
-                    result.flags |= ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP;
-                }
-                if (intent.isImplicitlyVisibleToInstantApp()) {
-                    result.flags |= ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP;
-                }
-            } else if (tagName.equals("meta-data")) {
-                if ((result.metaData = ApkParseUtils.parseMetaData(parsingPackage, res, parser,
-                        result.metaData,
-                        outError)) == null) {
-                    return null;
-                }
-            } else {
-                if (!PackageParser.RIGID_PARSER) {
-                    Slog.w(TAG, "Unknown element under <activity-alias>: " + tagName
-                            + " at " + parsingPackage.getBaseCodePath() + " "
-                            + parser.getPositionDescription());
-                    XmlUtils.skipCurrentTag(parser);
-                    continue;
-                } else {
-                    outError[0] = "Bad element under <activity-alias>: " + tagName;
-                    return null;
-                }
-            }
-        }
-
-        if (!setExported) {
-            result.exported = result.intents.size() > 0;
-        }
-
-        return result;
-    }
-
-    public static ParsedFeature parseFeature(
-            Resources res,
-            XmlResourceParser parser,
-            String[] outError
-    ) throws IOException, XmlPullParserException {
-        String featureId;
-        int label;
-        List<String> inheritFrom = null;
-
-        TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestFeature);
-        if (sa == null) {
-            outError[0] = "<feature> could not be parsed";
-            return null;
-        }
-
-        try {
-            featureId = sa.getNonConfigurationString(R.styleable.AndroidManifestFeature_featureId,
-                    0);
-            if (featureId == null) {
-                outError[0] = "<featureId> does not specify android:featureId";
-                return null;
-            }
-            if (featureId.length() > ParsedFeature.MAX_FEATURE_ID_LEN) {
-                outError[0] = "<featureId> is too long. Max length is "
-                        + ParsedFeature.MAX_FEATURE_ID_LEN;
-                return null;
-            }
-
-            label = sa.getResourceId(R.styleable.AndroidManifestFeature_label, 0);
-            if (label == Resources.ID_NULL) {
-                outError[0] = "<featureId> does not specify android:label";
-                return null;
-            }
-        } finally {
-            sa.recycle();
-        }
-
-        int type;
-        final int innerDepth = parser.getDepth();
-        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
-                && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
-            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
-                continue;
-            }
-
-            String tagName = parser.getName();
-            if (tagName.equals("inherit-from")) {
-                sa = res.obtainAttributes(parser, R.styleable.AndroidManifestFeatureInheritFrom);
-                if (sa == null) {
-                    outError[0] = "<inherit-from> could not be parsed";
-                    return null;
-                }
-
-                try {
-                    String inheritFromId = sa.getNonConfigurationString(
-                            R.styleable.AndroidManifestFeatureInheritFrom_featureId,0);
-
-                    if (inheritFrom == null) {
-                        inheritFrom = new ArrayList<>();
-                    }
-                    inheritFrom.add(inheritFromId);
-                } finally {
-                    sa.recycle();
-                }
-            } else {
-                outError[0] = "Bad element under <feature>: " + tagName;
-                return null;
-            }
-        }
-
-        if (inheritFrom == null) {
-            inheritFrom = Collections.emptyList();
-        } else {
-            ((ArrayList) inheritFrom).trimToSize();
-        }
-
-        return new ParsedFeature(featureId, label, inheritFrom);
-    }
-
-    public static ParsedPermission parsePermission(
-            ParsingPackage parsingPackage,
-            Resources res,
-            XmlResourceParser parser,
-            String[] outError
-    ) throws IOException, XmlPullParserException {
-        TypedArray sa = null;
-        String packageName = parsingPackage.getPackageName();
-        ParsedPermission result = new ParsedPermission();
-
-        try {
-            sa = res.obtainAttributes(parser, R.styleable.AndroidManifestPermission);
-
-            String name = sa.getNonConfigurationString(R.styleable.AndroidManifestPermission_name,
-                    0);
-            if (name == null) {
-                outError[0] = "<permission> does not specify android:name";
-                return null;
-            } else {
-                String className = ApkParseUtils.buildClassName(packageName, name);
-                if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) {
-                    outError[0] = "<permission> invalid android:name";
-                    return null;
-                } else if (className == null) {
-                    outError[0] = "Empty class name in package " + packageName;
-                    return null;
-                }
-
-                result.className = className;
-            }
-
-            int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId(
-                    R.styleable.AndroidManifestPermission_roundIcon, 0) : 0;
-            if (roundIconVal != 0) {
-                result.icon = roundIconVal;
-                result.nonLocalizedLabel = null;
-            } else {
-                int iconVal = sa.getResourceId(R.styleable.AndroidManifestPermission_icon, 0);
-                if (iconVal != 0) {
-                    result.icon = iconVal;
-                    result.nonLocalizedLabel = null;
-                }
-            }
-
-            int logoVal = sa.getResourceId(R.styleable.AndroidManifestPermission_logo, 0);
-            if (logoVal != 0) {
-                result.logo = logoVal;
-            }
-
-            int bannerVal = sa.getResourceId(R.styleable.AndroidManifestPermission_banner, 0);
-            if (bannerVal != 0) {
-                result.banner = bannerVal;
-            }
-
-            TypedValue v = sa.peekValue(R.styleable.AndroidManifestPermission_label);
-            if (v != null && (result.labelRes = v.resourceId) == 0) {
-                result.nonLocalizedLabel = v.coerceToString();
-            }
-
-            result.setPackageNameInternal(packageName);
-
-            result.descriptionRes = sa.getResourceId(
-                    R.styleable.AndroidManifestPermission_description, 0);
-
-            if (sa.hasValue(
-                    R.styleable.AndroidManifestPermission_backgroundPermission)) {
-                if ("android".equals(packageName)) {
-                    result.backgroundPermission = sa.getNonResourceString(
-                            R.styleable
-                                    .AndroidManifestPermission_backgroundPermission);
-                } else {
-                    Slog.w(TAG, packageName + " defines a background permission. Only the "
-                            + "'android' package can do that.");
-                }
-            }
-
-            // Note: don't allow this value to be a reference to a resource
-            // that may change.
-            result.setGroup(sa.getNonResourceString(
-                    R.styleable.AndroidManifestPermission_permissionGroup));
-
-            result.requestRes = sa.getResourceId(
-                    R.styleable.AndroidManifestPermission_request, 0);
-
-            result.protectionLevel = sa.getInt(
-                    R.styleable.AndroidManifestPermission_protectionLevel,
-                    PermissionInfo.PROTECTION_NORMAL);
-
-            result.flags = sa.getInt(
-                    R.styleable.AndroidManifestPermission_permissionFlags, 0);
-
-            // For now only platform runtime permissions can be restricted
-            if (!result.isRuntime() || !"android".equals(result.getPackageName())) {
-                result.flags &= ~PermissionInfo.FLAG_HARD_RESTRICTED;
-                result.flags &= ~PermissionInfo.FLAG_SOFT_RESTRICTED;
-            } else {
-                // The platform does not get to specify conflicting permissions
-                if ((result.flags & PermissionInfo.FLAG_HARD_RESTRICTED) != 0
-                        && (result.flags & PermissionInfo.FLAG_SOFT_RESTRICTED) != 0) {
-                    throw new IllegalStateException("Permission cannot be both soft and hard"
-                            + " restricted: " + result.getName());
-                }
-            }
-
-        } finally {
-            if (sa != null) {
-                sa.recycle();
-            }
-        }
-
-        if (result.protectionLevel == -1) {
-            outError[0] = "<permission> does not specify protectionLevel";
-            return null;
-        }
-
-        result.protectionLevel = PermissionInfo.fixProtectionLevel(result.protectionLevel);
-
-        if (result.getProtectionFlags() != 0) {
-            if ((result.protectionLevel & PermissionInfo.PROTECTION_FLAG_INSTANT) == 0
-                    && (result.protectionLevel & PermissionInfo.PROTECTION_FLAG_RUNTIME_ONLY)
-                    == 0
-                    && (result.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE) !=
-                    PermissionInfo.PROTECTION_SIGNATURE) {
-                outError[0] = "<permission>  protectionLevel specifies a non-instant flag but is "
-                        + "not based on signature type";
-                return null;
-            }
-        }
-
-        boolean success = parseAllMetaData(parsingPackage, res, parser,
-                "<permission>", result, outError);
-        if (!success || outError[0] != null) {
-            return null;
-        }
-
-        return result;
-    }
-
-    public static ParsedPermission parsePermissionTree(
-            ParsingPackage parsingPackage,
-            Resources res,
-            XmlResourceParser parser,
-            String[] outError
-    ) throws IOException, XmlPullParserException {
-        TypedArray sa = null;
-        String packageName = parsingPackage.getPackageName();
-        ParsedPermission result = new ParsedPermission();
-
-        try {
-            sa = res.obtainAttributes(parser, R.styleable.AndroidManifestPermissionTree);
-
-            String name = sa.getNonConfigurationString(
-                    R.styleable.AndroidManifestPermissionTree_name, 0);
-            if (name == null) {
-                outError[0] = "<permission-tree> does not specify android:name";
-                return null;
-            } else {
-                String className = ApkParseUtils.buildClassName(packageName, name);
-                if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) {
-                    outError[0] = "<permission-tree> invalid android:name";
-                    return null;
-                } else if (className == null) {
-                    outError[0] = "Empty class name in package " + packageName;
-                    return null;
-                }
-
-                result.className = className;
-            }
-
-            int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId(
-                    R.styleable.AndroidManifestPermissionTree_roundIcon, 0) : 0;
-            if (roundIconVal != 0) {
-                result.icon = roundIconVal;
-                result.nonLocalizedLabel = null;
-            } else {
-                int iconVal = sa.getResourceId(R.styleable.AndroidManifestPermissionTree_icon, 0);
-                if (iconVal != 0) {
-                    result.icon = iconVal;
-                    result.nonLocalizedLabel = null;
-                }
-            }
-
-            int logoVal = sa.getResourceId(R.styleable.AndroidManifestPermissionTree_logo, 0);
-            if (logoVal != 0) {
-                result.logo = logoVal;
-            }
-
-            int bannerVal = sa.getResourceId(R.styleable.AndroidManifestPermissionTree_banner, 0);
-            if (bannerVal != 0) {
-                result.banner = bannerVal;
-            }
-
-            TypedValue v = sa.peekValue(R.styleable.AndroidManifestPermissionTree_label);
-            if (v != null && (result.labelRes = v.resourceId) == 0) {
-                result.nonLocalizedLabel = v.coerceToString();
-            }
-
-            result.setPackageNameInternal(packageName);
-        } finally {
-            if (sa != null) {
-                sa.recycle();
-            }
-        }
-
-        int index = result.getName().indexOf('.');
-        if (index > 0) {
-            index = result.getName().indexOf('.', index + 1);
-        }
-        if (index < 0) {
-            outError[0] =
-                    "<permission-tree> name has less than three segments: " + result.getName();
-            return null;
-        }
-
-        result.descriptionRes = 0;
-        result.requestRes = 0;
-        result.protectionLevel = PermissionInfo.PROTECTION_NORMAL;
-        result.tree = true;
-
-        boolean success = parseAllMetaData(parsingPackage, res, parser,
-                "<permission-tree>", result, outError);
-        if (!success || outError[0] != null) {
-            return null;
-        }
-
-        return result;
-    }
-
-    public static ParsedPermissionGroup parsePermissionGroup(
-            ParsingPackage parsingPackage,
-            Resources res,
-            XmlResourceParser parser,
-            String[] outError
-    ) throws IOException, XmlPullParserException {
-        TypedArray sa = null;
-        String packageName = parsingPackage.getPackageName();
-        ParsedPermissionGroup result = new ParsedPermissionGroup();
-
-        try {
-            sa = res.obtainAttributes(parser, R.styleable.AndroidManifestPermissionGroup);
-
-            String name = sa.getNonConfigurationString(
-                    R.styleable.AndroidManifestPermissionGroup_name, 0);
-            if (name == null) {
-                outError[0] = "<permission> does not specify android:name";
-                return null;
-            } else {
-                String className = ApkParseUtils.buildClassName(packageName, name);
-                if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) {
-                    outError[0] = "<permission> invalid android:name";
-                    return null;
-                } else if (className == null) {
-                    outError[0] = "Empty class name in package " + packageName;
-                    return null;
-                }
-
-                result.className = className;
-            }
-
-            int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId(
-                    R.styleable.AndroidManifestPermissionGroup_roundIcon, 0) : 0;
-            if (roundIconVal != 0) {
-                result.icon = roundIconVal;
-                result.nonLocalizedLabel = null;
-            } else {
-                int iconVal = sa.getResourceId(R.styleable.AndroidManifestPermissionGroup_icon, 0);
-                if (iconVal != 0) {
-                    result.icon = iconVal;
-                    result.nonLocalizedLabel = null;
-                }
-            }
-
-            int logoVal = sa.getResourceId(R.styleable.AndroidManifestPermissionGroup_logo, 0);
-            if (logoVal != 0) {
-                result.logo = logoVal;
-            }
-
-            int bannerVal = sa.getResourceId(R.styleable.AndroidManifestPermissionGroup_banner, 0);
-            if (bannerVal != 0) {
-                result.banner = bannerVal;
-            }
-
-            TypedValue v = sa.peekValue(R.styleable.AndroidManifestPermissionGroup_label);
-            if (v != null && (result.labelRes = v.resourceId) == 0) {
-                result.nonLocalizedLabel = v.coerceToString();
-            }
-
-            result.setPackageNameInternal(packageName);
-
-            result.descriptionRes = sa.getResourceId(
-                    R.styleable.AndroidManifestPermissionGroup_description, 0);
-
-            result.requestDetailResourceId = sa.getResourceId(
-                    R.styleable.AndroidManifestPermissionGroup_requestDetail, 0);
-            result.backgroundRequestResourceId = sa.getResourceId(
-                    R.styleable.AndroidManifestPermissionGroup_backgroundRequest,
-                    0);
-            result.backgroundRequestDetailResourceId = sa.getResourceId(
-                    R.styleable
-                            .AndroidManifestPermissionGroup_backgroundRequestDetail, 0);
-
-            result.requestRes = sa.getResourceId(
-                    R.styleable.AndroidManifestPermissionGroup_request, 0);
-            result.flags = sa.getInt(
-                    R.styleable.AndroidManifestPermissionGroup_permissionGroupFlags,
-                    0);
-            result.priority = sa.getInt(
-                    R.styleable.AndroidManifestPermissionGroup_priority, 0);
-
-        } finally {
-            if (sa != null) {
-                sa.recycle();
-            }
-        }
-
-        boolean success = parseAllMetaData(parsingPackage, res, parser,
-                "<permission-group>", result, outError);
-        if (!success || outError[0] != null) {
-            return null;
-        }
-
-        return result;
-    }
-
-    public static ParsedInstrumentation parseInstrumentation(
-            ParsingPackage parsingPackage,
-            Resources res,
-            XmlResourceParser parser,
-            String[] outError
-    ) throws IOException, XmlPullParserException {
-        TypedArray sa = null;
-        String packageName = parsingPackage.getPackageName();
-        ParsedInstrumentation result = new ParsedInstrumentation();
-
-        try {
-            sa = res.obtainAttributes(parser, R.styleable.AndroidManifestInstrumentation);
-
-            // TODO(b/135203078): Re-share all of the configuration for this. ParseComponentArgs was
-            //  un-used for this, but can be adjusted and re-added to share all the initial result
-            //  parsing for icon/logo/name/etc in all of these parse methods.
-            String name = sa.getNonConfigurationString(
-                    R.styleable.AndroidManifestInstrumentation_name, 0);
-            if (name == null) {
-                outError[0] = "<instrumentation> does not specify android:name";
-                return null;
-            } else {
-                String className = ApkParseUtils.buildClassName(packageName, name);
-                if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) {
-                    outError[0] = "<instrumentation> invalid android:name";
-                    return null;
-                } else if (className == null) {
-                    outError[0] = "Empty class name in package " + packageName;
-                    return null;
-                }
-
-                result.className = className;
-            }
-
-            int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId(
-                    R.styleable.AndroidManifestInstrumentation_roundIcon, 0) : 0;
-            if (roundIconVal != 0) {
-                result.icon = roundIconVal;
-                result.nonLocalizedLabel = null;
-            } else {
-                int iconVal = sa.getResourceId(R.styleable.AndroidManifestInstrumentation_icon, 0);
-                if (iconVal != 0) {
-                    result.icon = iconVal;
-                    result.nonLocalizedLabel = null;
-                }
-            }
-
-            int logoVal = sa.getResourceId(R.styleable.AndroidManifestInstrumentation_logo, 0);
-            if (logoVal != 0) {
-                result.logo = logoVal;
-            }
-
-            int bannerVal = sa.getResourceId(R.styleable.AndroidManifestInstrumentation_banner, 0);
-            if (bannerVal != 0) {
-                result.banner = bannerVal;
-            }
-
-            TypedValue v = sa.peekValue(R.styleable.AndroidManifestInstrumentation_label);
-            if (v != null && (result.labelRes = v.resourceId) == 0) {
-                result.nonLocalizedLabel = v.coerceToString();
-            }
-
-            result.setPackageNameInternal(packageName);
-
-            String str;
-            // Note: don't allow this value to be a reference to a resource
-            // that may change.
-            str = sa.getNonResourceString(R.styleable.AndroidManifestInstrumentation_targetPackage);
-            result.setTargetPackage(str);
-
-            str = sa.getNonResourceString(
-                    R.styleable.AndroidManifestInstrumentation_targetProcesses);
-            result.setTargetProcesses(str);
-            result.handleProfiling = sa.getBoolean(
-                    R.styleable.AndroidManifestInstrumentation_handleProfiling, false);
-            result.functionalTest = sa.getBoolean(
-                    R.styleable.AndroidManifestInstrumentation_functionalTest, false);
-
-        } finally {
-            if (sa != null) {
-                sa.recycle();
-            }
-        }
-
-        boolean success = parseAllMetaData(parsingPackage, res, parser,
-                "<instrumentation>", result, outError);
-        if (!success || outError[0] != null) {
-            return null;
-        }
-
-        return result;
-    }
-
-    private static @Nullable ArraySet<String> parseDenyPermission(
-            ArraySet<String> perms,
-            Resources res,
-            XmlResourceParser parser,
-            String[] outError
-    ) throws IOException, XmlPullParserException {
-        TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestDenyPermission);
-        if (sa == null) {
-            outError[0] = "<deny-permission> could not be parsed";
-            return null;
-        }
-
-        try {
-            String perm = sa.getNonConfigurationString(
-                    R.styleable.AndroidManifestDenyPermission_name,0);
-            if (perm != null && perm.equals(android.Manifest.permission.INTERNET)) {
-                if (perms == null) {
-                    perms = new ArraySet<>();
-                }
-                perms.add(perm);
-            }
-        } finally {
-            sa.recycle();
-        }
-        XmlUtils.skipCurrentTag(parser);
-        return perms;
-    }
-
-    private static ArraySet<String> parseAllowPermission(
-            ArraySet<String> perms,
-            Resources res,
-            XmlResourceParser parser,
-            String[] outError
-    ) throws IOException, XmlPullParserException {
-        TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestAllowPermission);
-        if (sa == null) {
-            outError[0] = "<allow-permission> could not be parsed";
-            return null;
-        }
-
-        try {
-            String perm = sa.getNonConfigurationString(
-                    R.styleable.AndroidManifestAllowPermission_name,0);
-            if (perm != null && perm.equals(android.Manifest.permission.INTERNET)
-                    && perms != null) {
-                perms.remove(perm);
-                if (perms.size() <= 0) {
-                    perms = null;
-                }
-            }
-        } finally {
-            sa.recycle();
-        }
-        XmlUtils.skipCurrentTag(parser);
-        return perms;
-    }
-
-    public static ParsedProcess parseProcess(
-            ArraySet<String> perms,
-            String[] separateProcesses,
-            ParsingPackage parsingPackage,
-            Resources res,
-            XmlResourceParser parser,
-            int flags,
-            String[] outError
-    ) throws IOException, XmlPullParserException {
-        TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestProcess);
-        if (sa == null) {
-            outError[0] = "<process> could not be parsed";
-            return null;
-        }
-
-        ParsedProcess proc = new ParsedProcess();
-        if (perms != null) {
-            proc.deniedPermissions = new ArraySet(perms);
-        }
-
-        try {
-            proc.name = sa.getNonConfigurationString(
-                    R.styleable.AndroidManifestProcess_process,0);
-            proc.name = PackageParser.buildProcessName(parsingPackage.getPackageName(),
-                    parsingPackage.getPackageName(), proc.name, flags, separateProcesses, outError);
-            if (outError[0] != null) {
-                return null;
-            }
-            if (proc.name == null || proc.name.length() <= 0) {
-                outError[0] = "<process> does not specify android:process";
-                return null;
-            }
-        } finally {
-            sa.recycle();
-        }
-
-        int type;
-        final int innerDepth = parser.getDepth();
-        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
-                && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
-            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
-                continue;
-            }
-
-            String tagName = parser.getName();
-            if (tagName.equals("deny-permission")) {
-                proc.deniedPermissions = parseDenyPermission(proc.deniedPermissions, res, parser,
-                        outError);
-                if (outError[0] != null) {
-                    return null;
-                }
-            } else if (tagName.equals("allow-permission")) {
-                proc.deniedPermissions = parseAllowPermission(proc.deniedPermissions, res, parser,
-                        outError);
-                if (outError[0] != null) {
-                    return null;
-                }
-            } else {
-                Slog.w(TAG, "Unknown element under <process>: " + tagName
-                        + " at " + parsingPackage.getBaseCodePath() + " "
-                        + parser.getPositionDescription());
-                XmlUtils.skipCurrentTag(parser);
-                continue;
-            }
-        }
-
-        return proc;
-    }
-
-    public static ArrayMap<String, ParsedProcess> parseProcesses(
-            String[] separateProcesses,
-            ParsingPackage parsingPackage,
-            Resources res,
-            XmlResourceParser parser,
-            int flags,
-            String[] outError
-    ) throws IOException, XmlPullParserException {
-        ArraySet<String> deniedPerms = null;
-        ArrayMap<String, ParsedProcess> processes = new ArrayMap<>();
-
-        int type;
-        final int innerDepth = parser.getDepth();
-        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
-                && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
-            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
-                continue;
-            }
-
-            String tagName = parser.getName();
-            if (tagName.equals("deny-permission")) {
-                deniedPerms = parseDenyPermission(deniedPerms, res, parser, outError);
-                if (outError[0] != null) {
-                    return null;
-                }
-            } else if (tagName.equals("allow-permission")) {
-                deniedPerms = parseAllowPermission(deniedPerms, res, parser, outError);
-                if (outError[0] != null) {
-                    return null;
-                }
-            } else if (tagName.equals("process")) {
-                ParsedProcess proc = parseProcess(deniedPerms, separateProcesses, parsingPackage,
-                        res, parser, flags, outError);
-                if (outError[0] != null) {
-                    return null;
-                }
-                if (processes.get(proc.name) != null) {
-                    outError[0] = "<process> specified existing name '" + proc.name + "'";
-                    return null;
-                }
-                processes.put(proc.name, proc);
-            } else {
-                Slog.w(TAG, "Unknown element under <processes>: " + tagName
-                        + " at " + parsingPackage.getBaseCodePath() + " "
-                        + parser.getPositionDescription());
-                XmlUtils.skipCurrentTag(parser);
-                continue;
-            }
-        }
-
-        return processes;
-    }
-
-    public static ActivityInfo.WindowLayout parseLayout(Resources res, AttributeSet attrs) {
-        TypedArray sw = res.obtainAttributes(attrs,
-                R.styleable.AndroidManifestLayout);
-        int width = -1;
-        float widthFraction = -1f;
-        int height = -1;
-        float heightFraction = -1f;
-        final int widthType = sw.getType(
-                R.styleable.AndroidManifestLayout_defaultWidth);
-        if (widthType == TypedValue.TYPE_FRACTION) {
-            widthFraction = sw.getFraction(
-                    R.styleable.AndroidManifestLayout_defaultWidth,
-                    1, 1, -1);
-        } else if (widthType == TypedValue.TYPE_DIMENSION) {
-            width = sw.getDimensionPixelSize(
-                    R.styleable.AndroidManifestLayout_defaultWidth,
-                    -1);
-        }
-        final int heightType = sw.getType(
-                R.styleable.AndroidManifestLayout_defaultHeight);
-        if (heightType == TypedValue.TYPE_FRACTION) {
-            heightFraction = sw.getFraction(
-                    R.styleable.AndroidManifestLayout_defaultHeight,
-                    1, 1, -1);
-        } else if (heightType == TypedValue.TYPE_DIMENSION) {
-            height = sw.getDimensionPixelSize(
-                    R.styleable.AndroidManifestLayout_defaultHeight,
-                    -1);
-        }
-        int gravity = sw.getInt(
-                R.styleable.AndroidManifestLayout_gravity,
-                Gravity.CENTER);
-        int minWidth = sw.getDimensionPixelSize(
-                R.styleable.AndroidManifestLayout_minWidth,
-                -1);
-        int minHeight = sw.getDimensionPixelSize(
-                R.styleable.AndroidManifestLayout_minHeight,
-                -1);
-        sw.recycle();
-        return new ActivityInfo.WindowLayout(width, widthFraction,
-                height, heightFraction, gravity, minWidth, minHeight);
-    }
-
-    public static boolean parseIntentInfo(
-            ParsedIntentInfo intentInfo,
-            ParsingPackage parsingPackage,
-            Resources res, XmlResourceParser parser, boolean allowGlobs,
-            boolean allowAutoVerify, String[] outError
-    ) throws XmlPullParserException, IOException {
-        TypedArray sa = res.obtainAttributes(parser,
-                R.styleable.AndroidManifestIntentFilter);
-
-        int priority = sa.getInt(
-                R.styleable.AndroidManifestIntentFilter_priority, 0);
-        intentInfo.setPriority(priority);
-
-        int order = sa.getInt(
-                R.styleable.AndroidManifestIntentFilter_order, 0);
-        intentInfo.setOrder(order);
-
-        TypedValue v = sa.peekValue(
-                R.styleable.AndroidManifestIntentFilter_label);
-        if (v != null && (intentInfo.labelRes = v.resourceId) == 0) {
-            intentInfo.nonLocalizedLabel = v.coerceToString();
-        }
-
-        int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId(
-                R.styleable.AndroidManifestIntentFilter_roundIcon, 0) : 0;
-        if (roundIconVal != 0) {
-            intentInfo.icon = roundIconVal;
-        } else {
-            intentInfo.icon = sa.getResourceId(
-                    R.styleable.AndroidManifestIntentFilter_icon, 0);
-        }
-
-        if (allowAutoVerify) {
-            intentInfo.setAutoVerify(sa.getBoolean(
-                    R.styleable.AndroidManifestIntentFilter_autoVerify,
-                    false));
-        }
-
-        sa.recycle();
-
-        int outerDepth = parser.getDepth();
-        int type;
-        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
-                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
-            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
-                continue;
-            }
-
-            String nodeName = parser.getName();
-            if (nodeName.equals("action")) {
-                String value = parser.getAttributeValue(
-                        PackageParser.ANDROID_RESOURCES, "name");
-                if (TextUtils.isEmpty(value)) {
-                    outError[0] = "No value supplied for <android:name>";
-                    return false;
-                }
-                XmlUtils.skipCurrentTag(parser);
-
-                intentInfo.addAction(value);
-            } else if (nodeName.equals("category")) {
-                String value = parser.getAttributeValue(
-                        PackageParser.ANDROID_RESOURCES, "name");
-                if (TextUtils.isEmpty(value)) {
-                    outError[0] = "No value supplied for <android:name>";
-                    return false;
-                }
-                XmlUtils.skipCurrentTag(parser);
-
-                intentInfo.addCategory(value);
-
-            } else if (nodeName.equals("data")) {
-                sa = res.obtainAttributes(parser,
-                        R.styleable.AndroidManifestData);
-
-                String str = sa.getNonConfigurationString(
-                        R.styleable.AndroidManifestData_mimeType, 0);
-                if (str != null) {
-                    try {
-                        intentInfo.addRawDataType(str);
-                    } catch (IntentFilter.MalformedMimeTypeException e) {
-                        outError[0] = e.toString();
-                        sa.recycle();
-                        return false;
-                    }
-                }
-
-                str = sa.getNonConfigurationString(
-                        R.styleable.AndroidManifestData_mimeGroup, 0);
-                if (str != null) {
-                    intentInfo.addMimeGroup(str);
-                }
-
-                str = sa.getNonConfigurationString(
-                        R.styleable.AndroidManifestData_scheme, 0);
-                if (str != null) {
-                    intentInfo.addDataScheme(str);
-                }
-
-                str = sa.getNonConfigurationString(
-                        R.styleable.AndroidManifestData_ssp, 0);
-                if (str != null) {
-                    intentInfo.addDataSchemeSpecificPart(str, PatternMatcher.PATTERN_LITERAL);
-                }
-
-                str = sa.getNonConfigurationString(
-                        R.styleable.AndroidManifestData_sspPrefix, 0);
-                if (str != null) {
-                    intentInfo.addDataSchemeSpecificPart(str, PatternMatcher.PATTERN_PREFIX);
-                }
-
-                str = sa.getNonConfigurationString(
-                        R.styleable.AndroidManifestData_sspPattern, 0);
-                if (str != null) {
-                    if (!allowGlobs) {
-                        outError[0] = "sspPattern not allowed here; ssp must be literal";
-                        return false;
-                    }
-                    intentInfo.addDataSchemeSpecificPart(str, PatternMatcher.PATTERN_SIMPLE_GLOB);
-                }
-
-                String host = sa.getNonConfigurationString(
-                        R.styleable.AndroidManifestData_host, 0);
-                String port = sa.getNonConfigurationString(
-                        R.styleable.AndroidManifestData_port, 0);
-                if (host != null) {
-                    intentInfo.addDataAuthority(host, port);
-                }
-
-                str = sa.getNonConfigurationString(
-                        R.styleable.AndroidManifestData_path, 0);
-                if (str != null) {
-                    intentInfo.addDataPath(str, PatternMatcher.PATTERN_LITERAL);
-                }
-
-                str = sa.getNonConfigurationString(
-                        R.styleable.AndroidManifestData_pathPrefix, 0);
-                if (str != null) {
-                    intentInfo.addDataPath(str, PatternMatcher.PATTERN_PREFIX);
-                }
-
-                str = sa.getNonConfigurationString(
-                        R.styleable.AndroidManifestData_pathPattern, 0);
-                if (str != null) {
-                    if (!allowGlobs) {
-                        outError[0] = "pathPattern not allowed here; path must be literal";
-                        return false;
-                    }
-                    intentInfo.addDataPath(str, PatternMatcher.PATTERN_SIMPLE_GLOB);
-                }
-
-                str = sa.getNonConfigurationString(
-                        R.styleable.AndroidManifestData_pathAdvancedPattern, 0);
-                if (str != null) {
-                    if (!allowGlobs) {
-                        outError[0] = "pathAdvancedPattern not allowed here; path must be literal";
-                        return false;
-                    }
-                    intentInfo.addDataPath(str, PatternMatcher.PATTERN_ADVANCED_GLOB);
-                }
-
-                sa.recycle();
-                XmlUtils.skipCurrentTag(parser);
-            } else if (!PackageParser.RIGID_PARSER) {
-                Slog.w(TAG, "Unknown element under <intent-filter>: "
-                        + parser.getName() + " at " + parsingPackage.getBaseCodePath() + " "
-                        + parser.getPositionDescription());
-                XmlUtils.skipCurrentTag(parser);
-            } else {
-                outError[0] = "Bad element under <intent-filter>: " + parser.getName();
-                return false;
-            }
-        }
-
-        intentInfo.hasDefault = intentInfo.hasCategory(Intent.CATEGORY_DEFAULT);
-
-        if (PackageParser.DEBUG_PARSER) {
-            final StringBuilder cats = new StringBuilder("Intent d=");
-            cats.append(intentInfo.hasDefault);
-            cats.append(", cat=");
-
-            final Iterator<String> it = intentInfo.categoriesIterator();
-            if (it != null) {
-                while (it.hasNext()) {
-                    cats.append(' ');
-                    cats.append(it.next());
-                }
-            }
-            Slog.d(TAG, cats.toString());
-        }
-
-        return true;
-    }
-
-    private static boolean parseAllMetaData(
-            ParsingPackage parsingPackage,
-            Resources res, XmlResourceParser parser, String tag,
-            ParsedComponent outInfo,
-            String[] outError
-    ) throws XmlPullParserException, IOException {
-        int outerDepth = parser.getDepth();
-        int type;
-        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
-                && (type != XmlPullParser.END_TAG
-                || parser.getDepth() > outerDepth)) {
-            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
-                continue;
-            }
-
-            if (parser.getName().equals("meta-data")) {
-                if ((outInfo.metaData = ApkParseUtils.parseMetaData(parsingPackage, res, parser,
-                        outInfo.metaData, outError)) == null) {
-                    return false;
-                }
-            } else {
-                if (!PackageParser.RIGID_PARSER) {
-                    Slog.w(TAG, "Unknown element under " + tag + ": "
-                            + parser.getName() + " at " + parsingPackage.getBaseCodePath() + " "
-                            + parser.getPositionDescription());
-                    XmlUtils.skipCurrentTag(parser);
-                    continue;
-                } else {
-                    outError[0] = "Bad element under " + tag + ": " + parser.getName();
-                }
-            }
-        }
-
-        return true;
-    }
-
-    public static boolean isImplicitlyExposedIntent(IntentFilter intent) {
-        return intent.hasCategory(Intent.CATEGORY_BROWSABLE)
-                || intent.hasAction(Intent.ACTION_SEND)
-                || intent.hasAction(Intent.ACTION_SENDTO)
-                || intent.hasAction(Intent.ACTION_SEND_MULTIPLE);
-    }
-}
diff --git a/core/java/android/content/pm/parsing/PackageImpl.java b/core/java/android/content/pm/parsing/PackageImpl.java
deleted file mode 100644
index d06865b..0000000
--- a/core/java/android/content/pm/parsing/PackageImpl.java
+++ /dev/null
@@ -1,3379 +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 static android.os.Build.VERSION_CODES.DONUT;
-
-import static java.util.Collections.emptyMap;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.ActivityInfo;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.ConfigurationInfo;
-import android.content.pm.FeatureGroupInfo;
-import android.content.pm.FeatureInfo;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageParser;
-import android.content.pm.ProviderInfo;
-import android.content.pm.ServiceInfo;
-import android.content.pm.SharedLibraryInfo;
-import android.content.pm.parsing.ComponentParseUtils.ParsedActivity;
-import android.content.pm.parsing.ComponentParseUtils.ParsedActivityIntentInfo;
-import android.content.pm.parsing.ComponentParseUtils.ParsedComponent;
-import android.content.pm.parsing.ComponentParseUtils.ParsedFeature;
-import android.content.pm.parsing.ComponentParseUtils.ParsedInstrumentation;
-import android.content.pm.parsing.ComponentParseUtils.ParsedIntentInfo;
-import android.content.pm.parsing.ComponentParseUtils.ParsedPermission;
-import android.content.pm.parsing.ComponentParseUtils.ParsedPermissionGroup;
-import android.content.pm.parsing.ComponentParseUtils.ParsedProvider;
-import android.content.pm.parsing.ComponentParseUtils.ParsedService;
-import android.content.res.TypedArray;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.Environment;
-import android.os.Parcel;
-import android.os.UserHandle;
-import android.os.storage.StorageManager;
-import android.text.TextUtils;
-import android.util.ArrayMap;
-import android.util.ArraySet;
-import android.util.SparseArray;
-
-import com.android.internal.R;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.ArrayUtils;
-import com.android.internal.util.CollectionUtils;
-import com.android.server.SystemConfig;
-
-import java.security.PublicKey;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Set;
-import java.util.UUID;
-
-/**
- * The backing data for a package that was parsed from disk.
- *
- * TODO(b/135203078): Convert Lists used as sets into Sets, to better express intended use case
- * TODO(b/135203078): Field nullability annotations
- * TODO(b/135203078): Convert = 1 fields into Booleans
- * TODO(b/135203078): Make all lists nullable and Collections.unmodifiable immutable when returned.
- *   Prefer add/set methods if adding is necessary.
- * TODO(b/135203078): Consider comments to disable auto-format and single-line, single-space all the
- *   get/set methods to make this class far more compact. Maybe even separate some logic into parent
- *   classes, assuming there is no overhead.
- * TODO(b/135203078): Copy documentation from PackageParser#Package for the relevant fields included
- *   here. Should clarify and clean up any differences. Also consider renames if it helps make
- *   things clearer.
- * TODO(b/135203078): Intern all possibl e String values? Initial refactor just mirrored old
- *   behavior.
- *
- * @hide
- */
-public final class PackageImpl implements ParsingPackage, ParsedPackage, AndroidPackage,
-        AndroidPackageWrite {
-
-    private static final String TAG = "PackageImpl";
-
-    // Resource boolean are -1, so 1 means we don't know the value.
-    private int supportsSmallScreens = 1;
-    private int supportsNormalScreens = 1;
-    private int supportsLargeScreens = 1;
-    private int supportsXLargeScreens = 1;
-    private int resizeable = 1;
-    private int anyDensity = 1;
-
-    private long[] lastPackageUsageTimeInMills =
-            new long[PackageManager.NOTIFY_PACKAGE_USE_REASONS_COUNT];
-
-    private int versionCode;
-    private int versionCodeMajor;
-    private int baseRevisionCode;
-    private String versionName;
-
-    private boolean coreApp;
-    private int compileSdkVersion;
-    private String compileSdkVersionCodename;
-
-    private String packageName;
-    private String realPackage;
-    private String manifestPackageName;
-    private String baseCodePath;
-
-    private boolean requiredForAllUsers;
-    private String restrictedAccountType;
-    private String requiredAccountType;
-
-    private boolean baseHardwareAccelerated;
-
-    private String overlayTarget;
-    private String overlayTargetName;
-    private String overlayCategory;
-    private int overlayPriority;
-    private boolean overlayIsStatic;
-    private Map<String, String> overlayables = emptyMap();
-
-    private String staticSharedLibName;
-    private long staticSharedLibVersion;
-    private ArrayList<String> libraryNames;
-    private ArrayList<String> usesLibraries;
-    private ArrayList<String> usesOptionalLibraries;
-
-    private ArrayList<String> usesStaticLibraries;
-    private long[] usesStaticLibrariesVersions;
-    private String[][] usesStaticLibrariesCertDigests;
-
-    private String sharedUserId;
-
-    private int sharedUserLabel;
-    private ArrayList<ConfigurationInfo> configPreferences;
-    private ArrayList<FeatureInfo> reqFeatures;
-    private ArrayList<FeatureGroupInfo> featureGroups;
-
-    private byte[] restrictUpdateHash;
-
-    private ArrayList<String> originalPackages;
-    private ArrayList<String> adoptPermissions;
-
-    private ArrayList<String> requestedPermissions;
-    private ArrayList<String> implicitPermissions;
-
-    private ArraySet<String> upgradeKeySets;
-    private Map<String, ArraySet<PublicKey>> keySetMapping;
-
-    private ArrayList<String> protectedBroadcasts;
-
-    @Nullable
-    private ArrayList<ComponentParseUtils.ParsedActivity> activities;
-
-    @Nullable
-    private ArrayList<ComponentParseUtils.ParsedActivity> receivers;
-
-    @Nullable
-    private ArrayList<ComponentParseUtils.ParsedService> services;
-
-    @Nullable
-    private ArrayList<ComponentParseUtils.ParsedProvider> providers;
-
-    @Nullable
-    private ArrayList<ComponentParseUtils.ParsedFeature> features;
-
-    @Nullable
-    private ArrayList<ComponentParseUtils.ParsedPermission> permissions;
-
-    @Nullable
-    private ArrayList<ComponentParseUtils.ParsedPermissionGroup> permissionGroups;
-
-    @Nullable
-    private ArrayList<ComponentParseUtils.ParsedInstrumentation> instrumentations;
-
-    private ArrayList<ParsedActivityIntentInfo> preferredActivityFilters;
-
-    private Bundle appMetaData;
-
-    private String volumeUuid;
-    private String applicationVolumeUuid;
-    private PackageParser.SigningDetails signingDetails;
-
-    private String codePath;
-
-    private boolean use32BitAbi;
-    private boolean visibleToInstantApps;
-
-    private String cpuAbiOverride;
-
-    private boolean isStub;
-
-    // TODO(b/135203078): Remove, should be unused
-    private int preferredOrder;
-
-    private boolean forceQueryable;
-
-    @Nullable
-    private ArrayList<Intent> queriesIntents;
-
-    @Nullable
-    private ArrayList<String> queriesPackages;
-
-    @Nullable
-    private ArraySet<String> queriesProviders;
-
-    @Nullable
-    private ArrayMap<String, ComponentParseUtils.ParsedProcess> processes;
-
-    private String[] splitClassLoaderNames;
-    private String[] splitCodePaths;
-    private SparseArray<int[]> splitDependencies;
-    private int[] splitFlags;
-    private String[] splitNames;
-    private int[] splitRevisionCodes;
-
-    // TODO(b/135203078): Audit applicationInfo.something usages, which may be different from
-    //  package.something usages. There were differing cases of package.field = versus
-    //  package.appInfo.field =. This class assumes some obvious ones, like packageName,
-    //  were collapsible, but kept the following separate.
-
-    private String applicationInfoBaseResourcePath;
-    private String applicationInfoCodePath;
-    private String applicationInfoResourcePath;
-    private String[] applicationInfoSplitResourcePaths;
-
-    private String appComponentFactory;
-    private String backupAgentName;
-    private int banner;
-    private int category;
-    private String classLoaderName;
-    private String className;
-    private int compatibleWidthLimitDp;
-    private String credentialProtectedDataDir;
-    private String dataDir;
-    private int descriptionRes;
-    private String deviceProtectedDataDir;
-    private boolean enabled;
-    private boolean crossProfile;
-    private int flags;
-    private int fullBackupContent;
-    private boolean hiddenUntilInstalled;
-    private int icon;
-    private int iconRes;
-    private int installLocation = PackageParser.PARSE_DEFAULT_INSTALL_LOCATION;
-    private int labelRes;
-    private int largestWidthLimitDp;
-    private int logo;
-    private String manageSpaceActivityName;
-    private float maxAspectRatio;
-    private float minAspectRatio;
-    private int minSdkVersion;
-    private String name;
-    private String nativeLibraryDir;
-    private String nativeLibraryRootDir;
-    private boolean nativeLibraryRootRequiresIsa;
-    private int networkSecurityConfigRes;
-    private CharSequence nonLocalizedLabel;
-    private String permission;
-    private String primaryCpuAbi;
-    private int privateFlags;
-    private String processName;
-    private int requiresSmallestWidthDp;
-    private int roundIconRes;
-    private String secondaryCpuAbi;
-    private String secondaryNativeLibraryDir;
-    private String seInfo;
-    private String seInfoUser;
-    private int targetSandboxVersion;
-    private int targetSdkVersion;
-    private String taskAffinity;
-    private int theme;
-    private int uid = -1;
-    private int uiOptions;
-    private String[] usesLibraryFiles;
-    private List<SharedLibraryInfo> usesLibraryInfos;
-    private String zygotePreloadName;
-    private boolean preserveLegacyExternalStorage;
-
-    @Nullable
-    private ArraySet<String> mimeGroups;
-
-    @VisibleForTesting
-    public PackageImpl(
-            String packageName,
-            String baseCodePath,
-            TypedArray manifestArray,
-            boolean isCoreApp
-    ) {
-        this.packageName = TextUtils.safeIntern(packageName);
-        this.manifestPackageName = this.packageName;
-        this.baseCodePath = baseCodePath;
-
-        this.versionCode = manifestArray.getInteger(R.styleable.AndroidManifest_versionCode, 0);
-        this.versionCodeMajor = manifestArray.getInteger(
-                R.styleable.AndroidManifest_versionCodeMajor, 0);
-        this.baseRevisionCode = manifestArray.getInteger(R.styleable.AndroidManifest_revisionCode,
-                0);
-        setVersionName(manifestArray.getNonConfigurationString(
-                R.styleable.AndroidManifest_versionName, 0));
-        this.coreApp = isCoreApp;
-
-        this.compileSdkVersion = manifestArray.getInteger(
-                R.styleable.AndroidManifest_compileSdkVersion, 0);
-        setCompileSdkVersionCodename(manifestArray.getNonConfigurationString(
-                R.styleable.AndroidManifest_compileSdkVersionCodename, 0));
-    }
-
-    private PackageImpl(String packageName) {
-        this.packageName = TextUtils.safeIntern(packageName);
-        this.manifestPackageName = this.packageName;
-    }
-
-    @VisibleForTesting
-    public static ParsingPackage forParsing(String packageName) {
-        return new PackageImpl(packageName);
-    }
-
-    @VisibleForTesting
-    public static ParsingPackage forParsing(
-            String packageName,
-            String baseCodePath,
-            TypedArray manifestArray,
-            boolean isCoreApp) {
-        return new PackageImpl(packageName, baseCodePath, manifestArray, isCoreApp);
-    }
-
-    /**
-     * Mock an unavailable {@link AndroidPackage} to use when removing a package from the system.
-     * This can occur if the package was installed on a storage device that has since been removed.
-     * Since the infrastructure uses {@link AndroidPackage}, but for this case only cares about
-     * volumeUuid, just fake it rather than having separate method paths.
-     */
-    public static AndroidPackage buildFakeForDeletion(String packageName, String volumeUuid) {
-        return new PackageImpl(packageName)
-                .setVolumeUuid(volumeUuid)
-                .hideAsParsed()
-                .hideAsFinal();
-    }
-
-    @Override
-    public ParsedPackage hideAsParsed() {
-        return this;
-    }
-
-    @Override
-    public AndroidPackage hideAsFinal() {
-        updateFlags();
-        return this;
-    }
-
-    @Override
-    @Deprecated
-    public AndroidPackageWrite mutate() {
-        return this;
-    }
-
-    private void updateFlags() {
-        if (supportsSmallScreens < 0 || (supportsSmallScreens > 0
-                && targetSdkVersion
-                >= Build.VERSION_CODES.DONUT)) {
-            this.flags |= ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS;
-        }
-        if (supportsNormalScreens != 0) {
-            this.flags |= ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS;
-        }
-        if (supportsLargeScreens < 0 || (supportsLargeScreens > 0
-                && targetSdkVersion
-                >= Build.VERSION_CODES.DONUT)) {
-            this.flags |= ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS;
-        }
-        if (supportsXLargeScreens < 0 || (supportsXLargeScreens > 0
-                && targetSdkVersion
-                >= Build.VERSION_CODES.GINGERBREAD)) {
-            this.flags |= ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS;
-        }
-        if (resizeable < 0 || (resizeable > 0
-                && targetSdkVersion
-                >= Build.VERSION_CODES.DONUT)) {
-            this.flags |= ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS;
-        }
-        if (anyDensity < 0 || (anyDensity > 0
-                && targetSdkVersion
-                >= Build.VERSION_CODES.DONUT)) {
-            this.flags |= ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES;
-        }
-    }
-
-    @Override
-    public boolean usesCompatibilityMode() {
-        int flags = 0;
-
-        if (supportsSmallScreens < 0 || (supportsSmallScreens > 0
-                && targetSdkVersion
-                >= Build.VERSION_CODES.DONUT)) {
-            flags |= ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS;
-        }
-        if (supportsNormalScreens != 0) {
-            flags |= ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS;
-        }
-        if (supportsLargeScreens < 0 || (supportsLargeScreens > 0
-                && targetSdkVersion
-                >= Build.VERSION_CODES.DONUT)) {
-            flags |= ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS;
-        }
-        if (supportsXLargeScreens < 0 || (supportsXLargeScreens > 0
-                && targetSdkVersion
-                >= Build.VERSION_CODES.GINGERBREAD)) {
-            flags |= ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS;
-        }
-        if (resizeable < 0 || (resizeable > 0
-                && targetSdkVersion
-                >= Build.VERSION_CODES.DONUT)) {
-            flags |= ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS;
-        }
-        if (anyDensity < 0 || (anyDensity > 0
-                && targetSdkVersion
-                >= Build.VERSION_CODES.DONUT)) {
-            flags |= ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES;
-        }
-
-        return targetSdkVersion < DONUT
-                || (flags & (ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS
-                        | ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS
-                        | ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS
-                        | ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS
-                        | ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES
-                        | ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS)) == 0;
-    }
-
-    @Override
-    public String getBaseCodePath() {
-        return baseCodePath;
-    }
-
-    @Override
-    public int getTargetSdkVersion() {
-        return targetSdkVersion;
-    }
-
-    @Override
-    public String getPackageName() {
-        return packageName;
-    }
-
-    @Override
-    public String getProcessName() {
-        return processName;
-    }
-
-    @Override
-    public String getPermission() {
-        return permission;
-    }
-
-    @Override
-    public String getStaticSharedLibName() {
-        return staticSharedLibName;
-    }
-
-    @Override
-    public long getStaticSharedLibVersion() {
-        return staticSharedLibVersion;
-    }
-
-    @Override
-    public String getSharedUserId() {
-        return sharedUserId;
-    }
-
-    @Override
-    public List<String> getRequestedPermissions() {
-        return requestedPermissions == null ? Collections.emptyList() : requestedPermissions;
-    }
-
-    @Nullable
-    @Override
-    public List<ParsedInstrumentation> getInstrumentations() {
-        return instrumentations;
-    }
-
-    @Override
-    public Map<String, ArraySet<PublicKey>> getKeySetMapping() {
-        return keySetMapping == null ? emptyMap() : keySetMapping;
-    }
-
-    @Override
-    public float getMaxAspectRatio() {
-        return maxAspectRatio;
-    }
-
-    @Override
-    public float getMinAspectRatio() {
-        return minAspectRatio;
-    }
-
-    @NonNull
-    @Override
-    public List<String> getLibraryNames() {
-        return libraryNames == null ? Collections.emptyList() : libraryNames;
-    }
-
-    @Override
-    public List<ParsedActivity> getActivities() {
-        return activities == null ? Collections.emptyList()
-                : activities;
-    }
-
-    @Override
-    public Bundle getAppMetaData() {
-        return appMetaData;
-    }
-
-    @Nullable
-    @Override
-    public List<String> getUsesLibraries() {
-        return usesLibraries;
-    }
-
-    @Nullable
-    @Override
-    public List<String> getUsesStaticLibraries() {
-        return usesStaticLibraries;
-    }
-
-    @Nullable
-    @Override
-    public ArrayMap<String, ComponentParseUtils.ParsedProcess> getProcesses() {
-        return processes;
-    }
-
-    @Override
-    public boolean isBaseHardwareAccelerated() {
-        return baseHardwareAccelerated;
-    }
-
-    @Override
-    public int getUiOptions() {
-        return uiOptions;
-    }
-
-    // TODO(b/135203078): Checking flags directly can be error prone,
-    //  consider separate interface methods?
-    @Override
-    public int getFlags() {
-        return flags;
-    }
-
-    // TODO(b/135203078): Checking flags directly can be error prone,
-    //  consider separate interface methods?
-    @Override
-    public int getPrivateFlags() {
-        return privateFlags;
-    }
-
-    @Override
-    public String getTaskAffinity() {
-        return taskAffinity;
-    }
-
-    @Nullable
-    @Override
-    public List<String> getOriginalPackages() {
-        return originalPackages;
-    }
-
-    @Override
-    public PackageParser.SigningDetails getSigningDetails() {
-        return signingDetails;
-    }
-
-    @Override
-    public String getVolumeUuid() {
-        return volumeUuid;
-    }
-
-    @Nullable
-    @Override
-    public List<ParsedPermissionGroup> getPermissionGroups() {
-        return permissionGroups;
-    }
-
-    @Nullable
-    @Override
-    public List<ParsedPermission> getPermissions() {
-        return permissions;
-    }
-
-    @Nullable
-    @Override
-    public List<ParsedFeature> getFeatures() {
-        return features;
-    }
-
-    @Override
-    public String getCpuAbiOverride() {
-        return cpuAbiOverride;
-    }
-
-    @Override
-    public String getPrimaryCpuAbi() {
-        return primaryCpuAbi;
-    }
-
-    @Override
-    public String getSecondaryCpuAbi() {
-        return secondaryCpuAbi;
-    }
-
-    @Override
-    public boolean isUse32BitAbi() {
-        return use32BitAbi;
-    }
-
-    @Override
-    public boolean isForceQueryable() {
-        return forceQueryable;
-    }
-
-    @Override
-    public String getCodePath() {
-        return codePath;
-    }
-
-    @Override
-    public String getNativeLibraryDir() {
-        return nativeLibraryDir;
-    }
-
-    @Override
-    public String getNativeLibraryRootDir() {
-        return nativeLibraryRootDir;
-    }
-
-    @Override
-    public boolean isNativeLibraryRootRequiresIsa() {
-        return nativeLibraryRootRequiresIsa;
-    }
-
-    // TODO(b/135203078): Does nothing, remove?
-    @Override
-    public int getPreferredOrder() {
-        return preferredOrder;
-    }
-
-    @Override
-    public long getLongVersionCode() {
-        return PackageInfo.composeLongVersionCode(versionCodeMajor, versionCode);
-    }
-
-    @Override
-    public PackageImpl setIsOverlay(boolean isOverlay) {
-        this.privateFlags = isOverlay
-                ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_IS_RESOURCE_OVERLAY
-                : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_IS_RESOURCE_OVERLAY;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setExternalStorage(boolean externalStorage) {
-        this.flags = externalStorage
-                ? this.flags | ApplicationInfo.FLAG_EXTERNAL_STORAGE
-                : this.flags & ~ApplicationInfo.FLAG_EXTERNAL_STORAGE;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setIsolatedSplitLoading(boolean isolatedSplitLoading) {
-        this.privateFlags = isolatedSplitLoading
-                ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_ISOLATED_SPLIT_LOADING
-                : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_ISOLATED_SPLIT_LOADING;
-        return this;
-    }
-
-    @Override
-    public PackageImpl sortActivities() {
-        Collections.sort(this.activities, (a1, a2) -> Integer.compare(a2.order, a1.order));
-        return this;
-    }
-
-    @Override
-    public PackageImpl sortReceivers() {
-        Collections.sort(this.receivers, (a1, a2) -> Integer.compare(a2.order, a1.order));
-        return this;
-    }
-
-    @Override
-    public PackageImpl sortServices() {
-        Collections.sort(this.services, (a1, a2) -> Integer.compare(a2.order, a1.order));
-        return this;
-    }
-
-    @Override
-    public PackageImpl setBaseRevisionCode(int baseRevisionCode) {
-        this.baseRevisionCode = baseRevisionCode;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setPreferredOrder(int preferredOrder) {
-        this.preferredOrder = preferredOrder;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setVersionName(String versionName) {
-        this.versionName = TextUtils.safeIntern(versionName);
-        return this;
-    }
-
-    @Override
-    public ParsingPackage setCompileSdkVersion(int compileSdkVersion) {
-        this.compileSdkVersion = compileSdkVersion;
-        return this;
-    }
-
-    @Override
-    public ParsingPackage setCompileSdkVersionCodename(String compileSdkVersionCodename) {
-        this.compileSdkVersionCodename = TextUtils.safeIntern(compileSdkVersionCodename);
-        return this;
-    }
-
-    @Override
-    public PackageImpl setMaxAspectRatio(float maxAspectRatio) {
-        this.maxAspectRatio = maxAspectRatio;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setMinAspectRatio(float minAspectRatio) {
-        this.minAspectRatio = minAspectRatio;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setMinSdkVersion(int minSdkVersion) {
-        this.minSdkVersion = minSdkVersion;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setTargetSdkVersion(int targetSdkVersion) {
-        this.targetSdkVersion = targetSdkVersion;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setRealPackage(String realPackage) {
-        this.realPackage = realPackage;
-        return this;
-    }
-
-    @Override
-    public PackageImpl addConfigPreference(ConfigurationInfo configPreference) {
-        this.configPreferences = ArrayUtils.add(this.configPreferences, configPreference);
-        return this;
-    }
-
-    @Override
-    public PackageImpl addReqFeature(FeatureInfo reqFeature) {
-        this.reqFeatures = ArrayUtils.add(this.reqFeatures, reqFeature);
-        return this;
-    }
-
-    @Override
-    public PackageImpl addFeatureGroup(FeatureGroupInfo featureGroup) {
-        this.featureGroups = ArrayUtils.add(this.featureGroups, featureGroup);
-        return this;
-    }
-
-    @Override
-    public PackageImpl addProtectedBroadcast(String protectedBroadcast) {
-        if (this.protectedBroadcasts == null
-                || !this.protectedBroadcasts.contains(protectedBroadcast)) {
-            this.protectedBroadcasts = ArrayUtils.add(this.protectedBroadcasts,
-                    TextUtils.safeIntern(protectedBroadcast));
-        }
-        return this;
-    }
-
-    @Override
-    public PackageImpl addInstrumentation(ParsedInstrumentation instrumentation) {
-        this.instrumentations = ArrayUtils.add(this.instrumentations, instrumentation);
-        return this;
-    }
-
-    @Override
-    public PackageImpl addOriginalPackage(String originalPackage) {
-        this.originalPackages = ArrayUtils.add(this.originalPackages, originalPackage);
-        return this;
-    }
-
-    @Override
-    public ParsingPackage addOverlayable(String overlayableName, String actorName) {
-        this.overlayables = CollectionUtils.add(this.overlayables,
-                TextUtils.safeIntern(overlayableName), TextUtils.safeIntern(actorName));
-        return this;
-    }
-
-    @Override
-    public PackageImpl addAdoptPermission(String adoptPermission) {
-        this.adoptPermissions = ArrayUtils.add(this.adoptPermissions, adoptPermission);
-        return this;
-    }
-
-    @Override
-    public PackageImpl addFeature(ParsedFeature feature) {
-        this.features = ArrayUtils.add(this.features, feature);
-        return this;
-    }
-
-    @Override
-    public PackageImpl addPermission(ParsedPermission permission) {
-        this.permissions = ArrayUtils.add(this.permissions, permission);
-        return this;
-    }
-
-    @Override
-    public PackageImpl removePermission(int index) {
-        this.permissions.remove(index);
-        return this;
-    }
-
-    @Override
-    public PackageImpl addPermissionGroup(ParsedPermissionGroup permissionGroup) {
-        this.permissionGroups = ArrayUtils.add(this.permissionGroups, permissionGroup);
-        return this;
-    }
-
-    @Override
-    public PackageImpl addRequestedPermission(String permission) {
-        this.requestedPermissions = ArrayUtils.add(this.requestedPermissions,
-                TextUtils.safeIntern(permission));
-        return this;
-    }
-
-    @Override
-    public PackageImpl addImplicitPermission(String permission) {
-        this.implicitPermissions = ArrayUtils.add(this.implicitPermissions,
-                TextUtils.safeIntern(permission));
-        return this;
-    }
-
-    @Override
-    public PackageImpl addKeySet(String keySetName, PublicKey publicKey) {
-        if (keySetMapping == null) {
-            keySetMapping = new ArrayMap<>();
-        }
-
-        ArraySet<PublicKey> publicKeys = keySetMapping.get(keySetName);
-        if (publicKeys == null) {
-            publicKeys = new ArraySet<>();
-            keySetMapping.put(keySetName, publicKeys);
-        }
-
-        publicKeys.add(publicKey);
-
-        return this;
-    }
-
-    @Override
-    public ParsingPackage addActivity(ParsedActivity parsedActivity) {
-        this.activities = ArrayUtils.add(this.activities, parsedActivity);
-        addMimeGroupsFromComponent(parsedActivity);
-        return this;
-    }
-
-    @Override
-    public ParsingPackage addReceiver(ParsedActivity parsedReceiver) {
-        this.receivers = ArrayUtils.add(this.receivers, parsedReceiver);
-        addMimeGroupsFromComponent(parsedReceiver);
-        return this;
-    }
-
-    @Override
-    public ParsingPackage addService(ParsedService parsedService) {
-        this.services = ArrayUtils.add(this.services, parsedService);
-        addMimeGroupsFromComponent(parsedService);
-        return this;
-    }
-
-    @Override
-    public ParsingPackage addProvider(ParsedProvider parsedProvider) {
-        this.providers = ArrayUtils.add(this.providers, parsedProvider);
-        addMimeGroupsFromComponent(parsedProvider);
-        return this;
-    }
-
-    @Override
-    public PackageImpl addLibraryName(String libraryName) {
-        this.libraryNames = ArrayUtils.add(this.libraryNames, TextUtils.safeIntern(libraryName));
-        return this;
-    }
-
-    @Override
-    public PackageImpl addUsesLibrary(String libraryName) {
-        this.usesLibraries = ArrayUtils.add(this.usesLibraries, TextUtils.safeIntern(libraryName));
-        return this;
-    }
-
-    @Override
-    public PackageImpl addUsesOptionalLibrary(String libraryName) {
-        this.usesOptionalLibraries = ArrayUtils.add(this.usesOptionalLibraries,
-                TextUtils.safeIntern(libraryName));
-        return this;
-    }
-
-    @Override
-    public PackageImpl removeUsesOptionalLibrary(String libraryName) {
-        this.usesOptionalLibraries = ArrayUtils.remove(this.usesOptionalLibraries, libraryName);
-        return this;
-    }
-
-    @Override
-    public PackageImpl addUsesStaticLibrary(String libraryName) {
-        this.usesStaticLibraries = ArrayUtils.add(this.usesStaticLibraries,
-                TextUtils.safeIntern(libraryName));
-        return this;
-    }
-
-    @Override
-    public PackageImpl addUsesStaticLibraryVersion(long version) {
-        this.usesStaticLibrariesVersions = ArrayUtils.appendLong(this.usesStaticLibrariesVersions,
-                version, true);
-        return this;
-    }
-
-    @Override
-    public PackageImpl addUsesStaticLibraryCertDigests(String[] certSha256Digests) {
-        this.usesStaticLibrariesCertDigests = ArrayUtils.appendElement(String[].class,
-                this.usesStaticLibrariesCertDigests, certSha256Digests, true);
-        return this;
-    }
-
-    @Override
-    public PackageImpl addPreferredActivityFilter(
-            ParsedActivityIntentInfo parsedActivityIntentInfo) {
-        this.preferredActivityFilters = ArrayUtils.add(this.preferredActivityFilters,
-                parsedActivityIntentInfo);
-        return this;
-    }
-
-    @Override
-    public PackageImpl addQueriesIntent(Intent intent) {
-        this.queriesIntents = ArrayUtils.add(this.queriesIntents, intent);
-        return this;
-    }
-
-    @Override
-    public PackageImpl addQueriesPackage(String packageName) {
-        this.queriesPackages = ArrayUtils.add(this.queriesPackages,
-                TextUtils.safeIntern(packageName));
-        return this;
-    }
-
-    @Override
-    public ParsingPackage addQueriesProvider(String authority) {
-        this.queriesProviders = ArrayUtils.add(this.queriesProviders, authority);
-        return this;
-    }
-
-    @Override
-    public PackageImpl setProcesses(ArrayMap<String, ComponentParseUtils.ParsedProcess> processes) {
-        this.processes = processes;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setSupportsSmallScreens(int supportsSmallScreens) {
-        if (supportsSmallScreens == 1) {
-            return this;
-        }
-
-        this.supportsSmallScreens = supportsSmallScreens;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setSupportsNormalScreens(int supportsNormalScreens) {
-        if (supportsNormalScreens == 1) {
-            return this;
-        }
-
-        this.supportsNormalScreens = supportsNormalScreens;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setSupportsLargeScreens(int supportsLargeScreens) {
-        if (supportsLargeScreens == 1) {
-            return this;
-        }
-
-        this.supportsLargeScreens = supportsLargeScreens;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setSupportsXLargeScreens(int supportsXLargeScreens) {
-        if (supportsXLargeScreens == 1) {
-            return this;
-        }
-
-        this.supportsXLargeScreens = supportsXLargeScreens;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setResizeable(int resizeable) {
-        if (resizeable == 1) {
-            return this;
-        }
-
-        this.resizeable = resizeable;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setAnyDensity(int anyDensity) {
-        if (anyDensity == 1) {
-            return this;
-        }
-
-        this.anyDensity = anyDensity;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setRequiresSmallestWidthDp(int requiresSmallestWidthDp) {
-        this.requiresSmallestWidthDp = requiresSmallestWidthDp;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setCompatibleWidthLimitDp(int compatibleWidthLimitDp) {
-        this.compatibleWidthLimitDp = compatibleWidthLimitDp;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setLargestWidthLimitDp(int largestWidthLimitDp) {
-        this.largestWidthLimitDp = largestWidthLimitDp;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setInstallLocation(int installLocation) {
-        this.installLocation = installLocation;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setTargetSandboxVersion(int targetSandboxVersion) {
-        this.targetSandboxVersion = targetSandboxVersion;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setRequiredForAllUsers(boolean requiredForAllUsers) {
-        this.requiredForAllUsers = requiredForAllUsers;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setRestrictedAccountType(String restrictedAccountType) {
-        this.restrictedAccountType = restrictedAccountType;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setRequiredAccountType(String requiredAccountType) {
-        this.requiredAccountType = requiredAccountType;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setBaseHardwareAccelerated(boolean baseHardwareAccelerated) {
-        this.baseHardwareAccelerated = baseHardwareAccelerated;
-
-        this.flags = baseHardwareAccelerated
-                ? this.flags | ApplicationInfo.FLAG_HARDWARE_ACCELERATED
-                : this.flags & ~ApplicationInfo.FLAG_HARDWARE_ACCELERATED;
-
-        return this;
-    }
-
-    @Override
-    public PackageImpl setHasDomainUrls(boolean hasDomainUrls) {
-        this.privateFlags = hasDomainUrls
-                ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS
-                : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setAppMetaData(Bundle appMetaData) {
-        this.appMetaData = appMetaData;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setOverlayTarget(String overlayTarget) {
-        this.overlayTarget = overlayTarget;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setOverlayTargetName(String overlayTargetName) {
-        this.overlayTargetName = overlayTargetName;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setOverlayCategory(String overlayCategory) {
-        this.overlayCategory = overlayCategory;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setOverlayPriority(int overlayPriority) {
-        this.overlayPriority = overlayPriority;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setOverlayIsStatic(boolean overlayIsStatic) {
-        this.overlayIsStatic = overlayIsStatic;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setStaticSharedLibName(String staticSharedLibName) {
-        this.staticSharedLibName = TextUtils.safeIntern(staticSharedLibName);
-        return this;
-    }
-
-    @Override
-    public PackageImpl setStaticSharedLibVersion(long staticSharedLibVersion) {
-        this.staticSharedLibVersion = staticSharedLibVersion;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setSharedUserId(String sharedUserId) {
-        this.sharedUserId = TextUtils.safeIntern(sharedUserId);
-        return this;
-    }
-
-    @Override
-    public PackageImpl setSharedUserLabel(int sharedUserLabel) {
-        this.sharedUserLabel = sharedUserLabel;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setRestrictUpdateHash(byte[] restrictUpdateHash) {
-        this.restrictUpdateHash = restrictUpdateHash;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setUpgradeKeySets(ArraySet<String> upgradeKeySets) {
-        this.upgradeKeySets = upgradeKeySets;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setVolumeUuid(String volumeUuid) {
-        this.volumeUuid = volumeUuid;
-        return this;
-    }
-
-    @Deprecated
-    @Override
-    public PackageImpl setApplicationVolumeUuid(String applicationVolumeUuid) {
-        this.applicationVolumeUuid = applicationVolumeUuid;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setSigningDetails(PackageParser.SigningDetails signingDetails) {
-        this.signingDetails = signingDetails;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setCodePath(String codePath) {
-        this.codePath = codePath;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setUse32BitAbi(boolean use32BitAbi) {
-        this.use32BitAbi = use32BitAbi;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setCpuAbiOverride(String cpuAbiOverride) {
-        this.cpuAbiOverride = cpuAbiOverride;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setForceQueryable(boolean forceQueryable) {
-        this.forceQueryable = forceQueryable;
-        return this;
-    }
-
-    // TODO(b/135203078): Remove and move PackageManagerService#renameStaticSharedLibraryPackage
-    //  into initial package parsing
-    @Override
-    public PackageImpl setPackageName(String packageName) {
-        this.packageName = packageName.intern();
-
-        if (permissions != null) {
-            for (ParsedPermission permission : permissions) {
-                permission.setPackageName(this.packageName);
-            }
-        }
-
-        if (permissionGroups != null) {
-            for (ParsedPermissionGroup permissionGroup : permissionGroups) {
-                permissionGroup.setPackageName(this.packageName);
-            }
-        }
-
-        if (activities != null) {
-            for (ParsedActivity parsedActivity : activities) {
-                parsedActivity.setPackageName(this.packageName);
-            }
-        }
-
-        if (receivers != null) {
-            for (ParsedActivity receiver : receivers) {
-                receiver.setPackageName(this.packageName);
-            }
-        }
-
-        if (providers != null) {
-            for (ParsedProvider provider : providers) {
-                provider.setPackageName(this.packageName);
-            }
-        }
-
-        if (services != null) {
-            for (ParsedService service : services) {
-                service.setPackageName(this.packageName);
-            }
-        }
-
-        if (instrumentations != null) {
-            for (ParsedInstrumentation instrumentation : instrumentations) {
-                instrumentation.setPackageName(this.packageName);
-            }
-        }
-
-        return this;
-    }
-
-    // Under this is parseBaseApplication
-
-    @Override
-    public PackageImpl setAllowBackup(boolean allowBackup) {
-        this.flags = allowBackup
-                ? this.flags | ApplicationInfo.FLAG_ALLOW_BACKUP
-                : this.flags & ~ApplicationInfo.FLAG_ALLOW_BACKUP;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setKillAfterRestore(boolean killAfterRestore) {
-        this.flags = killAfterRestore
-                ? this.flags | ApplicationInfo.FLAG_KILL_AFTER_RESTORE
-                : this.flags & ~ApplicationInfo.FLAG_KILL_AFTER_RESTORE;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setRestoreAnyVersion(boolean restoreAnyVersion) {
-        this.flags = restoreAnyVersion
-                ? this.flags | ApplicationInfo.FLAG_RESTORE_ANY_VERSION
-                : this.flags & ~ApplicationInfo.FLAG_RESTORE_ANY_VERSION;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setFullBackupOnly(boolean fullBackupOnly) {
-        this.flags = fullBackupOnly
-                ? this.flags | ApplicationInfo.FLAG_FULL_BACKUP_ONLY
-                : this.flags & ~ApplicationInfo.FLAG_FULL_BACKUP_ONLY;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setPersistent(boolean persistent) {
-        this.flags = persistent
-                ? this.flags | ApplicationInfo.FLAG_PERSISTENT
-                : this.flags & ~ApplicationInfo.FLAG_PERSISTENT;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setDebuggable(boolean debuggable) {
-        this.flags = debuggable
-                ? this.flags | ApplicationInfo.FLAG_DEBUGGABLE
-                : this.flags & ~ApplicationInfo.FLAG_DEBUGGABLE;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setProfileableByShell(boolean profileableByShell) {
-        this.privateFlags = profileableByShell
-                ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_PROFILEABLE_BY_SHELL
-                : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_PROFILEABLE_BY_SHELL;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setVmSafeMode(boolean vmSafeMode) {
-        this.flags = vmSafeMode
-                ? this.flags | ApplicationInfo.FLAG_VM_SAFE_MODE
-                : this.flags & ~ApplicationInfo.FLAG_VM_SAFE_MODE;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setHasCode(boolean hasCode) {
-        this.flags = hasCode
-                ? this.flags | ApplicationInfo.FLAG_HAS_CODE
-                : this.flags & ~ApplicationInfo.FLAG_HAS_CODE;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setAllowTaskReparenting(boolean allowTaskReparenting) {
-        this.flags = allowTaskReparenting
-                ? this.flags | ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING
-                : this.flags & ~ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setAllowClearUserData(boolean allowClearUserData) {
-        this.flags = allowClearUserData
-                ? this.flags | ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA
-                : this.flags & ~ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setLargeHeap(boolean largeHeap) {
-        this.flags = largeHeap
-                ? this.flags | ApplicationInfo.FLAG_LARGE_HEAP
-                : this.flags & ~ApplicationInfo.FLAG_LARGE_HEAP;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setUsesCleartextTraffic(boolean usesCleartextTraffic) {
-        this.flags = usesCleartextTraffic
-                ? this.flags | ApplicationInfo.FLAG_USES_CLEARTEXT_TRAFFIC
-                : this.flags & ~ApplicationInfo.FLAG_USES_CLEARTEXT_TRAFFIC;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setSupportsRtl(boolean supportsRtl) {
-        this.flags = supportsRtl
-                ? this.flags | ApplicationInfo.FLAG_SUPPORTS_RTL
-                : this.flags & ~ApplicationInfo.FLAG_SUPPORTS_RTL;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setTestOnly(boolean testOnly) {
-        this.flags = testOnly
-                ? this.flags | ApplicationInfo.FLAG_TEST_ONLY
-                : this.flags & ~ApplicationInfo.FLAG_TEST_ONLY;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setMultiArch(boolean multiArch) {
-        this.flags = multiArch
-                ? this.flags | ApplicationInfo.FLAG_MULTIARCH
-                : this.flags & ~ApplicationInfo.FLAG_MULTIARCH;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setExtractNativeLibs(boolean extractNativeLibs) {
-        this.flags = extractNativeLibs
-                ? this.flags | ApplicationInfo.FLAG_EXTRACT_NATIVE_LIBS
-                : this.flags & ~ApplicationInfo.FLAG_EXTRACT_NATIVE_LIBS;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setIsGame(boolean isGame) {
-        this.flags = isGame
-                ? this.flags | ApplicationInfo.FLAG_IS_GAME
-                : this.flags & ~ApplicationInfo.FLAG_IS_GAME;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setBackupInForeground(boolean backupInForeground) {
-        this.privateFlags = backupInForeground
-                ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_BACKUP_IN_FOREGROUND
-                : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_BACKUP_IN_FOREGROUND;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setUseEmbeddedDex(boolean useEmbeddedDex) {
-        this.privateFlags = useEmbeddedDex
-                ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_USE_EMBEDDED_DEX
-                : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_USE_EMBEDDED_DEX;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setDefaultToDeviceProtectedStorage(boolean defaultToDeviceProtectedStorage) {
-        this.privateFlags = defaultToDeviceProtectedStorage
-                ? this.privateFlags | ApplicationInfo
-                        .PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE
-                : this.privateFlags & ~ApplicationInfo
-                        .PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setDirectBootAware(boolean directBootAware) {
-        this.privateFlags = directBootAware
-                ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE
-                : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setPartiallyDirectBootAware(boolean partiallyDirectBootAware) {
-        this.privateFlags = partiallyDirectBootAware
-                ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE
-                : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setActivitiesResizeModeResizeableViaSdkVersion(
-            boolean resizeableViaSdkVersion
-    ) {
-        this.privateFlags = resizeableViaSdkVersion
-                ? this.privateFlags | ApplicationInfo
-                        .PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION
-                : this.privateFlags & ~ApplicationInfo
-                        .PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setActivitiesResizeModeResizeable(boolean resizeable) {
-        this.privateFlags = resizeable
-                ? this.privateFlags | ApplicationInfo
-                        .PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE
-                : this.privateFlags & ~ApplicationInfo
-                        .PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE;
-
-        this.privateFlags = !resizeable
-                ? this.privateFlags | ApplicationInfo
-                        .PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_UNRESIZEABLE
-                : this.privateFlags & ~ApplicationInfo
-                        .PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_UNRESIZEABLE;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setAllowClearUserDataOnFailedRestore(
-            boolean allowClearUserDataOnFailedRestore
-    ) {
-        this.privateFlags = allowClearUserDataOnFailedRestore
-                ? this.privateFlags | ApplicationInfo
-                        .PRIVATE_FLAG_ALLOW_CLEAR_USER_DATA_ON_FAILED_RESTORE
-                : this.privateFlags & ~ApplicationInfo
-                        .PRIVATE_FLAG_ALLOW_CLEAR_USER_DATA_ON_FAILED_RESTORE;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setAllowAudioPlaybackCapture(boolean allowAudioPlaybackCapture) {
-        this.privateFlags = allowAudioPlaybackCapture
-                ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_ALLOW_AUDIO_PLAYBACK_CAPTURE
-                : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_ALLOW_AUDIO_PLAYBACK_CAPTURE;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setRequestLegacyExternalStorage(boolean requestLegacyExternalStorage) {
-        this.privateFlags = requestLegacyExternalStorage
-                ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_REQUEST_LEGACY_EXTERNAL_STORAGE
-                : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_REQUEST_LEGACY_EXTERNAL_STORAGE;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setAllowNativeHeapPointerTagging(boolean allowNativeHeapPointerTagging) {
-        this.privateFlags = allowNativeHeapPointerTagging
-                ? this.privateFlags | ApplicationInfo
-                        .PRIVATE_FLAG_ALLOW_NATIVE_HEAP_POINTER_TAGGING
-                : this.privateFlags & ~ApplicationInfo
-                        .PRIVATE_FLAG_ALLOW_NATIVE_HEAP_POINTER_TAGGING;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setPreserveLegacyExternalStorage(boolean preserveLegacyExternalStorage) {
-        this.preserveLegacyExternalStorage = preserveLegacyExternalStorage;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setUsesNonSdkApi(boolean usesNonSdkApi) {
-        this.privateFlags = usesNonSdkApi
-                ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_USES_NON_SDK_API
-                : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_USES_NON_SDK_API;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setHasFragileUserData(boolean hasFragileUserData) {
-        this.privateFlags = hasFragileUserData
-                ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_HAS_FRAGILE_USER_DATA
-                : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_HAS_FRAGILE_USER_DATA;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setCantSaveState(boolean cantSaveState) {
-        this.privateFlags = cantSaveState
-                ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE
-                : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE;
-        return this;
-    }
-
-    @Override
-    public boolean cantSaveState() {
-        return (privateFlags & ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0;
-    }
-
-    @Override
-    public boolean isLibrary() {
-        return staticSharedLibName != null || !ArrayUtils.isEmpty(libraryNames);
-    }
-
-    // TODO(b/135203078): This does nothing until the final stage without applyPolicy being
-    //  part of PackageParser
-    @Override
-    public boolean isSystemApp() {
-        return (flags & ApplicationInfo.FLAG_SYSTEM) != 0;
-    }
-
-    // TODO(b/135203078): This does nothing until the final stage without applyPolicy being
-    //  part of PackageParser
-    @Override
-    public boolean isSystemExt() {
-        return (privateFlags & ApplicationInfo.PRIVATE_FLAG_SYSTEM_EXT) != 0;
-    }
-
-    // TODO(b/135203078): This does nothing until the final stage without applyPolicy being
-    //  part of PackageParser
-    @Override
-    public boolean isUpdatedSystemApp() {
-        return (flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0;
-    }
-
-    @Override
-    public PackageImpl setStaticSharedLibrary(boolean staticSharedLibrary) {
-        this.privateFlags = staticSharedLibrary
-                ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_STATIC_SHARED_LIBRARY
-                : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_STATIC_SHARED_LIBRARY;
-        return this;
-    }
-
-    @Override
-    public boolean isStaticSharedLibrary() {
-        return (privateFlags & ApplicationInfo.PRIVATE_FLAG_STATIC_SHARED_LIBRARY) != 0;
-    }
-
-    @Override
-    public PackageImpl setVisibleToInstantApps(boolean visibleToInstantApps) {
-        this.visibleToInstantApps = visibleToInstantApps;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setIconRes(int iconRes) {
-        this.iconRes = iconRes;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setRoundIconRes(int roundIconRes) {
-        this.roundIconRes = roundIconRes;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setClassName(String className) {
-        this.className = className;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setManageSpaceActivityName(String manageSpaceActivityName) {
-        this.manageSpaceActivityName = manageSpaceActivityName;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setBackupAgentName(String backupAgentName) {
-        this.backupAgentName = backupAgentName;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setFullBackupContent(int fullBackupContent) {
-        this.fullBackupContent = fullBackupContent;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setTheme(int theme) {
-        this.theme = theme;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setDescriptionRes(int descriptionRes) {
-        this.descriptionRes = descriptionRes;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setNetworkSecurityConfigRes(int networkSecurityConfigRes) {
-        this.networkSecurityConfigRes = networkSecurityConfigRes;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setCategory(int category) {
-        this.category = category;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setPermission(String permission) {
-        this.permission = permission;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setTaskAffinity(String taskAffinity) {
-        this.taskAffinity = taskAffinity;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setAppComponentFactory(String appComponentFactory) {
-        this.appComponentFactory = appComponentFactory;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setProcessName(String processName) {
-        if (processName == null) {
-            this.processName = packageName;
-        } else {
-            this.processName = processName;
-        }
-        return this;
-    }
-
-    @Override
-    public PackageImpl setEnabled(boolean enabled) {
-        this.enabled = enabled;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setCrossProfile(boolean crossProfile) {
-        this.crossProfile = crossProfile;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setUiOptions(int uiOptions) {
-        this.uiOptions = uiOptions;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setClassLoaderName(String classLoaderName) {
-        this.classLoaderName = classLoaderName;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setZygotePreloadName(String zygotePreloadName) {
-        this.zygotePreloadName = zygotePreloadName;
-        return this;
-    }
-
-    // parsePackageItemInfo
-
-    @Override
-    public String getName() {
-        return name;
-    }
-
-    @Override
-    public PackageImpl setName(String name) {
-        this.name = name;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setIcon(int icon) {
-        this.icon = icon;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setNonLocalizedLabel(CharSequence nonLocalizedLabel) {
-        this.nonLocalizedLabel = nonLocalizedLabel;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setLogo(int logo) {
-        this.logo = logo;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setBanner(int banner) {
-        this.banner = banner;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setLabelRes(int labelRes) {
-        this.labelRes = labelRes;
-        return this;
-    }
-
-    @Override
-    public PackageImpl asSplit(
-            String[] splitNames,
-            String[] splitCodePaths,
-            int[] splitRevisionCodes,
-            SparseArray<int[]> splitDependencies
-    ) {
-        this.splitNames = splitNames;
-
-        if (this.splitNames != null) {
-            for (int index = 0; index < this.splitNames.length; index++) {
-                splitNames[index] = TextUtils.safeIntern(splitNames[index]);
-            }
-        }
-
-        this.splitCodePaths = splitCodePaths;
-        this.splitRevisionCodes = splitRevisionCodes;
-        this.splitDependencies = splitDependencies;
-
-        int count = splitNames.length;
-        this.splitFlags = new int[count];
-        this.splitClassLoaderNames = new String[count];
-        return this;
-    }
-
-    @Override
-    public String[] getSplitNames() {
-        return splitNames;
-    }
-
-    @Override
-    public String[] getSplitCodePaths() {
-        return splitCodePaths;
-    }
-
-    @Override
-    public PackageImpl setSplitHasCode(int splitIndex, boolean splitHasCode) {
-        this.splitFlags[splitIndex] = splitHasCode
-                ? this.splitFlags[splitIndex] | ApplicationInfo.FLAG_HAS_CODE
-                : this.splitFlags[splitIndex] & ~ApplicationInfo.FLAG_HAS_CODE;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setSplitClassLoaderName(int splitIndex, String classLoaderName) {
-        this.splitClassLoaderNames[splitIndex] = classLoaderName;
-        return this;
-    }
-
-    @Override
-    public List<String> makeListAllCodePaths() {
-        ArrayList<String> paths = new ArrayList<>();
-        paths.add(baseCodePath);
-
-        if (!ArrayUtils.isEmpty(splitCodePaths)) {
-            Collections.addAll(paths, splitCodePaths);
-        }
-        return paths;
-    }
-
-    @Override
-    public PackageImpl setBaseCodePath(String baseCodePath) {
-        this.baseCodePath = baseCodePath;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setSplitCodePaths(String[] splitCodePaths) {
-        this.splitCodePaths = splitCodePaths;
-        return this;
-    }
-
-    @Override
-    public String toString() {
-        return "Package{"
-                + Integer.toHexString(System.identityHashCode(this))
-                + " " + packageName + "}";
-    }
-
-    @Override
-    public PackageImpl setPrimaryCpuAbi(String primaryCpuAbi) {
-        this.primaryCpuAbi = primaryCpuAbi;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setSecondaryCpuAbi(String secondaryCpuAbi) {
-        this.secondaryCpuAbi = secondaryCpuAbi;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setNativeLibraryRootDir(String nativeLibraryRootDir) {
-        this.nativeLibraryRootDir = nativeLibraryRootDir;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setNativeLibraryRootRequiresIsa(boolean nativeLibraryRootRequiresIsa) {
-        this.nativeLibraryRootRequiresIsa = nativeLibraryRootRequiresIsa;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setNativeLibraryDir(String nativeLibraryDir) {
-        this.nativeLibraryDir = nativeLibraryDir;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setSecondaryNativeLibraryDir(String secondaryNativeLibraryDir) {
-        this.secondaryNativeLibraryDir = secondaryNativeLibraryDir;
-        return this;
-    }
-
-    @Deprecated
-    @Override
-    public PackageImpl setApplicationInfoCodePath(String applicationInfoCodePath) {
-        this.applicationInfoCodePath = applicationInfoCodePath;
-        return this;
-    }
-
-    @Deprecated
-    @Override
-    public PackageImpl setApplicationInfoResourcePath(String applicationInfoResourcePath) {
-        this.applicationInfoResourcePath = applicationInfoResourcePath;
-        return this;
-    }
-
-    @Deprecated
-    @Override
-    public PackageImpl setApplicationInfoBaseResourcePath(
-            String applicationInfoBaseResourcePath) {
-        this.applicationInfoBaseResourcePath = applicationInfoBaseResourcePath;
-        return this;
-    }
-
-    @Deprecated
-    @Override
-    public PackageImpl setApplicationInfoSplitResourcePaths(
-            String[] applicationInfoSplitResourcePaths) {
-        this.applicationInfoSplitResourcePaths = applicationInfoSplitResourcePaths;
-        return this;
-    }
-
-    @Override
-    public boolean isDirectBootAware() {
-        return (privateFlags & ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE) != 0;
-    }
-
-    @Override
-    public PackageImpl setAllComponentsDirectBootAware(boolean allComponentsDirectBootAware) {
-        if (activities != null) {
-            for (ParsedActivity parsedActivity : activities) {
-                parsedActivity.directBootAware = allComponentsDirectBootAware;
-            }
-        }
-
-        if (receivers != null) {
-            for (ParsedActivity parsedReceiver : receivers) {
-                parsedReceiver.directBootAware = allComponentsDirectBootAware;
-            }
-        }
-
-        if (providers != null) {
-            for (ParsedProvider parsedProvider : providers) {
-                parsedProvider.directBootAware = allComponentsDirectBootAware;
-            }
-        }
-
-        if (services != null) {
-            for (ParsedService parsedService : services) {
-                parsedService.directBootAware = allComponentsDirectBootAware;
-            }
-        }
-
-        return this;
-    }
-
-    @Override
-    public PackageImpl setSystem(boolean system) {
-        this.flags = system
-                ? this.flags | ApplicationInfo.FLAG_SYSTEM
-                : this.flags & ~ApplicationInfo.FLAG_SYSTEM;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setSystemExt(boolean systemExt) {
-        this.privateFlags = systemExt
-                ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_SYSTEM_EXT
-                : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_SYSTEM_EXT;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setIsStub(boolean isStub) {
-        this.isStub = isStub;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setCoreApp(boolean coreApp) {
-        this.coreApp = coreApp;
-        return this;
-    }
-
-    @Override
-    public ParsedPackage capPermissionPriorities() {
-        if (permissionGroups != null && !permissionGroups.isEmpty()) {
-            for (int i = permissionGroups.size() - 1; i >= 0; --i) {
-                // TODO(b/135203078): Builder/immutability
-                permissionGroups.get(i).priority = 0;
-            }
-        }
-        return this;
-    }
-
-    @Override
-    public ParsedPackage clearProtectedBroadcasts() {
-        if (protectedBroadcasts != null) {
-            protectedBroadcasts.clear();
-        }
-        return this;
-    }
-
-    @Override
-    public ParsedPackage markNotActivitiesAsNotExportedIfSingleUser() {
-        // ignore export request for single user receivers
-        if (receivers != null) {
-            for (ParsedActivity receiver : receivers) {
-                if ((receiver.flags & ActivityInfo.FLAG_SINGLE_USER) != 0) {
-                    receiver.exported = false;
-                }
-            }
-        }
-        // ignore export request for single user services
-        if (services != null) {
-            for (ParsedService service : services) {
-                if ((service.flags & ServiceInfo.FLAG_SINGLE_USER) != 0) {
-                    service.exported = false;
-                }
-            }
-        }
-        // ignore export request for single user providers
-        if (providers != null) {
-            for (ParsedProvider provider : providers) {
-                if ((provider.flags & ProviderInfo.FLAG_SINGLE_USER) != 0) {
-                    provider.exported = false;
-                }
-            }
-        }
-
-        return this;
-    }
-
-    @Override
-    public ParsedPackage setPrivileged(boolean privileged) {
-        this.privateFlags = privileged
-                ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_PRIVILEGED
-                : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
-        return this;
-    }
-
-    @Override
-    public ParsedPackage setOem(boolean oem) {
-        this.privateFlags = oem
-                ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_OEM
-                : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_OEM;
-        return this;
-    }
-
-    @Override
-    public ParsedPackage setVendor(boolean vendor) {
-        this.privateFlags = vendor
-                ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_VENDOR
-                : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_VENDOR;
-        return this;
-    }
-
-    @Override
-    public ParsedPackage setProduct(boolean product) {
-        this.privateFlags = product
-                ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_PRODUCT
-                : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_PRODUCT;
-        return this;
-    }
-
-    @Override
-    public ParsedPackage setOdm(boolean odm) {
-        this.privateFlags = odm
-                ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_ODM
-                : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_ODM;
-        return this;
-    }
-
-    @Override
-    public ParsedPackage setSignedWithPlatformKey(boolean signedWithPlatformKey) {
-        this.privateFlags = signedWithPlatformKey
-                ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_SIGNED_WITH_PLATFORM_KEY
-                : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_SIGNED_WITH_PLATFORM_KEY;
-        return this;
-    }
-
-    @Override
-    public ParsedPackage clearOriginalPackages() {
-        if (originalPackages != null) {
-            originalPackages.clear();
-        }
-        return this;
-    }
-
-    @Override
-    public ParsedPackage clearAdoptPermissions() {
-        if (adoptPermissions != null) {
-            adoptPermissions.clear();
-        }
-        return this;
-    }
-
-    @Override
-    public PackageImpl addUsesLibrary(int index, String libraryName) {
-        this.usesLibraries = ArrayUtils.add(usesLibraries, index, libraryName);
-        return this;
-    }
-
-    @Override
-    public ParsedPackage removeUsesLibrary(String libraryName) {
-        this.usesLibraries = ArrayUtils.remove(this.usesLibraries, libraryName);
-        return this;
-    }
-
-    @Override
-    public PackageImpl addUsesOptionalLibrary(int index, String libraryName) {
-        this.usesOptionalLibraries = ArrayUtils.add(usesOptionalLibraries, index, libraryName);
-        return this;
-    }
-
-    @Nullable
-    @Override
-    public List<String> getUsesOptionalLibraries() {
-        return usesOptionalLibraries;
-    }
-
-    @Override
-    public int getVersionCode() {
-        return versionCode;
-    }
-
-    @Nullable
-    @Override
-    public long[] getUsesStaticLibrariesVersions() {
-        return usesStaticLibrariesVersions;
-    }
-
-    @Override
-    public PackageImpl setPackageSettingCallback(PackageSettingCallback packageSettingCallback) {
-        packageSettingCallback.setAndroidPackage(this);
-        return this;
-    }
-
-    @Override
-    public PackageImpl setUpdatedSystemApp(boolean updatedSystemApp) {
-        this.flags = updatedSystemApp
-                ? this.flags | ApplicationInfo.FLAG_UPDATED_SYSTEM_APP
-                : this.flags & ~ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
-        return this;
-    }
-
-    @Override
-    public boolean isPrivileged() {
-        return (privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
-    }
-
-    @Override
-    public PackageImpl setSeInfo(String seInfo) {
-        this.seInfo = seInfo;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setSeInfoUser(String seInfoUser) {
-        this.seInfoUser = seInfoUser;
-        return this;
-    }
-
-    @Override
-    public PackageImpl initForUser(int userId) {
-        // TODO(b/135203078): Move this user state to some other data structure
-        this.uid = UserHandle.getUid(userId, UserHandle.getAppId(this.uid));
-
-        if ("android".equals(packageName)) {
-            dataDir = Environment.getDataSystemDirectory().getAbsolutePath();
-            return this;
-        }
-
-        deviceProtectedDataDir = Environment
-                .getDataUserDePackageDirectory(applicationVolumeUuid, userId, packageName)
-                .getAbsolutePath();
-        credentialProtectedDataDir = Environment
-                .getDataUserCePackageDirectory(applicationVolumeUuid, userId, packageName)
-                .getAbsolutePath();
-
-        if ((privateFlags & ApplicationInfo.PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE) != 0
-                && PackageManager.APPLY_DEFAULT_TO_DEVICE_PROTECTED_STORAGE) {
-            dataDir = deviceProtectedDataDir;
-        } else {
-            dataDir = credentialProtectedDataDir;
-        }
-        return this;
-    }
-
-    @Override
-    public ParsedPackage setFactoryTest(boolean factoryTest) {
-        this.flags = factoryTest
-                ? this.flags | ApplicationInfo.FLAG_FACTORY_TEST
-                : this.flags & ~ApplicationInfo.FLAG_FACTORY_TEST;
-        return this;
-    }
-
-    @Override
-    public String getManifestPackageName() {
-        return manifestPackageName;
-    }
-
-    @Override
-    public String getRealPackage() {
-        return realPackage;
-    }
-
-    @Override
-    public String getOverlayTarget() {
-        return overlayTarget;
-    }
-
-    @Override
-    public String getOverlayTargetName() {
-        return overlayTargetName;
-    }
-
-    @Override
-    public Map<String, String> getOverlayables() {
-        return overlayables;
-    }
-
-    @Override
-    public boolean isOverlayIsStatic() {
-        return overlayIsStatic;
-    }
-
-    @Override
-    public int[] getSplitFlags() {
-        return splitFlags;
-    }
-
-    @Deprecated
-    @Override
-    public String getApplicationInfoVolumeUuid() {
-        return applicationVolumeUuid;
-    }
-
-    @Nullable
-    @Override
-    public List<String> getProtectedBroadcasts() {
-        return protectedBroadcasts;
-    }
-
-    @Nullable
-    @Override
-    public Set<String> getUpgradeKeySets() {
-        return upgradeKeySets;
-    }
-
-    @Nullable
-    @Override
-    public String[][] getUsesStaticLibrariesCertDigests() {
-        return usesStaticLibrariesCertDigests;
-    }
-
-    @Override
-    public int getOverlayPriority() {
-        return overlayPriority;
-    }
-
-    @Deprecated
-    @Override
-    public String getAppInfoPackageName() {
-        return packageName;
-    }
-
-    @Override
-    public UUID getStorageUuid() {
-        return StorageManager.convert(applicationVolumeUuid);
-    }
-
-    @Override
-    public int getUid() {
-        return uid;
-    }
-
-    @Override
-    public boolean isStub() {
-        return isStub;
-    }
-
-    @Deprecated
-    @Override
-    public String getAppInfoCodePath() {
-        return applicationInfoCodePath;
-    }
-
-    @Override
-    public boolean isSystem() {
-        return (flags & ApplicationInfo.FLAG_SYSTEM) != 0;
-    }
-
-    @Override
-    public boolean isMatch(int flags) {
-        if ((flags & PackageManager.MATCH_SYSTEM_ONLY) != 0) {
-            return isSystem();
-        }
-        return true;
-    }
-
-    @Override
-    public boolean isVisibleToInstantApps() {
-        return visibleToInstantApps;
-    }
-
-    @Override
-    public PackageImpl setLastPackageUsageTimeInMills(int reason, long time) {
-        lastPackageUsageTimeInMills[reason] = time;
-        return this;
-    }
-
-    @Override
-    public List<SharedLibraryInfo> getUsesLibraryInfos() {
-        return usesLibraryInfos;
-    }
-
-    @NonNull
-    @Override
-    public List<String> getAllCodePaths() {
-        return makeListAllCodePaths();
-    }
-
-    @Nullable
-    @Override
-    public String[] getUsesLibraryFiles() {
-        return usesLibraryFiles;
-    }
-
-    @Override
-    public PackageImpl setUsesLibraryInfos(
-            @Nullable List<SharedLibraryInfo> usesLibraryInfos) {
-        this.usesLibraryInfos = usesLibraryInfos;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setUsesLibraryFiles(@Nullable String[] usesLibraryFiles) {
-        this.usesLibraryFiles = usesLibraryFiles;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setUid(int uid) {
-        this.uid = uid;
-        return this;
-    }
-
-    @Override
-    public List<String> getAdoptPermissions() {
-        return adoptPermissions;
-    }
-
-    @Override
-    public ApplicationInfo toAppInfoWithoutState() {
-        updateFlags();
-
-        ApplicationInfo appInfo = new ApplicationInfo();
-        appInfo.packageName = packageName;
-        appInfo.flags = flags;
-        appInfo.privateFlags = privateFlags;
-
-        appInfo.appComponentFactory = appComponentFactory;
-        appInfo.backupAgentName = backupAgentName;
-        appInfo.banner = banner;
-        appInfo.category = category;
-        appInfo.classLoaderName = classLoaderName;
-        appInfo.className = className;
-        appInfo.compatibleWidthLimitDp = compatibleWidthLimitDp;
-        appInfo.compileSdkVersion = compileSdkVersion;
-        appInfo.compileSdkVersionCodename = compileSdkVersionCodename;
-        appInfo.credentialProtectedDataDir = credentialProtectedDataDir;
-        appInfo.dataDir = dataDir;
-        appInfo.descriptionRes = descriptionRes;
-        appInfo.deviceProtectedDataDir = deviceProtectedDataDir;
-        appInfo.enabled = enabled;
-        appInfo.fullBackupContent = fullBackupContent;
-        appInfo.hiddenUntilInstalled = hiddenUntilInstalled;
-        appInfo.icon = icon;
-        appInfo.iconRes = iconRes;
-        appInfo.installLocation = installLocation;
-        appInfo.labelRes = labelRes;
-        appInfo.largestWidthLimitDp = largestWidthLimitDp;
-        appInfo.logo = logo;
-        appInfo.manageSpaceActivityName = manageSpaceActivityName;
-        appInfo.maxAspectRatio = maxAspectRatio;
-        appInfo.metaData = appMetaData;
-        appInfo.minAspectRatio = minAspectRatio;
-        appInfo.minSdkVersion = minSdkVersion;
-        appInfo.name = className;
-        if (appInfo.name != null) {
-            appInfo.name = appInfo.name.trim();
-        }
-        appInfo.nativeLibraryDir = nativeLibraryDir;
-        appInfo.nativeLibraryRootDir = nativeLibraryRootDir;
-        appInfo.nativeLibraryRootRequiresIsa = nativeLibraryRootRequiresIsa;
-        appInfo.networkSecurityConfigRes = networkSecurityConfigRes;
-        appInfo.nonLocalizedLabel = nonLocalizedLabel;
-        if (appInfo.nonLocalizedLabel != null) {
-            appInfo.nonLocalizedLabel = appInfo.nonLocalizedLabel.toString().trim();
-        }
-        appInfo.packageName = packageName;
-        appInfo.permission = permission;
-        appInfo.primaryCpuAbi = primaryCpuAbi;
-        appInfo.processName = getProcessName();
-        appInfo.requiresSmallestWidthDp = requiresSmallestWidthDp;
-        appInfo.roundIconRes = roundIconRes;
-        appInfo.secondaryCpuAbi = secondaryCpuAbi;
-        appInfo.secondaryNativeLibraryDir = secondaryNativeLibraryDir;
-        appInfo.seInfo = seInfo;
-        appInfo.seInfoUser = seInfoUser;
-        appInfo.sharedLibraryFiles = usesLibraryFiles;
-        appInfo.sharedLibraryInfos = ArrayUtils.isEmpty(usesLibraryInfos) ? null : usesLibraryInfos;
-        appInfo.splitClassLoaderNames = splitClassLoaderNames;
-        appInfo.splitDependencies = splitDependencies;
-        appInfo.splitNames = splitNames;
-        appInfo.storageUuid = StorageManager.convert(volumeUuid);
-        appInfo.targetSandboxVersion = targetSandboxVersion;
-        appInfo.targetSdkVersion = targetSdkVersion;
-        appInfo.taskAffinity = taskAffinity;
-        appInfo.theme = theme;
-        appInfo.uid = uid;
-        appInfo.uiOptions = uiOptions;
-        appInfo.volumeUuid = volumeUuid;
-        appInfo.zygotePreloadName = zygotePreloadName;
-        appInfo.crossProfile = isCrossProfile();
-
-        appInfo.setBaseCodePath(baseCodePath);
-        appInfo.setBaseResourcePath(baseCodePath);
-        appInfo.setCodePath(codePath);
-        appInfo.setResourcePath(codePath);
-        appInfo.setSplitCodePaths(splitCodePaths);
-        appInfo.setSplitResourcePaths(splitCodePaths);
-        appInfo.setVersionCode(getLongVersionCode());
-
-        // TODO(b/135203078): Can this be removed? Looks only used in ActivityInfo.
-//        appInfo.showUserIcon = pkg.getShowUserIcon();
-        // TODO(b/135203078): Unused?
-//        appInfo.resourceDirs = pkg.getResourceDirs();
-        // TODO(b/135203078): Unused?
-//        appInfo.enabledSetting = pkg.getEnabledSetting();
-        // TODO(b/135203078): See PackageImpl#getHiddenApiEnforcementPolicy
-//        appInfo.mHiddenApiPolicy = pkg.getHiddenApiPolicy();
-
-        return appInfo;
-    }
-
-    @Override
-    public PackageImpl setVersionCode(int versionCode) {
-        this.versionCode = versionCode;
-        return this;
-    }
-
-    @Override
-    public PackageImpl setHiddenUntilInstalled(boolean hidden) {
-        this.hiddenUntilInstalled = hidden;
-        return this;
-    }
-
-    @Override
-    public String getSeInfo() {
-        return seInfo;
-    }
-
-    @Deprecated
-    @Override
-    public String getAppInfoResourcePath() {
-        return applicationInfoResourcePath;
-    }
-
-    @Override
-    public boolean isForwardLocked() {
-        // TODO(b/135203078): Unused? Move to debug flag?
-        return false;
-    }
-
-    @Override
-    public byte[] getRestrictUpdateHash() {
-        return restrictUpdateHash;
-    }
-
-    @Override
-    public boolean hasComponentClassName(String className) {
-        if (activities != null) {
-            for (ParsedActivity parsedActivity : activities) {
-                if (Objects.equals(className, parsedActivity.className)) {
-                    return true;
-                }
-            }
-        }
-
-        if (receivers != null) {
-            for (ParsedActivity receiver : receivers) {
-                if (Objects.equals(className, receiver.className)) {
-                    return true;
-                }
-            }
-        }
-
-        if (providers != null) {
-            for (ParsedProvider provider : providers) {
-                if (Objects.equals(className, provider.className)) {
-                    return true;
-                }
-            }
-        }
-
-        if (services != null) {
-            for (ParsedService service : services) {
-                if (Objects.equals(className, service.className)) {
-                    return true;
-                }
-            }
-        }
-
-        if (instrumentations != null) {
-            for (ParsedInstrumentation instrumentation : instrumentations) {
-                if (Objects.equals(className, instrumentation.className)) {
-                    return true;
-                }
-            }
-        }
-
-        return false;
-    }
-
-    @Override
-    public boolean isDefaultToDeviceProtectedStorage() {
-        return (privateFlags & ApplicationInfo.PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE)
-                != 0;
-    }
-
-    @Override
-    public boolean isInternal() {
-        return (flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) == 0;
-    }
-
-    @Override
-    public int getBaseRevisionCode() {
-        return baseRevisionCode;
-    }
-
-    @Override
-    public int[] getSplitRevisionCodes() {
-        return splitRevisionCodes;
-    }
-
-    @Override
-    public boolean canHaveOatDir() {
-        // The following app types CANNOT have oat directory
-        // - non-updated system apps
-        return !isSystem() || isUpdatedSystemApp();
-    }
-
-    @Override
-    public long getLatestPackageUseTimeInMills() {
-        long latestUse = 0L;
-        for (long use : lastPackageUsageTimeInMills) {
-            latestUse = Math.max(latestUse, use);
-        }
-        return latestUse;
-    }
-
-    @Override
-    public long getLatestForegroundPackageUseTimeInMills() {
-        int[] foregroundReasons = {
-                PackageManager.NOTIFY_PACKAGE_USE_ACTIVITY,
-                PackageManager.NOTIFY_PACKAGE_USE_FOREGROUND_SERVICE
-        };
-
-        long latestUse = 0L;
-        for (int reason : foregroundReasons) {
-            latestUse = Math.max(latestUse, lastPackageUsageTimeInMills[reason]);
-        }
-        return latestUse;
-    }
-
-    @Override
-    public boolean isCoreApp() {
-        return coreApp;
-    }
-
-    @Override
-    public String getVersionName() {
-        return versionName;
-    }
-
-    @Override
-    public PackageImpl setVersionCodeMajor(int versionCodeMajor) {
-        this.versionCodeMajor = versionCodeMajor;
-        return this;
-    }
-
-    @Override
-    public long[] getLastPackageUsageTimeInMills() {
-        return lastPackageUsageTimeInMills;
-    }
-
-    @Override
-    public String getDataDir() {
-        return dataDir;
-    }
-
-    @Override
-    public boolean isExternal() {
-        return (flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0;
-    }
-
-    @Override
-    public List<String> getImplicitPermissions() {
-        return implicitPermissions == null ? Collections.emptyList() : implicitPermissions;
-    }
-
-    /**
-     * TODO(b/135203078): Remove, ensure b/140256621 is fixed or irrelevant
-     * TODO(b/140256621): Remove after fixing instant app check
-     * @deprecated This method always returns false because there's no paired set method
-     */
-    @Deprecated
-    @Override
-    public boolean isInstantApp() {
-        return (privateFlags & ApplicationInfo.PRIVATE_FLAG_INSTANT) != 0;
-    }
-
-    @Override
-    public boolean hasRequestedLegacyExternalStorage() {
-        return (privateFlags & ApplicationInfo.PRIVATE_FLAG_REQUEST_LEGACY_EXTERNAL_STORAGE) != 0;
-    }
-
-    @Override
-    public boolean isVendor() {
-        return (privateFlags & ApplicationInfo.PRIVATE_FLAG_VENDOR) != 0;
-    }
-
-    @Override
-    public boolean isProduct() {
-        return (privateFlags & ApplicationInfo.PRIVATE_FLAG_PRODUCT) != 0;
-    }
-
-    @Override
-    public boolean isOem() {
-        return (privateFlags & ApplicationInfo.PRIVATE_FLAG_OEM) != 0;
-    }
-
-    @Override
-    public boolean isEncryptionAware() {
-        boolean isPartiallyDirectBootAware =
-                (privateFlags & ApplicationInfo.PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE) != 0;
-        return isDirectBootAware() || isPartiallyDirectBootAware;
-    }
-
-    @Override
-    public boolean isEmbeddedDexUsed() {
-        return (privateFlags & ApplicationInfo.PRIVATE_FLAG_USE_EMBEDDED_DEX) != 0;
-    }
-
-    @Deprecated
-    @Override
-    public String getAppInfoProcessName() {
-        return processName;
-    }
-
-    @Override
-    public List<String> getAllCodePathsExcludingResourceOnly() {
-        ArrayList<String> paths = new ArrayList<>();
-        if ((flags & ApplicationInfo.FLAG_HAS_CODE) != 0) {
-            paths.add(baseCodePath);
-        }
-        if (!ArrayUtils.isEmpty(splitCodePaths)) {
-            for (int i = 0; i < splitCodePaths.length; i++) {
-                if ((splitFlags[i] & ApplicationInfo.FLAG_HAS_CODE) != 0) {
-                    paths.add(splitCodePaths[i]);
-                }
-            }
-        }
-        return paths;
-    }
-
-    @Deprecated
-    @Override
-    public String getAppInfoName() {
-        return name;
-    }
-
-    private boolean isSignedWithPlatformKey() {
-        return (privateFlags & ApplicationInfo.PRIVATE_FLAG_SIGNED_WITH_PLATFORM_KEY) != 0;
-    }
-
-    private boolean usesNonSdkApi() {
-        return (privateFlags & ApplicationInfo.PRIVATE_FLAG_USES_NON_SDK_API) != 0;
-    }
-
-    private boolean isPackageWhitelistedForHiddenApis() {
-        return SystemConfig.getInstance().getHiddenApiWhitelistedApps().contains(packageName);
-    }
-
-    private boolean isAllowedToUseHiddenApis() {
-        if (isSignedWithPlatformKey()) {
-            return true;
-        } else if (isSystemApp() || isUpdatedSystemApp()) {
-            return usesNonSdkApi() || isPackageWhitelistedForHiddenApis();
-        } else {
-            return false;
-        }
-    }
-
-    @Override
-    public int getHiddenApiEnforcementPolicy() {
-        if (isAllowedToUseHiddenApis()) {
-            return ApplicationInfo.HIDDEN_API_ENFORCEMENT_DISABLED;
-        }
-
-        // TODO(b/135203078): Handle maybeUpdateHiddenApiEnforcementPolicy. Right now it's done
-        //  entirely through ApplicationInfo and shouldn't touch this specific class, but that
-        //  may not always hold true.
-//        if (mHiddenApiPolicy != ApplicationInfo.HIDDEN_API_ENFORCEMENT_DEFAULT) {
-//            return mHiddenApiPolicy;
-//        }
-        return ApplicationInfo.HIDDEN_API_ENFORCEMENT_ENABLED;
-    }
-
-    @Nullable
-    @Override
-    public SparseArray<int[]> getSplitDependencies() {
-        return splitDependencies;
-    }
-
-    @Override
-    public boolean requestsIsolatedSplitLoading() {
-        return (privateFlags & ApplicationInfo.PRIVATE_FLAG_ISOLATED_SPLIT_LOADING) != 0;
-    }
-
-    @Deprecated
-    @Override
-    public String getAppInfoClassLoaderName() {
-        return classLoaderName;
-    }
-
-    @Override
-    public String getClassLoaderName() {
-        return classLoaderName;
-    }
-
-    @Override
-    public String[] getSplitClassLoaderNames() {
-        return splitClassLoaderNames;
-    }
-
-    @Override
-    public String getOverlayCategory() {
-        return overlayCategory;
-    }
-
-    @Override
-    public boolean isProfileableByShell() {
-        return (privateFlags & ApplicationInfo.PRIVATE_FLAG_PROFILEABLE_BY_SHELL) != 0;
-    }
-
-    @Nullable
-    @Override
-    public List<ParsedActivityIntentInfo> getPreferredActivityFilters() {
-        return preferredActivityFilters;
-    }
-
-    @Override
-    public boolean isHiddenUntilInstalled() {
-        return hiddenUntilInstalled;
-    }
-
-    @Override
-    public int getMinSdkVersion() {
-        return minSdkVersion;
-    }
-
-    @Override
-    public String getRestrictedAccountType() {
-        return restrictedAccountType;
-    }
-
-    @Override
-    public String getRequiredAccountType() {
-        return requiredAccountType;
-    }
-
-    @Override
-    public int getInstallLocation() {
-        return installLocation;
-    }
-
-    @Override
-    public List<ParsedActivity> getReceivers() {
-        return receivers;
-    }
-
-    @Override
-    public List<ParsedService> getServices() {
-        return services;
-    }
-
-    @Override
-    public List<ParsedProvider> getProviders() {
-        return providers;
-    }
-
-    @Override
-    public int getSharedUserLabel() {
-        return sharedUserLabel;
-    }
-
-    @Override
-    public int getVersionCodeMajor() {
-        return versionCodeMajor;
-    }
-
-    @Override
-    public boolean isRequiredForAllUsers() {
-        return requiredForAllUsers;
-    }
-
-    @Override
-    public int getCompileSdkVersion() {
-        return compileSdkVersion;
-    }
-
-    @Override
-    public String getCompileSdkVersionCodeName() {
-        return compileSdkVersionCodename;
-    }
-
-    @Nullable
-    @Override
-    public List<ConfigurationInfo> getConfigPreferences() {
-        return configPreferences;
-    }
-
-    @Nullable
-    @Override
-    public List<FeatureInfo> getReqFeatures() {
-        return reqFeatures;
-    }
-
-    @Override
-    public List<FeatureGroupInfo> getFeatureGroups() {
-        return featureGroups;
-    }
-
-    @Override
-    public String getDeviceProtectedDataDir() {
-        return deviceProtectedDataDir;
-    }
-
-    @Override
-    public String getCredentialProtectedDataDir() {
-        return credentialProtectedDataDir;
-    }
-
-    @Override
-    public String getSeInfoUser() {
-        return seInfoUser;
-    }
-
-    @Override
-    public String getClassName() {
-        return className;
-    }
-
-    @Override
-    public int getTheme() {
-        return theme;
-    }
-
-    @Override
-    public int getRequiresSmallestWidthDp() {
-        return requiresSmallestWidthDp;
-    }
-
-    @Override
-    public int getCompatibleWidthLimitDp() {
-        return compatibleWidthLimitDp;
-    }
-
-    @Override
-    public int getLargestWidthLimitDp() {
-        return largestWidthLimitDp;
-    }
-
-    @Override
-    public String getScanSourceDir() {
-        return applicationInfoCodePath;
-    }
-
-    @Override
-    public String getScanPublicSourceDir() {
-        return applicationInfoResourcePath;
-    }
-
-    @Override
-    public String getPublicSourceDir() {
-        return applicationInfoBaseResourcePath;
-    }
-
-    @Override
-    public String[] getSplitPublicSourceDirs() {
-        return applicationInfoSplitResourcePaths;
-    }
-
-    @Override
-    public String getSecondaryNativeLibraryDir() {
-        return secondaryNativeLibraryDir;
-    }
-
-    @Override
-    public boolean isEnabled() {
-        return enabled;
-    }
-
-    @Override
-    public boolean isCrossProfile() {
-        return crossProfile;
-    }
-
-    @Override
-    public String getManageSpaceActivityName() {
-        return manageSpaceActivityName;
-    }
-
-    @Override
-    public int getDescriptionRes() {
-        return descriptionRes;
-    }
-
-    @Override
-    public String getBackupAgentName() {
-        return backupAgentName;
-    }
-
-    @Override
-    public int getFullBackupContent() {
-        return fullBackupContent;
-    }
-
-    @Override
-    public int getNetworkSecurityConfigRes() {
-        return networkSecurityConfigRes;
-    }
-
-    @Override
-    public int getCategory() {
-        return category;
-    }
-
-    @Override
-    public int getTargetSandboxVersion() {
-        return targetSandboxVersion;
-    }
-
-    @Override
-    public String getAppComponentFactory() {
-        return appComponentFactory;
-    }
-
-    @Override
-    public int getIconRes() {
-        return iconRes;
-    }
-
-    @Override
-    public int getRoundIconRes() {
-        return roundIconRes;
-    }
-
-    @Override
-    public String getZygotePreloadName() {
-        return zygotePreloadName;
-    }
-
-    @Override
-    public int getLabelRes() {
-        return labelRes;
-    }
-
-    @Override
-    public CharSequence getNonLocalizedLabel() {
-        return nonLocalizedLabel;
-    }
-
-    @Override
-    public int getIcon() {
-        return icon;
-    }
-
-    @Override
-    public int getBanner() {
-        return banner;
-    }
-
-    @Override
-    public int getLogo() {
-        return logo;
-    }
-
-    @Override
-    public Bundle getMetaData() {
-        return appMetaData;
-    }
-
-    private void addMimeGroupsFromComponent(ParsedComponent<?> component) {
-        for (int i = component.intents.size() - 1; i >= 0; i--) {
-            IntentFilter filter = component.intents.get(i);
-            for (int groupIndex = filter.countMimeGroups() - 1; groupIndex >= 0; groupIndex--) {
-                mimeGroups = ArrayUtils.add(mimeGroups, filter.getMimeGroup(groupIndex));
-            }
-        }
-    }
-
-    @Override
-    @Nullable
-    public Set<String> getMimeGroups() {
-        return mimeGroups;
-    }
-
-    @Override
-    @Nullable
-    public List<Intent> getQueriesIntents() {
-        return queriesIntents;
-    }
-
-    @Override
-    @Nullable
-    public List<String> getQueriesPackages() {
-        return queriesPackages;
-    }
-
-    @Override
-    public Set<String> getQueriesProviders() {
-        return queriesProviders;
-    }
-
-    @Override
-    public boolean hasPreserveLegacyExternalStorage() {
-        return preserveLegacyExternalStorage;
-    }
-
-    private static void internStringArrayList(List<String> list) {
-        if (list != null) {
-            final int N = list.size();
-            for (int i = 0; i < N; ++i) {
-                list.set(i, list.get(i).intern());
-            }
-        }
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeInt(this.supportsSmallScreens);
-        dest.writeInt(this.supportsNormalScreens);
-        dest.writeInt(this.supportsLargeScreens);
-        dest.writeInt(this.supportsXLargeScreens);
-        dest.writeInt(this.resizeable);
-        dest.writeInt(this.anyDensity);
-        dest.writeLongArray(this.lastPackageUsageTimeInMills);
-        dest.writeInt(this.versionCode);
-        dest.writeInt(this.versionCodeMajor);
-        dest.writeInt(this.baseRevisionCode);
-        dest.writeString(this.versionName);
-        dest.writeBoolean(this.coreApp);
-        dest.writeInt(this.compileSdkVersion);
-        dest.writeString(this.compileSdkVersionCodename);
-        dest.writeString(this.packageName);
-        dest.writeString(this.realPackage);
-        dest.writeString(this.manifestPackageName);
-        dest.writeString(this.baseCodePath);
-        dest.writeBoolean(this.requiredForAllUsers);
-        dest.writeString(this.restrictedAccountType);
-        dest.writeString(this.requiredAccountType);
-        dest.writeBoolean(this.baseHardwareAccelerated);
-        dest.writeString(this.overlayTarget);
-        dest.writeString(this.overlayTargetName);
-        dest.writeString(this.overlayCategory);
-        dest.writeInt(this.overlayPriority);
-        dest.writeBoolean(this.overlayIsStatic);
-        dest.writeMap(this.overlayables);
-        dest.writeString(this.staticSharedLibName);
-        dest.writeLong(this.staticSharedLibVersion);
-        dest.writeStringList(this.libraryNames);
-        dest.writeStringList(this.usesLibraries);
-        dest.writeStringList(this.usesOptionalLibraries);
-        dest.writeStringList(this.usesStaticLibraries);
-        dest.writeLongArray(this.usesStaticLibrariesVersions);
-        final int numProcesses = this.processes != null ? this.processes.size() : 0;
-        dest.writeInt(numProcesses);
-        for (int i = 0; i < numProcesses; i++) {
-            this.processes.valueAt(i).writeToParcel(dest, 0);
-        }
-
-        if (this.usesStaticLibrariesCertDigests == null) {
-            dest.writeInt(-1);
-        } else {
-            dest.writeInt(this.usesStaticLibrariesCertDigests.length);
-            for (int index = 0; index < this.usesStaticLibrariesCertDigests.length; index++) {
-                dest.writeStringArray(this.usesStaticLibrariesCertDigests[index]);
-            }
-        }
-
-        dest.writeString(this.sharedUserId);
-        dest.writeInt(this.sharedUserLabel);
-        dest.writeTypedList(this.configPreferences);
-        dest.writeTypedList(this.reqFeatures);
-        dest.writeTypedList(this.featureGroups);
-        dest.writeByteArray(this.restrictUpdateHash);
-        dest.writeStringList(this.originalPackages);
-        dest.writeStringList(this.adoptPermissions);
-        dest.writeStringList(this.requestedPermissions);
-        dest.writeStringList(this.implicitPermissions);
-        dest.writeArraySet(this.upgradeKeySets);
-        dest.writeMap(this.keySetMapping);
-        dest.writeStringList(this.protectedBroadcasts);
-        dest.writeTypedList(this.activities);
-        dest.writeTypedList(this.receivers);
-        dest.writeTypedList(this.services);
-        dest.writeTypedList(this.providers);
-        dest.writeTypedList(this.features);
-        dest.writeTypedList(this.permissions);
-        dest.writeTypedList(this.permissionGroups);
-        dest.writeTypedList(this.instrumentations);
-        ParsedIntentInfo.writeIntentsList(this.preferredActivityFilters, dest, flags);
-        dest.writeBundle(this.appMetaData);
-        dest.writeString(this.volumeUuid);
-        dest.writeString(this.applicationVolumeUuid);
-        dest.writeParcelable(this.signingDetails, flags);
-        dest.writeString(this.codePath);
-        dest.writeBoolean(this.use32BitAbi);
-        dest.writeBoolean(this.visibleToInstantApps);
-        dest.writeString(this.cpuAbiOverride);
-        dest.writeBoolean(this.isStub);
-        dest.writeInt(this.preferredOrder);
-        dest.writeBoolean(this.forceQueryable);
-        dest.writeParcelableList(this.queriesIntents, flags);
-        dest.writeStringList(this.queriesPackages);
-        dest.writeString(this.applicationInfoBaseResourcePath);
-        dest.writeString(this.applicationInfoCodePath);
-        dest.writeString(this.applicationInfoResourcePath);
-        dest.writeStringArray(this.applicationInfoSplitResourcePaths);
-        dest.writeString(this.appComponentFactory);
-        dest.writeString(this.backupAgentName);
-        dest.writeInt(this.banner);
-        dest.writeInt(this.category);
-        dest.writeString(this.classLoaderName);
-        dest.writeString(this.className);
-        dest.writeInt(this.compatibleWidthLimitDp);
-        dest.writeString(this.credentialProtectedDataDir);
-        dest.writeString(this.dataDir);
-        dest.writeInt(this.descriptionRes);
-        dest.writeString(this.deviceProtectedDataDir);
-        dest.writeBoolean(this.enabled);
-        dest.writeBoolean(this.crossProfile);
-        dest.writeInt(this.flags);
-        dest.writeInt(this.fullBackupContent);
-        dest.writeBoolean(this.hiddenUntilInstalled);
-        dest.writeInt(this.icon);
-        dest.writeInt(this.iconRes);
-        dest.writeInt(this.installLocation);
-        dest.writeInt(this.labelRes);
-        dest.writeInt(this.largestWidthLimitDp);
-        dest.writeInt(this.logo);
-        dest.writeString(this.manageSpaceActivityName);
-        dest.writeFloat(this.maxAspectRatio);
-        dest.writeFloat(this.minAspectRatio);
-        dest.writeInt(this.minSdkVersion);
-        dest.writeString(this.name);
-        dest.writeString(this.nativeLibraryDir);
-        dest.writeString(this.nativeLibraryRootDir);
-        dest.writeBoolean(this.nativeLibraryRootRequiresIsa);
-        dest.writeInt(this.networkSecurityConfigRes);
-        dest.writeCharSequence(this.nonLocalizedLabel);
-        dest.writeString(this.permission);
-        dest.writeString(this.primaryCpuAbi);
-        dest.writeInt(this.privateFlags);
-        dest.writeString(this.processName);
-        dest.writeInt(this.requiresSmallestWidthDp);
-        dest.writeInt(this.roundIconRes);
-        dest.writeString(this.secondaryCpuAbi);
-        dest.writeString(this.secondaryNativeLibraryDir);
-        dest.writeString(this.seInfo);
-        dest.writeString(this.seInfoUser);
-        dest.writeInt(this.targetSandboxVersion);
-        dest.writeInt(this.targetSdkVersion);
-        dest.writeString(this.taskAffinity);
-        dest.writeInt(this.theme);
-        dest.writeInt(this.uid);
-        dest.writeInt(this.uiOptions);
-        dest.writeStringArray(this.usesLibraryFiles);
-        dest.writeTypedList(this.usesLibraryInfos);
-        dest.writeString(this.zygotePreloadName);
-        dest.writeStringArray(this.splitClassLoaderNames);
-        dest.writeStringArray(this.splitCodePaths);
-        dest.writeSparseArray(this.splitDependencies);
-        dest.writeIntArray(this.splitFlags);
-        dest.writeStringArray(this.splitNames);
-        dest.writeIntArray(this.splitRevisionCodes);
-        dest.writeArraySet(this.mimeGroups);
-    }
-
-    public PackageImpl(Parcel in) {
-        // We use the boot classloader for all classes that we load.
-        final ClassLoader boot = Object.class.getClassLoader();
-        this.supportsSmallScreens = in.readInt();
-        this.supportsNormalScreens = in.readInt();
-        this.supportsLargeScreens = in.readInt();
-        this.supportsXLargeScreens = in.readInt();
-        this.resizeable = in.readInt();
-        this.anyDensity = in.readInt();
-        this.lastPackageUsageTimeInMills = in.createLongArray();
-        this.versionCode = in.readInt();
-        this.versionCodeMajor = in.readInt();
-        this.baseRevisionCode = in.readInt();
-        this.versionName = TextUtils.safeIntern(in.readString());
-        this.coreApp = in.readBoolean();
-        this.compileSdkVersion = in.readInt();
-        this.compileSdkVersionCodename = TextUtils.safeIntern(in.readString());
-        this.packageName = TextUtils.safeIntern(in.readString());
-        this.realPackage = in.readString();
-        this.manifestPackageName = in.readString();
-        this.baseCodePath = in.readString();
-        this.requiredForAllUsers = in.readBoolean();
-        this.restrictedAccountType = in.readString();
-        this.requiredAccountType = in.readString();
-        this.baseHardwareAccelerated = in.readBoolean();
-        this.overlayTarget = in.readString();
-        this.overlayTargetName = in.readString();
-        this.overlayCategory = in.readString();
-        this.overlayPriority = in.readInt();
-        this.overlayIsStatic = in.readBoolean();
-        this.overlayables = new HashMap<>();
-        in.readMap(overlayables, boot);
-        this.staticSharedLibName = TextUtils.safeIntern(in.readString());
-        this.staticSharedLibVersion = in.readLong();
-        this.libraryNames = in.createStringArrayList();
-        internStringArrayList(this.libraryNames);
-        this.usesLibraries = in.createStringArrayList();
-        internStringArrayList(this.usesLibraries);
-        this.usesOptionalLibraries = in.createStringArrayList();
-        internStringArrayList(this.usesOptionalLibraries);
-        this.usesStaticLibraries = in.createStringArrayList();
-        internStringArrayList(usesStaticLibraries);
-        this.usesStaticLibrariesVersions = in.createLongArray();
-        final int numProcesses = in.readInt();
-        if (numProcesses > 0) {
-            this.processes = new ArrayMap<>(numProcesses);
-            for (int i = 0; i < numProcesses; i++) {
-                ComponentParseUtils.ParsedProcess proc = new ComponentParseUtils.ParsedProcess(in);
-                this.processes.put(proc.name, proc);
-            }
-        } else {
-            this.processes = null;
-        }
-
-        int digestsSize = in.readInt();
-        if (digestsSize >= 0) {
-            this.usesStaticLibrariesCertDigests = new String[digestsSize][];
-            for (int index = 0; index < digestsSize; index++) {
-                this.usesStaticLibrariesCertDigests[index] = in.readStringArray();
-            }
-        }
-
-        this.sharedUserId = TextUtils.safeIntern(in.readString());
-        this.sharedUserLabel = in.readInt();
-        this.configPreferences = in.createTypedArrayList(ConfigurationInfo.CREATOR);
-        this.reqFeatures = in.createTypedArrayList(FeatureInfo.CREATOR);
-        this.featureGroups = in.createTypedArrayList(FeatureGroupInfo.CREATOR);
-        this.restrictUpdateHash = in.createByteArray();
-        this.originalPackages = in.createStringArrayList();
-        this.adoptPermissions = in.createStringArrayList();
-        this.requestedPermissions = in.createStringArrayList();
-        internStringArrayList(this.requestedPermissions);
-        this.implicitPermissions = in.createStringArrayList();
-        internStringArrayList(this.implicitPermissions);
-        this.upgradeKeySets = (ArraySet<String>) in.readArraySet(boot);
-        this.keySetMapping = in.readHashMap(boot);
-        this.protectedBroadcasts = in.createStringArrayList();
-        internStringArrayList(this.protectedBroadcasts);
-        this.activities = in.createTypedArrayList(ParsedActivity.CREATOR);
-        this.receivers = in.createTypedArrayList(ParsedActivity.CREATOR);
-        this.services = in.createTypedArrayList(ParsedService.CREATOR);
-        this.providers = in.createTypedArrayList(ParsedProvider.CREATOR);
-        this.features = in.createTypedArrayList(ParsedFeature.CREATOR);
-        this.permissions = in.createTypedArrayList(ParsedPermission.CREATOR);
-        this.permissionGroups = in.createTypedArrayList(ParsedPermissionGroup.CREATOR);
-        this.instrumentations = in.createTypedArrayList(ParsedInstrumentation.CREATOR);
-        this.preferredActivityFilters = ParsedIntentInfo.createIntentsList(in);
-        this.appMetaData = in.readBundle(boot);
-        this.volumeUuid = in.readString();
-        this.applicationVolumeUuid = in.readString();
-        this.signingDetails = in.readParcelable(boot);
-        this.codePath = in.readString();
-        this.use32BitAbi = in.readBoolean();
-        this.visibleToInstantApps = in.readBoolean();
-        this.cpuAbiOverride = in.readString();
-        this.isStub = in.readBoolean();
-        this.preferredOrder = in.readInt();
-        this.forceQueryable = in.readBoolean();
-        this.queriesIntents = in.createTypedArrayList(Intent.CREATOR);
-        this.queriesPackages = in.createStringArrayList();
-        internStringArrayList(this.queriesPackages);
-        this.applicationInfoBaseResourcePath = in.readString();
-        this.applicationInfoCodePath = in.readString();
-        this.applicationInfoResourcePath = in.readString();
-        this.applicationInfoSplitResourcePaths = in.createStringArray();
-        this.appComponentFactory = in.readString();
-        this.backupAgentName = in.readString();
-        this.banner = in.readInt();
-        this.category = in.readInt();
-        this.classLoaderName = in.readString();
-        this.className = in.readString();
-        this.compatibleWidthLimitDp = in.readInt();
-        this.credentialProtectedDataDir = in.readString();
-        this.dataDir = in.readString();
-        this.descriptionRes = in.readInt();
-        this.deviceProtectedDataDir = in.readString();
-        this.enabled = in.readBoolean();
-        this.crossProfile = in.readBoolean();
-        this.flags = in.readInt();
-        this.fullBackupContent = in.readInt();
-        this.hiddenUntilInstalled = in.readBoolean();
-        this.icon = in.readInt();
-        this.iconRes = in.readInt();
-        this.installLocation = in.readInt();
-        this.labelRes = in.readInt();
-        this.largestWidthLimitDp = in.readInt();
-        this.logo = in.readInt();
-        this.manageSpaceActivityName = in.readString();
-        this.maxAspectRatio = in.readFloat();
-        this.minAspectRatio = in.readFloat();
-        this.minSdkVersion = in.readInt();
-        this.name = in.readString();
-        this.nativeLibraryDir = in.readString();
-        this.nativeLibraryRootDir = in.readString();
-        this.nativeLibraryRootRequiresIsa = in.readBoolean();
-        this.networkSecurityConfigRes = in.readInt();
-        this.nonLocalizedLabel = in.readCharSequence();
-        this.permission = TextUtils.safeIntern(in.readString());
-        this.primaryCpuAbi = in.readString();
-        this.privateFlags = in.readInt();
-        this.processName = in.readString();
-        this.requiresSmallestWidthDp = in.readInt();
-        this.roundIconRes = in.readInt();
-        this.secondaryCpuAbi = in.readString();
-        this.secondaryNativeLibraryDir = in.readString();
-        this.seInfo = in.readString();
-        this.seInfoUser = in.readString();
-        this.targetSandboxVersion = in.readInt();
-        this.targetSdkVersion = in.readInt();
-        this.taskAffinity = in.readString();
-        this.theme = in.readInt();
-        this.uid = in.readInt();
-        this.uiOptions = in.readInt();
-        this.usesLibraryFiles = in.createStringArray();
-        this.usesLibraryInfos = in.createTypedArrayList(SharedLibraryInfo.CREATOR);
-        this.zygotePreloadName = in.readString();
-        this.splitClassLoaderNames = in.createStringArray();
-        this.splitCodePaths = in.createStringArray();
-        this.splitDependencies = in.readSparseArray(boot);
-        this.splitFlags = in.createIntArray();
-        this.splitNames = in.createStringArray();
-        this.splitRevisionCodes = in.createIntArray();
-        this.mimeGroups = (ArraySet<String>) in.readArraySet(boot);
-    }
-
-    public static final Creator<PackageImpl> CREATOR = new Creator<PackageImpl>() {
-        @Override
-        public PackageImpl createFromParcel(Parcel source) {
-            return new PackageImpl(source);
-        }
-
-        @Override
-        public PackageImpl[] newArray(int size) {
-            return new PackageImpl[size];
-        }
-    };
-}
diff --git a/core/java/android/content/pm/parsing/PackageInfoUtils.java b/core/java/android/content/pm/parsing/PackageInfoUtils.java
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..e7d91c2
--- /dev/null
+++ b/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java
@@ -0,0 +1,697 @@
+/*
+ * 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.ParsingPackage;
+import android.os.Environment;
+import android.os.UserHandle;
+
+import com.android.internal.util.ArrayUtils;
+import android.content.pm.parsing.component.ComponentParseUtils;
+import android.content.pm.parsing.component.ParsedActivity;
+import android.content.pm.parsing.component.ParsedComponent;
+import android.content.pm.parsing.component.ParsedInstrumentation;
+import android.content.pm.parsing.component.ParsedMainComponent;
+import android.content.pm.parsing.component.ParsedPermission;
+import android.content.pm.parsing.component.ParsedPermissionGroup;
+import android.content.pm.parsing.component.ParsedProvider;
+import android.content.pm.parsing.component.ParsedService;
+
+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 (ComponentParseUtils.isMatch(state, 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 (ComponentParseUtils.isMatch(state, 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 (ComponentParseUtils.isMatch(state, 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 (ComponentParseUtils.isMatch(state, 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.getTargetActivity();
+        ai.processName = a.getProcessName();
+        ai.exported = a.isExported();
+        ai.theme = a.getTheme();
+        ai.uiOptions = a.getUiOptions();
+        ai.parentActivityName = a.getParentActivityName();
+        ai.permission = a.getPermission();
+        ai.taskAffinity = a.getTaskAffinity();
+        ai.flags = a.getFlags();
+        ai.privateFlags = a.getPrivateFlags();
+        ai.launchMode = a.getLaunchMode();
+        ai.documentLaunchMode = a.getDocumentLaunchMode();
+        ai.maxRecents = a.getMaxRecents();
+        ai.configChanges = a.getConfigChanges();
+        ai.softInputMode = a.getSoftInputMode();
+        ai.persistableMode = a.getPersistableMode();
+        ai.lockTaskLaunchMode = a.getLockTaskLaunchMode();
+        ai.screenOrientation = a.getScreenOrientation();
+        ai.resizeMode = a.getResizeMode();
+        Float maxAspectRatio = a.getMaxAspectRatio();
+        ai.maxAspectRatio = maxAspectRatio != null ? maxAspectRatio : 0f;
+        Float minAspectRatio = a.getMinAspectRatio();
+        ai.minAspectRatio = minAspectRatio != null ? minAspectRatio : 0f;
+        ai.requestedVrComponent = a.getRequestedVrComponent();
+        ai.rotationAnimation = a.getRotationAnimation();
+        ai.colorMode = a.getColorMode();
+        ai.preferMinimalPostProcessing = a.isPreferMinimalPostProcessing();
+        ai.windowLayout = a.getWindowLayout();
+        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.isExported();
+        si.flags = s.getFlags();
+        si.metaData = s.getMetaData();
+        si.permission = s.getPermission();
+        si.processName = s.getProcessName();
+        si.mForegroundServiceType = s.getForegroundServiceType();
+        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.isHandleProfiling();
+        ii.functionalTest = i.isFunctionalTest();
+
+        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, userId).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.getBackgroundPermission());
+
+        assignSharedFieldsForPackageItemInfo(pi, p);
+
+        pi.group = p.getGroup();
+        pi.requestRes = p.getRequestRes();
+        pi.protectionLevel = p.getProtectionLevel();
+        pi.descriptionRes = p.getDescriptionRes();
+        pi.flags = p.getFlags();
+
+        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.getRequestDetailResourceId(),
+                pg.getBackgroundRequestResourceId(),
+                pg.getBackgroundRequestDetailResourceId()
+        );
+
+        assignSharedFieldsForPackageItemInfo(pgi, pg);
+        pgi.descriptionRes = pg.getDescriptionRes();
+        pgi.priority = pg.getPriority();
+        pgi.requestRes = pg.getRequestRes();
+        pgi.flags = pg.getFlags();
+
+        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.getDescriptionRes();
+        componentInfo.directBootAware = mainComponent.isDirectBootAware();
+        componentInfo.enabled = mainComponent.isEnabled();
+        componentInfo.splitName = mainComponent.getSplitName();
+    }
+
+    private static void assignSharedFieldsForPackageItemInfo(
+            @NonNull PackageItemInfo packageItemInfo, @NonNull ParsedComponent component) {
+        packageItemInfo.nonLocalizedLabel = ComponentParseUtils.getNonLocalizedLabel(component);
+        packageItemInfo.icon = ComponentParseUtils.getIcon(component);
+
+        packageItemInfo.banner = component.getBanner();
+        packageItemInfo.labelRes = component.getLabelRes();
+        packageItemInfo.logo = component.getLogo();
+        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/ParsingPackage.java b/core/java/android/content/pm/parsing/ParsingPackage.java
index 74a2640..aa93d80 100644
--- a/core/java/android/content/pm/parsing/ParsingPackage.java
+++ b/core/java/android/content/pm/parsing/ParsingPackage.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2019 The Android Open Source Project
+ * 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.
@@ -16,35 +16,36 @@
 
 package android.content.pm.parsing;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.Intent;
 import android.content.pm.ConfigurationInfo;
 import android.content.pm.FeatureGroupInfo;
 import android.content.pm.FeatureInfo;
 import android.content.pm.PackageParser;
-import android.content.pm.parsing.ComponentParseUtils.ParsedActivity;
-import android.content.pm.parsing.ComponentParseUtils.ParsedActivityIntentInfo;
-import android.content.pm.parsing.ComponentParseUtils.ParsedFeature;
-import android.content.pm.parsing.ComponentParseUtils.ParsedInstrumentation;
-import android.content.pm.parsing.ComponentParseUtils.ParsedPermission;
-import android.content.pm.parsing.ComponentParseUtils.ParsedPermissionGroup;
-import android.content.pm.parsing.ComponentParseUtils.ParsedProvider;
-import android.content.pm.parsing.ComponentParseUtils.ParsedService;
+import android.content.pm.parsing.component.ParsedActivity;
+import android.content.pm.parsing.component.ParsedFeature;
+import android.content.pm.parsing.component.ParsedInstrumentation;
+import android.content.pm.parsing.component.ParsedIntentInfo;
+import android.content.pm.parsing.component.ParsedPermission;
+import android.content.pm.parsing.component.ParsedPermissionGroup;
+import android.content.pm.parsing.component.ParsedProcess;
+import android.content.pm.parsing.component.ParsedProvider;
+import android.content.pm.parsing.component.ParsedService;
 import android.os.Bundle;
-import android.util.ArrayMap;
-import android.util.ArraySet;
 import android.util.SparseArray;
 
 import java.security.PublicKey;
+import java.util.Map;
+import java.util.Set;
 
 /**
  * Methods used for mutation during direct package parsing.
  *
- * Java disallows defining this as an inner interface, so this must be a separate file.
- *
  * @hide
  */
-public interface ParsingPackage extends AndroidPackage {
+@SuppressWarnings("UnusedReturnValue")
+public interface ParsingPackage extends ParsingPackageRead {
 
     ParsingPackage addActivity(ParsedActivity parsedActivity);
 
@@ -66,18 +67,18 @@
 
     ParsingPackage addOverlayable(String overlayableName, String actorName);
 
-    ParsingPackage addFeature(ParsedFeature permission);
-
     ParsingPackage addPermission(ParsedPermission permission);
 
     ParsingPackage addPermissionGroup(ParsedPermissionGroup permissionGroup);
 
-    ParsingPackage addPreferredActivityFilter(ParsedActivityIntentInfo activityIntentInfo);
+    ParsingPackage addPreferredActivityFilter(String className, ParsedIntentInfo intentInfo);
 
     ParsingPackage addProtectedBroadcast(String protectedBroadcast);
 
     ParsingPackage addProvider(ParsedProvider parsedProvider);
 
+    ParsingPackage addFeature(ParsedFeature permission);
+
     ParsingPackage addReceiver(ParsedActivity parsedReceiver);
 
     ParsingPackage addReqFeature(FeatureInfo reqFeature);
@@ -102,7 +103,7 @@
 
     ParsingPackage addQueriesProvider(String authority);
 
-    ParsingPackage setProcesses(ArrayMap<String, ComponentParseUtils.ParsedProcess> processes);
+    ParsingPackage setProcesses(@NonNull Map<String, ParsedProcess> processes);
 
     ParsingPackage asSplit(
             String[] splitNames,
@@ -111,7 +112,7 @@
             @Nullable SparseArray<int[]> splitDependencies
     );
 
-    ParsingPackage setAppMetaData(Bundle appMetaData);
+    ParsingPackage setMetaData(Bundle metaData);
 
     ParsingPackage setForceQueryable(boolean forceQueryable);
 
@@ -119,8 +120,6 @@
 
     ParsingPackage setMinAspectRatio(float minAspectRatio);
 
-    ParsingPackage setName(String name);
-
     ParsingPackage setPermission(String permission);
 
     ParsingPackage setProcessName(String processName);
@@ -137,9 +136,9 @@
 
     ParsingPackage setBaseHardwareAccelerated(boolean baseHardwareAccelerated);
 
-    ParsingPackage setActivitiesResizeModeResizeable(boolean resizeable);
+    ParsingPackage setResizeableActivity(Boolean resizeable);
 
-    ParsingPackage setActivitiesResizeModeResizeableViaSdkVersion(boolean resizeableViaSdkVersion);
+    ParsingPackage setResizeableActivityViaSdkVersion(boolean resizeableViaSdkVersion);
 
     ParsingPackage setAllowAudioPlaybackCapture(boolean allowAudioPlaybackCapture);
 
@@ -151,7 +150,7 @@
 
     ParsingPackage setAllowTaskReparenting(boolean allowTaskReparenting);
 
-    ParsingPackage setIsOverlay(boolean isOverlay);
+    ParsingPackage setOverlay(boolean isOverlay);
 
     ParsingPackage setBackupInForeground(boolean backupInForeground);
 
@@ -173,7 +172,7 @@
 
     ParsingPackage setHasFragileUserData(boolean hasFragileUserData);
 
-    ParsingPackage setIsGame(boolean isGame);
+    ParsingPackage setGame(boolean isGame);
 
     ParsingPackage setIsolatedSplitLoading(boolean isolatedSplitLoading);
 
@@ -221,8 +220,6 @@
 
     ParsingPackage setAppComponentFactory(String appComponentFactory);
 
-    ParsingPackage setApplicationVolumeUuid(String applicationVolumeUuid);
-
     ParsingPackage setBackupAgentName(String backupAgentName);
 
     ParsingPackage setBanner(int banner);
@@ -233,8 +230,6 @@
 
     ParsingPackage setClassName(String className);
 
-    ParsingPackage setCodePath(String codePath);
-
     ParsingPackage setCompatibleWidthLimitDp(int compatibleWidthLimitDp);
 
     ParsingPackage setDescriptionRes(int descriptionRes);
@@ -247,8 +242,6 @@
 
     ParsingPackage setHasDomainUrls(boolean hasDomainUrls);
 
-    ParsingPackage setIcon(int icon);
-
     ParsingPackage setIconRes(int iconRes);
 
     ParsingPackage setInstallLocation(int installLocation);
@@ -307,17 +300,17 @@
 
     ParsingPackage setSupportsSmallScreens(int supportsSmallScreens);
 
-    ParsingPackage setSupportsXLargeScreens(int supportsXLargeScreens);
+    ParsingPackage setSupportsExtraLargeScreens(int supportsExtraLargeScreens);
 
     ParsingPackage setTargetSandboxVersion(int targetSandboxVersion);
 
     ParsingPackage setTheme(int theme);
 
-    ParsingPackage setUpgradeKeySets(ArraySet<String> upgradeKeySets);
+    ParsingPackage setUpgradeKeySets(@NonNull Set<String> upgradeKeySets);
 
     ParsingPackage setUse32BitAbi(boolean use32BitAbi);
 
-    ParsingPackage setVolumeUuid(String volumeUuid);
+    ParsingPackage setVolumeUuid(@Nullable String volumeUuid);
 
     ParsingPackage setZygotePreloadName(String zygotePreloadName);
 
@@ -327,17 +320,16 @@
 
     ParsingPackage sortServices();
 
-    ParsedPackage hideAsParsed();
-
     ParsingPackage setBaseRevisionCode(int baseRevisionCode);
 
-    ParsingPackage setPreferredOrder(int preferredOrder);
-
     ParsingPackage setVersionName(String versionName);
 
     ParsingPackage setCompileSdkVersion(int compileSdkVersion);
 
     ParsingPackage setCompileSdkVersionCodename(String compileSdkVersionCodename);
 
-    boolean usesCompatibilityMode();
+    // TODO(b/135203078): This class no longer has access to ParsedPackage, find a replacement
+    //  for moving to the next step
+    @Deprecated
+    Object hideAsParsed();
 }
diff --git a/core/java/android/content/pm/parsing/ParsingPackageImpl.java b/core/java/android/content/pm/parsing/ParsingPackageImpl.java
new file mode 100644
index 0000000..c3eea2b
--- /dev/null
+++ b/core/java/android/content/pm/parsing/ParsingPackageImpl.java
@@ -0,0 +1,2584 @@
+/*
+ * 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 static java.util.Collections.emptyList;
+import static java.util.Collections.emptyMap;
+import static java.util.Collections.emptySet;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.ConfigurationInfo;
+import android.content.pm.FeatureGroupInfo;
+import android.content.pm.FeatureInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageParser;
+import android.content.pm.parsing.component.ParsedActivity;
+import android.content.pm.parsing.component.ParsedComponent;
+import android.content.pm.parsing.component.ParsedFeature;
+import android.content.pm.parsing.component.ParsedInstrumentation;
+import android.content.pm.parsing.component.ParsedIntentInfo;
+import android.content.pm.parsing.component.ParsedMainComponent;
+import android.content.pm.parsing.component.ParsedPermission;
+import android.content.pm.parsing.component.ParsedPermissionGroup;
+import android.content.pm.parsing.component.ParsedProcess;
+import android.content.pm.parsing.component.ParsedProvider;
+import android.content.pm.parsing.component.ParsedService;
+import android.content.res.TypedArray;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.storage.StorageManager;
+import android.text.TextUtils;
+import android.util.ArraySet;
+import android.util.Pair;
+import android.util.SparseArray;
+
+import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.CollectionUtils;
+import com.android.internal.util.DataClass;
+import com.android.internal.util.Parcelling;
+import com.android.internal.util.Parcelling.BuiltIn.ForBoolean;
+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.ForInternedStringSet;
+import com.android.internal.util.Parcelling.BuiltIn.ForInternedStringValueMap;
+
+import java.security.PublicKey;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * The backing data for a package that was parsed from disk.
+ *
+ * The field nullability annotations here are for internal reference. For effective nullability,
+ * see the parent interfaces.
+ *
+ * TODO(b/135203078): Convert Lists used as sets into Sets, to better express intended use case
+ *
+ * @hide
+ */
+public class ParsingPackageImpl implements ParsingPackage, Parcelable {
+
+    private static final String TAG = "PackageImpl";
+
+    public static ForBoolean sForBoolean = Parcelling.Cache.getOrCreate(ForBoolean.class);
+    public static ForInternedString sForString = Parcelling.Cache.getOrCreate(
+            ForInternedString.class);
+    public static ForInternedStringArray sForStringArray = Parcelling.Cache.getOrCreate(
+            ForInternedStringArray.class);
+    public static ForInternedStringList sForStringList = Parcelling.Cache.getOrCreate(
+            ForInternedStringList.class);
+    public static ForInternedStringValueMap sForStringValueMap = Parcelling.Cache.getOrCreate(
+            ForInternedStringValueMap.class);
+    public static ForInternedStringSet sForStringSet = Parcelling.Cache.getOrCreate(
+            ForInternedStringSet.class);
+    protected static ParsedIntentInfo.StringPairListParceler sForIntentInfoPairs =
+            Parcelling.Cache.getOrCreate(ParsedIntentInfo.StringPairListParceler.class);
+
+    private static final Comparator<ParsedMainComponent> ORDER_COMPARATOR =
+            (first, second) -> Integer.compare(second.getOrder(), first.getOrder());
+
+    // These are objects because null represents not explicitly set
+    @Nullable
+    @DataClass.ParcelWith(ForBoolean.class)
+    private Boolean supportsSmallScreens;
+    @Nullable
+    @DataClass.ParcelWith(ForBoolean.class)
+    private Boolean supportsNormalScreens;
+    @Nullable
+    @DataClass.ParcelWith(ForBoolean.class)
+    private Boolean supportsLargeScreens;
+    @Nullable
+    @DataClass.ParcelWith(ForBoolean.class)
+    private Boolean supportsExtraLargeScreens;
+    @Nullable
+    @DataClass.ParcelWith(ForBoolean.class)
+    private Boolean resizeable;
+    @Nullable
+    @DataClass.ParcelWith(ForBoolean.class)
+    private Boolean anyDensity;
+
+    protected int versionCode;
+    protected int versionCodeMajor;
+    private int baseRevisionCode;
+    @Nullable
+    @DataClass.ParcelWith(ForInternedString.class)
+    private String versionName;
+
+    private int compileSdkVersion;
+    @Nullable
+    @DataClass.ParcelWith(ForInternedString.class)
+    private String compileSdkVersionCodeName;
+
+    @NonNull
+    @DataClass.ParcelWith(ForInternedString.class)
+    protected String packageName;
+
+    @Nullable
+    @DataClass.ParcelWith(ForInternedString.class)
+    private String realPackage;
+
+    @NonNull
+    protected String baseCodePath;
+
+    private boolean requiredForAllUsers;
+    @Nullable
+    @DataClass.ParcelWith(ForInternedString.class)
+    private String restrictedAccountType;
+    @Nullable
+    @DataClass.ParcelWith(ForInternedString.class)
+    private String requiredAccountType;
+
+    @Nullable
+    @DataClass.ParcelWith(ForInternedString.class)
+    private String overlayTarget;
+    @Nullable
+    @DataClass.ParcelWith(ForInternedString.class)
+    private String overlayTargetName;
+    @Nullable
+    @DataClass.ParcelWith(ForInternedString.class)
+    private String overlayCategory;
+    private int overlayPriority;
+    private boolean overlayIsStatic;
+    @NonNull
+    @DataClass.ParcelWith(ForInternedStringValueMap.class)
+    private Map<String, String> overlayables = emptyMap();
+
+    @Nullable
+    @DataClass.ParcelWith(ForInternedString.class)
+    private String staticSharedLibName;
+    private long staticSharedLibVersion;
+    @NonNull
+    @DataClass.ParcelWith(ForInternedStringList.class)
+    private List<String> libraryNames = emptyList();
+    @NonNull
+    @DataClass.ParcelWith(ForInternedStringList.class)
+    protected List<String> usesLibraries = emptyList();
+    @NonNull
+    @DataClass.ParcelWith(ForInternedStringList.class)
+    protected List<String> usesOptionalLibraries = emptyList();
+
+    @NonNull
+    @DataClass.ParcelWith(ForInternedStringList.class)
+    private List<String> usesStaticLibraries = emptyList();
+    @Nullable
+    private long[] usesStaticLibrariesVersions;
+
+    @Nullable
+    private String[][] usesStaticLibrariesCertDigests;
+
+    @Nullable
+    @DataClass.ParcelWith(ForInternedString.class)
+    private String sharedUserId;
+
+    private int sharedUserLabel;
+    @NonNull
+    private List<ConfigurationInfo> configPreferences = emptyList();
+    @NonNull
+    private List<FeatureInfo> reqFeatures = emptyList();
+    @NonNull
+    private List<FeatureGroupInfo> featureGroups = emptyList();
+
+    @Nullable
+    private byte[] restrictUpdateHash;
+
+    @NonNull
+    @DataClass.ParcelWith(ForInternedStringList.class)
+    protected List<String> originalPackages = emptyList();
+    @NonNull
+    @DataClass.ParcelWith(ForInternedStringList.class)
+    protected List<String> adoptPermissions = emptyList();
+
+    @NonNull
+    @DataClass.ParcelWith(ForInternedStringList.class)
+    private List<String> requestedPermissions = emptyList();
+    @NonNull
+    @DataClass.ParcelWith(ForInternedStringList.class)
+    private List<String> implicitPermissions = emptyList();
+
+    @NonNull
+    private Set<String> upgradeKeySets = emptySet();
+    @NonNull
+    private Map<String, ArraySet<PublicKey>> keySetMapping = emptyMap();
+
+    @NonNull
+    @DataClass.ParcelWith(ForInternedStringList.class)
+    protected List<String> protectedBroadcasts = emptyList();
+
+    @NonNull
+    protected List<ParsedActivity> activities = emptyList();
+
+    @NonNull
+    protected List<ParsedActivity> receivers = emptyList();
+
+    @NonNull
+    protected List<ParsedService> services = emptyList();
+
+    @NonNull
+    protected List<ParsedProvider> providers = emptyList();
+
+    @NonNull
+    private List<ParsedFeature> features = emptyList();
+
+    @NonNull
+    protected List<ParsedPermission> permissions = emptyList();
+
+    @NonNull
+    protected List<ParsedPermissionGroup> permissionGroups = emptyList();
+
+    @NonNull
+    protected List<ParsedInstrumentation> instrumentations = emptyList();
+
+    @NonNull
+    @DataClass.ParcelWith(ParsedIntentInfo.ListParceler.class)
+    private List<Pair<String, ParsedIntentInfo>> preferredActivityFilters = emptyList();
+
+    @NonNull
+    private Map<String, ParsedProcess> processes = emptyMap();
+
+    @Nullable
+    private Bundle metaData;
+
+    @Nullable
+    @DataClass.ParcelWith(ForInternedString.class)
+    protected String volumeUuid;
+    @Nullable
+    private PackageParser.SigningDetails signingDetails;
+
+    @NonNull
+    @DataClass.ParcelWith(ForInternedString.class)
+    protected String codePath;
+
+    private boolean use32BitAbi;
+    private boolean visibleToInstantApps;
+
+    private boolean forceQueryable;
+
+    @NonNull
+    @DataClass.ParcelWith(ForInternedStringList.class)
+    private List<Intent> queriesIntents = emptyList();
+
+    @NonNull
+    @DataClass.ParcelWith(ForInternedStringList.class)
+    private List<String> queriesPackages = emptyList();
+
+    @NonNull
+    @DataClass.ParcelWith(ForInternedStringSet.class)
+    private Set<String> queriesProviders = emptySet();
+
+    @Nullable
+    @DataClass.ParcelWith(ForInternedStringArray.class)
+    private String[] splitClassLoaderNames;
+    @Nullable
+    protected String[] splitCodePaths;
+    @Nullable
+    private SparseArray<int[]> splitDependencies;
+    @Nullable
+    private int[] splitFlags;
+    @Nullable
+    @DataClass.ParcelWith(ForInternedStringArray.class)
+    private String[] splitNames;
+    @Nullable
+    private int[] splitRevisionCodes;
+
+    @Nullable
+    @DataClass.ParcelWith(ForInternedString.class)
+    private String appComponentFactory;
+    @Nullable
+    @DataClass.ParcelWith(ForInternedString.class)
+    private String backupAgentName;
+    private int banner;
+    private int category;
+    @Nullable
+    @DataClass.ParcelWith(ForInternedString.class)
+    private String classLoaderName;
+    @Nullable
+    @DataClass.ParcelWith(ForInternedString.class)
+    private String className;
+    private int compatibleWidthLimitDp;
+    private int descriptionRes;
+    private boolean enabled;
+    private boolean crossProfile;
+    private int fullBackupContent;
+    private int iconRes;
+    private int installLocation = PackageParser.PARSE_DEFAULT_INSTALL_LOCATION;
+    private int labelRes;
+    private int largestWidthLimitDp;
+    private int logo;
+    @Nullable
+    @DataClass.ParcelWith(ForInternedString.class)
+    private String manageSpaceActivityName;
+    private float maxAspectRatio;
+    private float minAspectRatio;
+    private int minSdkVersion;
+    private int networkSecurityConfigRes;
+    @Nullable
+    private CharSequence nonLocalizedLabel;
+    @Nullable
+    @DataClass.ParcelWith(ForInternedString.class)
+    private String permission;
+    @Nullable
+    @DataClass.ParcelWith(ForInternedString.class)
+    private String processName;
+    private int requiresSmallestWidthDp;
+    private int roundIconRes;
+    private int targetSandboxVersion;
+    private int targetSdkVersion;
+    @Nullable
+    @DataClass.ParcelWith(ForInternedString.class)
+    private String taskAffinity;
+    private int theme;
+
+    private int uiOptions;
+    @Nullable
+    @DataClass.ParcelWith(ForInternedString.class)
+    private String zygotePreloadName;
+
+    private boolean externalStorage;
+    private boolean baseHardwareAccelerated;
+    private boolean allowBackup;
+    private boolean killAfterRestore;
+    private boolean restoreAnyVersion;
+    private boolean fullBackupOnly;
+    private boolean persistent;
+    private boolean debuggable;
+    private boolean vmSafeMode;
+    private boolean hasCode;
+    private boolean allowTaskReparenting;
+    private boolean allowClearUserData;
+    private boolean largeHeap;
+    private boolean usesCleartextTraffic;
+    private boolean supportsRtl;
+    private boolean testOnly;
+    private boolean multiArch;
+    private boolean extractNativeLibs;
+    private boolean game;
+
+    /**
+     * @see ParsingPackageRead#getResizeableActivity()
+     */
+    @Nullable
+    @DataClass.ParcelWith(ForBoolean.class)
+    private Boolean resizeableActivity;
+
+    private boolean staticSharedLibrary;
+    private boolean overlay;
+    private boolean isolatedSplitLoading;
+    private boolean hasDomainUrls;
+    private boolean profileableByShell;
+    private boolean backupInForeground;
+    private boolean useEmbeddedDex;
+    private boolean defaultToDeviceProtectedStorage;
+    private boolean directBootAware;
+    private boolean partiallyDirectBootAware;
+    private boolean resizeableActivityViaSdkVersion;
+    private boolean allowClearUserDataOnFailedRestore;
+    private boolean allowAudioPlaybackCapture;
+    private boolean requestLegacyExternalStorage;
+    private boolean usesNonSdkApi;
+    private boolean hasFragileUserData;
+    private boolean cantSaveState;
+    private boolean allowNativeHeapPointerTagging;
+    private boolean preserveLegacyExternalStorage;
+
+    // TODO(chiuwinson): Non-null
+    @Nullable
+    private ArraySet<String> mimeGroups;
+
+    @VisibleForTesting
+    public ParsingPackageImpl(@NonNull String packageName, @NonNull String baseCodePath,
+            @NonNull String codePath, @Nullable TypedArray manifestArray) {
+        this.packageName = TextUtils.safeIntern(packageName);
+        this.baseCodePath = TextUtils.safeIntern(baseCodePath);
+        this.codePath = TextUtils.safeIntern(codePath);
+
+        if (manifestArray != null) {
+            versionCode = manifestArray.getInteger(R.styleable.AndroidManifest_versionCode, 0);
+            versionCodeMajor = manifestArray.getInteger(
+                    R.styleable.AndroidManifest_versionCodeMajor, 0);
+            setBaseRevisionCode(
+                    manifestArray.getInteger(R.styleable.AndroidManifest_revisionCode, 0));
+            setVersionName(manifestArray.getNonConfigurationString(
+                    R.styleable.AndroidManifest_versionName, 0));
+
+            setCompileSdkVersion(manifestArray.getInteger(
+                    R.styleable.AndroidManifest_compileSdkVersion, 0));
+            setCompileSdkVersionCodename(manifestArray.getNonConfigurationString(
+                    R.styleable.AndroidManifest_compileSdkVersionCodename, 0));
+        }
+    }
+
+    public boolean isSupportsSmallScreens() {
+        if (supportsSmallScreens == null) {
+            return targetSdkVersion >= Build.VERSION_CODES.DONUT;
+        }
+
+        return supportsSmallScreens;
+    }
+
+    public boolean isSupportsNormalScreens() {
+        return supportsNormalScreens == null || supportsNormalScreens;
+    }
+
+    public boolean isSupportsLargeScreens() {
+        if (supportsLargeScreens == null) {
+            return targetSdkVersion >= Build.VERSION_CODES.DONUT;
+        }
+
+        return supportsLargeScreens;
+    }
+
+    public boolean isSupportsExtraLargeScreens() {
+        if (supportsExtraLargeScreens == null) {
+            return targetSdkVersion >= Build.VERSION_CODES.GINGERBREAD;
+        }
+
+        return supportsExtraLargeScreens;
+    }
+
+    public boolean isResizeable() {
+        if (resizeable == null) {
+            return targetSdkVersion >= Build.VERSION_CODES.DONUT;
+        }
+
+        return resizeable;
+    }
+
+    public boolean isAnyDensity() {
+        if (anyDensity == null) {
+            return targetSdkVersion >= Build.VERSION_CODES.DONUT;
+        }
+
+        return anyDensity;
+    }
+
+    @Override
+    public ParsingPackageImpl sortActivities() {
+        Collections.sort(this.activities, ORDER_COMPARATOR);
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl sortReceivers() {
+        Collections.sort(this.receivers, ORDER_COMPARATOR);
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl sortServices() {
+        Collections.sort(this.services, ORDER_COMPARATOR);
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setVersionName(String versionName) {
+        this.versionName = TextUtils.safeIntern(versionName);
+        return this;
+    }
+
+    @Override
+    public ParsingPackage setCompileSdkVersionCodename(String compileSdkVersionCodename) {
+        this.compileSdkVersionCodeName = TextUtils.safeIntern(compileSdkVersionCodename);
+        return this;
+    }
+
+    @Override
+    public Object hideAsParsed() {
+        // There is no equivalent for core-only parsing
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ParsingPackageImpl addConfigPreference(ConfigurationInfo configPreference) {
+        this.configPreferences = CollectionUtils.add(this.configPreferences, configPreference);
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl addReqFeature(FeatureInfo reqFeature) {
+        this.reqFeatures = CollectionUtils.add(this.reqFeatures, reqFeature);
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl addFeatureGroup(FeatureGroupInfo featureGroup) {
+        this.featureGroups = CollectionUtils.add(this.featureGroups, featureGroup);
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl addProtectedBroadcast(String protectedBroadcast) {
+        if (!this.protectedBroadcasts.contains(protectedBroadcast)) {
+            this.protectedBroadcasts = CollectionUtils.add(this.protectedBroadcasts,
+                    TextUtils.safeIntern(protectedBroadcast));
+        }
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl addInstrumentation(ParsedInstrumentation instrumentation) {
+        this.instrumentations = CollectionUtils.add(this.instrumentations, instrumentation);
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl addOriginalPackage(String originalPackage) {
+        this.originalPackages = CollectionUtils.add(this.originalPackages,
+                TextUtils.safeIntern(originalPackage));
+        return this;
+    }
+
+    @Override
+    public ParsingPackage addOverlayable(String overlayableName, String actorName) {
+        this.overlayables = CollectionUtils.add(this.overlayables,
+                TextUtils.safeIntern(overlayableName), TextUtils.safeIntern(actorName));
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl addAdoptPermission(String adoptPermission) {
+        this.adoptPermissions = CollectionUtils.add(this.adoptPermissions,
+                TextUtils.safeIntern(adoptPermission));
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl addPermission(ParsedPermission permission) {
+        this.permissions = CollectionUtils.add(this.permissions, permission);
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl addPermissionGroup(ParsedPermissionGroup permissionGroup) {
+        this.permissionGroups = CollectionUtils.add(this.permissionGroups, permissionGroup);
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl addRequestedPermission(String permission) {
+        this.requestedPermissions = CollectionUtils.add(this.requestedPermissions,
+                TextUtils.safeIntern(permission));
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl addImplicitPermission(String permission) {
+        this.implicitPermissions = CollectionUtils.add(this.implicitPermissions,
+                TextUtils.safeIntern(permission));
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl addKeySet(String keySetName, PublicKey publicKey) {
+        ArraySet<PublicKey> publicKeys = keySetMapping.get(keySetName);
+        if (publicKeys == null) {
+            publicKeys = new ArraySet<>();
+        }
+        publicKeys.add(publicKey);
+        keySetMapping = CollectionUtils.add(this.keySetMapping, keySetName, publicKeys);
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl addActivity(ParsedActivity parsedActivity) {
+        this.activities = CollectionUtils.add(this.activities, parsedActivity);
+        addMimeGroupsFromComponent(parsedActivity);
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl addReceiver(ParsedActivity parsedReceiver) {
+        this.receivers = CollectionUtils.add(this.receivers, parsedReceiver);
+        addMimeGroupsFromComponent(parsedReceiver);
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl addService(ParsedService parsedService) {
+        this.services = CollectionUtils.add(this.services, parsedService);
+        addMimeGroupsFromComponent(parsedService);
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl addProvider(ParsedProvider parsedProvider) {
+        this.providers = CollectionUtils.add(this.providers, parsedProvider);
+        addMimeGroupsFromComponent(parsedProvider);
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl addFeature(ParsedFeature feature) {
+        this.features = CollectionUtils.add(this.features, feature);
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl addLibraryName(String libraryName) {
+        this.libraryNames = CollectionUtils.add(this.libraryNames,
+                TextUtils.safeIntern(libraryName));
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl addUsesOptionalLibrary(String libraryName) {
+        this.usesOptionalLibraries = CollectionUtils.add(this.usesOptionalLibraries,
+                TextUtils.safeIntern(libraryName));
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl addUsesLibrary(String libraryName) {
+        this.usesLibraries = CollectionUtils.add(this.usesLibraries,
+                TextUtils.safeIntern(libraryName));
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl removeUsesOptionalLibrary(String libraryName) {
+        this.usesOptionalLibraries = CollectionUtils.remove(this.usesOptionalLibraries,
+                libraryName);
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl addUsesStaticLibrary(String libraryName) {
+        this.usesStaticLibraries = CollectionUtils.add(this.usesStaticLibraries,
+                TextUtils.safeIntern(libraryName));
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl addUsesStaticLibraryVersion(long version) {
+        this.usesStaticLibrariesVersions = ArrayUtils.appendLong(this.usesStaticLibrariesVersions,
+                version, true);
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl addUsesStaticLibraryCertDigests(String[] certSha256Digests) {
+        this.usesStaticLibrariesCertDigests = ArrayUtils.appendElement(String[].class,
+                this.usesStaticLibrariesCertDigests, certSha256Digests, true);
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl addPreferredActivityFilter(String className,
+            ParsedIntentInfo intentInfo) {
+        this.preferredActivityFilters = CollectionUtils.add(this.preferredActivityFilters,
+                Pair.create(className, intentInfo));
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl addQueriesIntent(Intent intent) {
+        this.queriesIntents = CollectionUtils.add(this.queriesIntents, intent);
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl addQueriesPackage(String packageName) {
+        this.queriesPackages = CollectionUtils.add(this.queriesPackages,
+                TextUtils.safeIntern(packageName));
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl addQueriesProvider(String authority) {
+        this.queriesProviders = CollectionUtils.add(this.queriesProviders,
+                TextUtils.safeIntern(authority));
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setSupportsSmallScreens(int supportsSmallScreens) {
+        if (supportsSmallScreens == 1) {
+            return this;
+        }
+
+        this.supportsSmallScreens = supportsSmallScreens < 0;
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setSupportsNormalScreens(int supportsNormalScreens) {
+        if (supportsNormalScreens == 1) {
+            return this;
+        }
+
+        this.supportsNormalScreens = supportsNormalScreens < 0;
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setSupportsLargeScreens(int supportsLargeScreens) {
+        if (supportsLargeScreens == 1) {
+            return this;
+        }
+
+        this.supportsLargeScreens = supportsLargeScreens < 0;
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setSupportsExtraLargeScreens(int supportsExtraLargeScreens) {
+        if (supportsExtraLargeScreens == 1) {
+            return this;
+        }
+
+        this.supportsExtraLargeScreens = supportsExtraLargeScreens < 0;
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setResizeable(int resizeable) {
+        if (resizeable == 1) {
+            return this;
+        }
+
+        this.resizeable = resizeable < 0;
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setAnyDensity(int anyDensity) {
+        if (anyDensity == 1) {
+            return this;
+        }
+
+        this.anyDensity = anyDensity < 0;
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl asSplit(
+            String[] splitNames,
+            String[] splitCodePaths,
+            int[] splitRevisionCodes,
+            SparseArray<int[]> splitDependencies
+    ) {
+        this.splitNames = splitNames;
+
+        if (this.splitNames != null) {
+            for (int index = 0; index < this.splitNames.length; index++) {
+                splitNames[index] = TextUtils.safeIntern(splitNames[index]);
+            }
+        }
+
+        this.splitCodePaths = splitCodePaths;
+        this.splitRevisionCodes = splitRevisionCodes;
+        this.splitDependencies = splitDependencies;
+
+        int count = splitNames.length;
+        this.splitFlags = new int[count];
+        this.splitClassLoaderNames = new String[count];
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setSplitHasCode(int splitIndex, boolean splitHasCode) {
+        this.splitFlags[splitIndex] = splitHasCode
+                ? this.splitFlags[splitIndex] | ApplicationInfo.FLAG_HAS_CODE
+                : this.splitFlags[splitIndex] & ~ApplicationInfo.FLAG_HAS_CODE;
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setSplitClassLoaderName(int splitIndex, String classLoaderName) {
+        this.splitClassLoaderNames[splitIndex] = classLoaderName;
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setProcessName(String processName) {
+        this.processName = TextUtils.safeIntern(processName);
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setRealPackage(@Nullable String realPackage) {
+        this.realPackage = TextUtils.safeIntern(realPackage);
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setRestrictedAccountType(@Nullable String restrictedAccountType) {
+        this.restrictedAccountType = TextUtils.safeIntern(restrictedAccountType);
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setRequiredAccountType(@Nullable String requiredAccountType) {
+        this.requiredAccountType = TextUtils.nullIfEmpty(TextUtils.safeIntern(requiredAccountType));
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setOverlayTarget(@Nullable String overlayTarget) {
+        this.overlayTarget = TextUtils.safeIntern(overlayTarget);
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setOverlayTargetName(@Nullable String overlayTargetName) {
+        this.overlayTargetName = TextUtils.safeIntern(overlayTargetName);
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setOverlayCategory(@Nullable String overlayCategory) {
+        this.overlayCategory = TextUtils.safeIntern(overlayCategory);
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setVolumeUuid(@Nullable String volumeUuid) {
+        this.volumeUuid = TextUtils.safeIntern(volumeUuid);
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setAppComponentFactory(@Nullable String appComponentFactory) {
+        this.appComponentFactory = TextUtils.safeIntern(appComponentFactory);
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setBackupAgentName(@Nullable String backupAgentName) {
+        this.backupAgentName = TextUtils.safeIntern(backupAgentName);
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setClassLoaderName(@Nullable String classLoaderName) {
+        this.classLoaderName = TextUtils.safeIntern(classLoaderName);
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setClassName(@Nullable String className) {
+        this.className = TextUtils.safeIntern(className);
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setManageSpaceActivityName(@Nullable String manageSpaceActivityName) {
+        this.manageSpaceActivityName = TextUtils.safeIntern(manageSpaceActivityName);
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setPermission(@Nullable String permission) {
+        this.permission = TextUtils.safeIntern(permission);
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setTaskAffinity(@Nullable String taskAffinity) {
+        this.taskAffinity = TextUtils.safeIntern(taskAffinity);
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setZygotePreloadName(@Nullable String zygotePreloadName) {
+        this.zygotePreloadName = TextUtils.safeIntern(zygotePreloadName);
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setStaticSharedLibName(String staticSharedLibName) {
+        this.staticSharedLibName = TextUtils.safeIntern(staticSharedLibName);
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setSharedUserId(String sharedUserId) {
+        this.sharedUserId = TextUtils.safeIntern(sharedUserId);
+        return this;
+    }
+
+    @NonNull
+    @Override
+    public String getProcessName() {
+        return processName != null ? processName : packageName;
+    }
+
+    @Override
+    public String toString() {
+        return "Package{"
+                + Integer.toHexString(System.identityHashCode(this))
+                + " " + packageName + "}";
+    }
+
+    @Deprecated
+    @Override
+    public ApplicationInfo toAppInfoWithoutState() {
+        ApplicationInfo appInfo = new ApplicationInfo();
+        appInfo.flags = PackageInfoWithoutStateUtils.appInfoFlags(this);
+        appInfo.privateFlags = PackageInfoWithoutStateUtils.appInfoPrivateFlags(this);
+
+        appInfo.appComponentFactory = appComponentFactory;
+        appInfo.backupAgentName = backupAgentName;
+        appInfo.banner = banner;
+        appInfo.category = category;
+        appInfo.classLoaderName = classLoaderName;
+        appInfo.className = className;
+        appInfo.compatibleWidthLimitDp = compatibleWidthLimitDp;
+        appInfo.compileSdkVersion = compileSdkVersion;
+        appInfo.compileSdkVersionCodename = compileSdkVersionCodeName;
+//        appInfo.credentialProtectedDataDir = credentialProtectedDataDir;
+//        appInfo.dataDir = dataDir;
+        appInfo.descriptionRes = descriptionRes;
+//        appInfo.deviceProtectedDataDir = deviceProtectedDataDir;
+        appInfo.enabled = enabled;
+        appInfo.fullBackupContent = fullBackupContent;
+//        appInfo.hiddenUntilInstalled = hiddenUntilInstalled;
+        appInfo.icon = (PackageParser.sUseRoundIcon && roundIconRes != 0) ? roundIconRes : iconRes;
+        appInfo.iconRes = iconRes;
+        appInfo.roundIconRes = roundIconRes;
+        appInfo.installLocation = installLocation;
+        appInfo.labelRes = labelRes;
+        appInfo.largestWidthLimitDp = largestWidthLimitDp;
+        appInfo.logo = logo;
+        appInfo.manageSpaceActivityName = manageSpaceActivityName;
+        appInfo.maxAspectRatio = maxAspectRatio;
+        appInfo.metaData = metaData;
+        appInfo.minAspectRatio = minAspectRatio;
+        appInfo.minSdkVersion = minSdkVersion;
+        appInfo.name = className;
+        if (appInfo.name != null) {
+            appInfo.name = appInfo.name.trim();
+        }
+//        appInfo.nativeLibraryDir = nativeLibraryDir;
+//        appInfo.nativeLibraryRootDir = nativeLibraryRootDir;
+//        appInfo.nativeLibraryRootRequiresIsa = nativeLibraryRootRequiresIsa;
+        appInfo.networkSecurityConfigRes = networkSecurityConfigRes;
+        appInfo.nonLocalizedLabel = nonLocalizedLabel;
+        if (appInfo.nonLocalizedLabel != null) {
+            appInfo.nonLocalizedLabel = appInfo.nonLocalizedLabel.toString().trim();
+        }
+        appInfo.packageName = packageName;
+        appInfo.permission = permission;
+//        appInfo.primaryCpuAbi = primaryCpuAbi;
+        appInfo.processName = getProcessName();
+        appInfo.requiresSmallestWidthDp = requiresSmallestWidthDp;
+//        appInfo.secondaryCpuAbi = secondaryCpuAbi;
+//        appInfo.secondaryNativeLibraryDir = secondaryNativeLibraryDir;
+//        appInfo.seInfo = seInfo;
+//        appInfo.seInfoUser = seInfoUser;
+//        appInfo.sharedLibraryFiles = usesLibraryFiles.isEmpty()
+//                ? null : usesLibraryFiles.toArray(new String[0]);
+//        appInfo.sharedLibraryInfos = usesLibraryInfos.isEmpty() ? null : usesLibraryInfos;
+        appInfo.splitClassLoaderNames = splitClassLoaderNames;
+        appInfo.splitDependencies = splitDependencies;
+        appInfo.splitNames = splitNames;
+        appInfo.storageUuid = StorageManager.convert(volumeUuid);
+        appInfo.targetSandboxVersion = targetSandboxVersion;
+        appInfo.targetSdkVersion = targetSdkVersion;
+        appInfo.taskAffinity = taskAffinity;
+        appInfo.theme = theme;
+//        appInfo.uid = uid;
+        appInfo.uiOptions = uiOptions;
+        appInfo.volumeUuid = volumeUuid;
+        appInfo.zygotePreloadName = zygotePreloadName;
+        appInfo.crossProfile = isCrossProfile();
+
+        appInfo.setBaseCodePath(baseCodePath);
+        appInfo.setBaseResourcePath(baseCodePath);
+        appInfo.setCodePath(codePath);
+        appInfo.setResourcePath(codePath);
+        appInfo.setSplitCodePaths(splitCodePaths);
+        appInfo.setSplitResourcePaths(splitCodePaths);
+        appInfo.setVersionCode(PackageInfo.composeLongVersionCode(versionCodeMajor, versionCode));
+
+        // TODO(b/135203078): Can this be removed? Looks only used in ActivityInfo.
+//        appInfo.showUserIcon = pkg.getShowUserIcon();
+        // TODO(b/135203078): Unused?
+//        appInfo.resourceDirs = pkg.getResourceDirs();
+        // TODO(b/135203078): Unused?
+//        appInfo.enabledSetting = pkg.getEnabledSetting();
+        // TODO(b/135203078): See ParsingPackageImpl#getHiddenApiEnforcementPolicy
+//        appInfo.mHiddenApiPolicy = pkg.getHiddenApiPolicy();
+
+        return appInfo;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        sForBoolean.parcel(this.supportsSmallScreens, dest, flags);
+        sForBoolean.parcel(this.supportsNormalScreens, dest, flags);
+        sForBoolean.parcel(this.supportsLargeScreens, dest, flags);
+        sForBoolean.parcel(this.supportsExtraLargeScreens, dest, flags);
+        sForBoolean.parcel(this.resizeable, dest, flags);
+        sForBoolean.parcel(this.anyDensity, dest, flags);
+        dest.writeInt(this.versionCode);
+        dest.writeInt(this.versionCodeMajor);
+        dest.writeInt(this.baseRevisionCode);
+        sForString.parcel(this.versionName, dest, flags);
+        dest.writeInt(this.compileSdkVersion);
+        sForString.parcel(this.compileSdkVersionCodeName, dest, flags);
+        sForString.parcel(this.packageName, dest, flags);
+        sForString.parcel(this.realPackage, dest, flags);
+        sForString.parcel(this.baseCodePath, dest, flags);
+        dest.writeBoolean(this.requiredForAllUsers);
+        sForString.parcel(this.restrictedAccountType, dest, flags);
+        sForString.parcel(this.requiredAccountType, dest, flags);
+        sForString.parcel(this.overlayTarget, dest, flags);
+        sForString.parcel(this.overlayTargetName, dest, flags);
+        sForString.parcel(this.overlayCategory, dest, flags);
+        dest.writeInt(this.overlayPriority);
+        dest.writeBoolean(this.overlayIsStatic);
+        sForStringValueMap.parcel(this.overlayables, dest, flags);
+        sForString.parcel(this.staticSharedLibName, dest, flags);
+        dest.writeLong(this.staticSharedLibVersion);
+        sForStringList.parcel(this.libraryNames, dest, flags);
+        sForStringList.parcel(this.usesLibraries, dest, flags);
+        sForStringList.parcel(this.usesOptionalLibraries, dest, flags);
+        sForStringList.parcel(this.usesStaticLibraries, dest, flags);
+        dest.writeLongArray(this.usesStaticLibrariesVersions);
+
+        if (this.usesStaticLibrariesCertDigests == null) {
+            dest.writeInt(-1);
+        } else {
+            dest.writeInt(this.usesStaticLibrariesCertDigests.length);
+            for (int index = 0; index < this.usesStaticLibrariesCertDigests.length; index++) {
+                sForStringArray.parcel(this.usesStaticLibrariesCertDigests[index], dest, flags);
+            }
+        }
+
+        sForString.parcel(this.sharedUserId, dest, flags);
+        dest.writeInt(this.sharedUserLabel);
+        dest.writeTypedList(this.configPreferences);
+        dest.writeTypedList(this.reqFeatures);
+        dest.writeTypedList(this.featureGroups);
+        dest.writeByteArray(this.restrictUpdateHash);
+        sForStringList.parcel(this.originalPackages, dest, flags);
+        sForStringList.parcel(this.adoptPermissions, dest, flags);
+        sForStringList.parcel(this.requestedPermissions, dest, flags);
+        sForStringList.parcel(this.implicitPermissions, dest, flags);
+        sForStringSet.parcel(this.upgradeKeySets, dest, flags);
+        dest.writeMap(this.keySetMapping);
+        sForStringList.parcel(this.protectedBroadcasts, dest, flags);
+        dest.writeTypedList(this.activities);
+        dest.writeTypedList(this.receivers);
+        dest.writeTypedList(this.services);
+        dest.writeTypedList(this.providers);
+        dest.writeTypedList(this.features);
+        dest.writeTypedList(this.permissions);
+        dest.writeTypedList(this.permissionGroups);
+        dest.writeTypedList(this.instrumentations);
+        sForIntentInfoPairs.parcel(this.preferredActivityFilters, dest, flags);
+        dest.writeMap(this.processes);
+        dest.writeBundle(this.metaData);
+        sForString.parcel(this.volumeUuid, dest, flags);
+        dest.writeParcelable(this.signingDetails, flags);
+        sForString.parcel(this.codePath, dest, flags);
+        dest.writeBoolean(this.use32BitAbi);
+        dest.writeBoolean(this.visibleToInstantApps);
+        dest.writeBoolean(this.forceQueryable);
+        dest.writeParcelableList(this.queriesIntents, flags);
+        sForStringList.parcel(this.queriesPackages, dest, flags);
+        sForString.parcel(this.appComponentFactory, dest, flags);
+        sForString.parcel(this.backupAgentName, dest, flags);
+        dest.writeInt(this.banner);
+        dest.writeInt(this.category);
+        sForString.parcel(this.classLoaderName, dest, flags);
+        sForString.parcel(this.className, dest, flags);
+        dest.writeInt(this.compatibleWidthLimitDp);
+        dest.writeInt(this.descriptionRes);
+        dest.writeBoolean(this.enabled);
+        dest.writeBoolean(this.crossProfile);
+        dest.writeInt(this.fullBackupContent);
+        dest.writeInt(this.iconRes);
+        dest.writeInt(this.installLocation);
+        dest.writeInt(this.labelRes);
+        dest.writeInt(this.largestWidthLimitDp);
+        dest.writeInt(this.logo);
+        sForString.parcel(this.manageSpaceActivityName, dest, flags);
+        dest.writeFloat(this.maxAspectRatio);
+        dest.writeFloat(this.minAspectRatio);
+        dest.writeInt(this.minSdkVersion);
+        dest.writeInt(this.networkSecurityConfigRes);
+        dest.writeCharSequence(this.nonLocalizedLabel);
+        sForString.parcel(this.permission, dest, flags);
+        sForString.parcel(this.processName, dest, flags);
+        dest.writeInt(this.requiresSmallestWidthDp);
+        dest.writeInt(this.roundIconRes);
+        dest.writeInt(this.targetSandboxVersion);
+        dest.writeInt(this.targetSdkVersion);
+        sForString.parcel(this.taskAffinity, dest, flags);
+        dest.writeInt(this.theme);
+        dest.writeInt(this.uiOptions);
+        sForString.parcel(this.zygotePreloadName, dest, flags);
+        sForStringArray.parcel(this.splitClassLoaderNames, dest, flags);
+        sForStringArray.parcel(this.splitCodePaths, dest, flags);
+        dest.writeSparseArray(this.splitDependencies);
+        dest.writeIntArray(this.splitFlags);
+        sForStringArray.parcel(this.splitNames, dest, flags);
+        dest.writeIntArray(this.splitRevisionCodes);
+
+        dest.writeBoolean(this.externalStorage);
+        dest.writeBoolean(this.baseHardwareAccelerated);
+        dest.writeBoolean(this.allowBackup);
+        dest.writeBoolean(this.killAfterRestore);
+        dest.writeBoolean(this.restoreAnyVersion);
+        dest.writeBoolean(this.fullBackupOnly);
+        dest.writeBoolean(this.persistent);
+        dest.writeBoolean(this.debuggable);
+        dest.writeBoolean(this.vmSafeMode);
+        dest.writeBoolean(this.hasCode);
+        dest.writeBoolean(this.allowTaskReparenting);
+        dest.writeBoolean(this.allowClearUserData);
+        dest.writeBoolean(this.largeHeap);
+        dest.writeBoolean(this.usesCleartextTraffic);
+        dest.writeBoolean(this.supportsRtl);
+        dest.writeBoolean(this.testOnly);
+        dest.writeBoolean(this.multiArch);
+        dest.writeBoolean(this.extractNativeLibs);
+        dest.writeBoolean(this.game);
+
+        sForBoolean.parcel(this.resizeableActivity, dest, flags);
+
+        dest.writeBoolean(this.staticSharedLibrary);
+        dest.writeBoolean(this.overlay);
+        dest.writeBoolean(this.isolatedSplitLoading);
+        dest.writeBoolean(this.hasDomainUrls);
+        dest.writeBoolean(this.profileableByShell);
+        dest.writeBoolean(this.backupInForeground);
+        dest.writeBoolean(this.useEmbeddedDex);
+        dest.writeBoolean(this.defaultToDeviceProtectedStorage);
+        dest.writeBoolean(this.directBootAware);
+        dest.writeBoolean(this.partiallyDirectBootAware);
+        dest.writeBoolean(this.resizeableActivityViaSdkVersion);
+        dest.writeBoolean(this.allowClearUserDataOnFailedRestore);
+        dest.writeBoolean(this.allowAudioPlaybackCapture);
+        dest.writeBoolean(this.requestLegacyExternalStorage);
+        dest.writeBoolean(this.usesNonSdkApi);
+        dest.writeBoolean(this.hasFragileUserData);
+        dest.writeBoolean(this.cantSaveState);
+        dest.writeBoolean(this.allowNativeHeapPointerTagging);
+        dest.writeBoolean(this.preserveLegacyExternalStorage);
+        dest.writeArraySet(this.mimeGroups);
+    }
+
+    public ParsingPackageImpl(Parcel in) {
+        // We use the boot classloader for all classes that we load.
+        final ClassLoader boot = Object.class.getClassLoader();
+        this.supportsSmallScreens = sForBoolean.unparcel(in);
+        this.supportsNormalScreens = sForBoolean.unparcel(in);
+        this.supportsLargeScreens = sForBoolean.unparcel(in);
+        this.supportsExtraLargeScreens = sForBoolean.unparcel(in);
+        this.resizeable = sForBoolean.unparcel(in);
+        this.anyDensity = sForBoolean.unparcel(in);
+        this.versionCode = in.readInt();
+        this.versionCodeMajor = in.readInt();
+        this.baseRevisionCode = in.readInt();
+        this.versionName = sForString.unparcel(in);
+        this.compileSdkVersion = in.readInt();
+        this.compileSdkVersionCodeName = sForString.unparcel(in);
+        this.packageName = sForString.unparcel(in);
+        this.realPackage = sForString.unparcel(in);
+        this.baseCodePath = sForString.unparcel(in);
+        this.requiredForAllUsers = in.readBoolean();
+        this.restrictedAccountType = sForString.unparcel(in);
+        this.requiredAccountType = sForString.unparcel(in);
+        this.overlayTarget = sForString.unparcel(in);
+        this.overlayTargetName = sForString.unparcel(in);
+        this.overlayCategory = sForString.unparcel(in);
+        this.overlayPriority = in.readInt();
+        this.overlayIsStatic = in.readBoolean();
+        this.overlayables = sForStringValueMap.unparcel(in);
+        this.staticSharedLibName = sForString.unparcel(in);
+        this.staticSharedLibVersion = in.readLong();
+        this.libraryNames = sForStringList.unparcel(in);
+        this.usesLibraries = sForStringList.unparcel(in);
+        this.usesOptionalLibraries = sForStringList.unparcel(in);
+        this.usesStaticLibraries = sForStringList.unparcel(in);
+        this.usesStaticLibrariesVersions = in.createLongArray();
+
+        int digestsSize = in.readInt();
+        if (digestsSize >= 0) {
+            this.usesStaticLibrariesCertDigests = new String[digestsSize][];
+            for (int index = 0; index < digestsSize; index++) {
+                this.usesStaticLibrariesCertDigests[index] = sForStringArray.unparcel(in);
+            }
+        }
+
+        this.sharedUserId = sForString.unparcel(in);
+        this.sharedUserLabel = in.readInt();
+        this.configPreferences = in.createTypedArrayList(ConfigurationInfo.CREATOR);
+        this.reqFeatures = in.createTypedArrayList(FeatureInfo.CREATOR);
+        this.featureGroups = in.createTypedArrayList(FeatureGroupInfo.CREATOR);
+        this.restrictUpdateHash = in.createByteArray();
+        this.originalPackages = sForStringList.unparcel(in);
+        this.adoptPermissions = sForStringList.unparcel(in);
+        this.requestedPermissions = sForStringList.unparcel(in);
+        this.implicitPermissions = sForStringList.unparcel(in);
+        this.upgradeKeySets = sForStringSet.unparcel(in);
+        this.keySetMapping = in.readHashMap(boot);
+        this.protectedBroadcasts = sForStringList.unparcel(in);
+        this.activities = in.createTypedArrayList(ParsedActivity.CREATOR);
+        this.receivers = in.createTypedArrayList(ParsedActivity.CREATOR);
+        this.services = in.createTypedArrayList(ParsedService.CREATOR);
+        this.providers = in.createTypedArrayList(ParsedProvider.CREATOR);
+        this.features = in.createTypedArrayList(ParsedFeature.CREATOR);
+        this.permissions = in.createTypedArrayList(ParsedPermission.CREATOR);
+        this.permissionGroups = in.createTypedArrayList(ParsedPermissionGroup.CREATOR);
+        this.instrumentations = in.createTypedArrayList(ParsedInstrumentation.CREATOR);
+        this.preferredActivityFilters = sForIntentInfoPairs.unparcel(in);
+        this.processes = in.readHashMap(boot);
+        this.metaData = in.readBundle(boot);
+        this.volumeUuid = sForString.unparcel(in);
+        this.signingDetails = in.readParcelable(boot);
+        this.codePath = sForString.unparcel(in);
+        this.use32BitAbi = in.readBoolean();
+        this.visibleToInstantApps = in.readBoolean();
+        this.forceQueryable = in.readBoolean();
+        this.queriesIntents = in.createTypedArrayList(Intent.CREATOR);
+        this.queriesPackages = sForStringList.unparcel(in);
+        this.appComponentFactory = sForString.unparcel(in);
+        this.backupAgentName = sForString.unparcel(in);
+        this.banner = in.readInt();
+        this.category = in.readInt();
+        this.classLoaderName = sForString.unparcel(in);
+        this.className = sForString.unparcel(in);
+        this.compatibleWidthLimitDp = in.readInt();
+        this.descriptionRes = in.readInt();
+        this.enabled = in.readBoolean();
+        this.crossProfile = in.readBoolean();
+        this.fullBackupContent = in.readInt();
+        this.iconRes = in.readInt();
+        this.installLocation = in.readInt();
+        this.labelRes = in.readInt();
+        this.largestWidthLimitDp = in.readInt();
+        this.logo = in.readInt();
+        this.manageSpaceActivityName = sForString.unparcel(in);
+        this.maxAspectRatio = in.readFloat();
+        this.minAspectRatio = in.readFloat();
+        this.minSdkVersion = in.readInt();
+        this.networkSecurityConfigRes = in.readInt();
+        this.nonLocalizedLabel = in.readCharSequence();
+        this.permission = sForString.unparcel(in);
+        this.processName = sForString.unparcel(in);
+        this.requiresSmallestWidthDp = in.readInt();
+        this.roundIconRes = in.readInt();
+        this.targetSandboxVersion = in.readInt();
+        this.targetSdkVersion = in.readInt();
+        this.taskAffinity = sForString.unparcel(in);
+        this.theme = in.readInt();
+        this.uiOptions = in.readInt();
+        this.zygotePreloadName = sForString.unparcel(in);
+        this.splitClassLoaderNames = sForStringArray.unparcel(in);
+        this.splitCodePaths = sForStringArray.unparcel(in);
+        this.splitDependencies = in.readSparseArray(boot);
+        this.splitFlags = in.createIntArray();
+        this.splitNames = sForStringArray.unparcel(in);
+        this.splitRevisionCodes = in.createIntArray();
+        this.externalStorage = in.readBoolean();
+        this.baseHardwareAccelerated = in.readBoolean();
+        this.allowBackup = in.readBoolean();
+        this.killAfterRestore = in.readBoolean();
+        this.restoreAnyVersion = in.readBoolean();
+        this.fullBackupOnly = in.readBoolean();
+        this.persistent = in.readBoolean();
+        this.debuggable = in.readBoolean();
+        this.vmSafeMode = in.readBoolean();
+        this.hasCode = in.readBoolean();
+        this.allowTaskReparenting = in.readBoolean();
+        this.allowClearUserData = in.readBoolean();
+        this.largeHeap = in.readBoolean();
+        this.usesCleartextTraffic = in.readBoolean();
+        this.supportsRtl = in.readBoolean();
+        this.testOnly = in.readBoolean();
+        this.multiArch = in.readBoolean();
+        this.extractNativeLibs = in.readBoolean();
+        this.game = in.readBoolean();
+
+        this.resizeableActivity = sForBoolean.unparcel(in);
+
+        this.staticSharedLibrary = in.readBoolean();
+        this.overlay = in.readBoolean();
+        this.isolatedSplitLoading = in.readBoolean();
+        this.hasDomainUrls = in.readBoolean();
+        this.profileableByShell = in.readBoolean();
+        this.backupInForeground = in.readBoolean();
+        this.useEmbeddedDex = in.readBoolean();
+        this.defaultToDeviceProtectedStorage = in.readBoolean();
+        this.directBootAware = in.readBoolean();
+        this.partiallyDirectBootAware = in.readBoolean();
+        this.resizeableActivityViaSdkVersion = in.readBoolean();
+        this.allowClearUserDataOnFailedRestore = in.readBoolean();
+        this.allowAudioPlaybackCapture = in.readBoolean();
+        this.requestLegacyExternalStorage = in.readBoolean();
+        this.usesNonSdkApi = in.readBoolean();
+        this.hasFragileUserData = in.readBoolean();
+        this.cantSaveState = in.readBoolean();
+        this.allowNativeHeapPointerTagging = in.readBoolean();
+        this.preserveLegacyExternalStorage = in.readBoolean();
+        this.mimeGroups = (ArraySet<String>) in.readArraySet(boot);
+    }
+
+    public static final Parcelable.Creator<ParsingPackageImpl> CREATOR =
+            new Parcelable.Creator<ParsingPackageImpl>() {
+                @Override
+                public ParsingPackageImpl createFromParcel(Parcel source) {
+                    return new ParsingPackageImpl(source);
+                }
+
+                @Override
+                public ParsingPackageImpl[] newArray(int size) {
+                    return new ParsingPackageImpl[size];
+                }
+            };
+
+    @Override
+    public int getVersionCode() {
+        return versionCode;
+    }
+
+    @Override
+    public int getVersionCodeMajor() {
+        return versionCodeMajor;
+    }
+
+    @Override
+    public int getBaseRevisionCode() {
+        return baseRevisionCode;
+    }
+
+    @Nullable
+    @Override
+    public String getVersionName() {
+        return versionName;
+    }
+
+    @Override
+    public int getCompileSdkVersion() {
+        return compileSdkVersion;
+    }
+
+    @Nullable
+    @Override
+    public String getCompileSdkVersionCodeName() {
+        return compileSdkVersionCodeName;
+    }
+
+    @NonNull
+    @Override
+    public String getPackageName() {
+        return packageName;
+    }
+
+    @Nullable
+    @Override
+    public String getRealPackage() {
+        return realPackage;
+    }
+
+    @NonNull
+    @Override
+    public String getBaseCodePath() {
+        return baseCodePath;
+    }
+
+    @Override
+    public boolean isRequiredForAllUsers() {
+        return requiredForAllUsers;
+    }
+
+    @Nullable
+    @Override
+    public String getRestrictedAccountType() {
+        return restrictedAccountType;
+    }
+
+    @Nullable
+    @Override
+    public String getRequiredAccountType() {
+        return requiredAccountType;
+    }
+
+    @Nullable
+    @Override
+    public String getOverlayTarget() {
+        return overlayTarget;
+    }
+
+    @Nullable
+    @Override
+    public String getOverlayTargetName() {
+        return overlayTargetName;
+    }
+
+    @Nullable
+    @Override
+    public String getOverlayCategory() {
+        return overlayCategory;
+    }
+
+    @Override
+    public int getOverlayPriority() {
+        return overlayPriority;
+    }
+
+    @Override
+    public boolean isOverlayIsStatic() {
+        return overlayIsStatic;
+    }
+
+    @NonNull
+    @Override
+    public Map<String,String> getOverlayables() {
+        return overlayables;
+    }
+
+    @Nullable
+    @Override
+    public String getStaticSharedLibName() {
+        return staticSharedLibName;
+    }
+
+    @Override
+    public long getStaticSharedLibVersion() {
+        return staticSharedLibVersion;
+    }
+
+    @NonNull
+    @Override
+    public List<String> getLibraryNames() {
+        return libraryNames;
+    }
+
+    @NonNull
+    @Override
+    public List<String> getUsesLibraries() {
+        return usesLibraries;
+    }
+
+    @NonNull
+    @Override
+    public List<String> getUsesOptionalLibraries() {
+        return usesOptionalLibraries;
+    }
+
+    @NonNull
+    @Override
+    public List<String> getUsesStaticLibraries() {
+        return usesStaticLibraries;
+    }
+
+    @Nullable
+    @Override
+    public long[] getUsesStaticLibrariesVersions() {
+        return usesStaticLibrariesVersions;
+    }
+
+    @Nullable
+    @Override
+    public String[][] getUsesStaticLibrariesCertDigests() {
+        return usesStaticLibrariesCertDigests;
+    }
+
+    @Nullable
+    @Override
+    public String getSharedUserId() {
+        return sharedUserId;
+    }
+
+    @Override
+    public int getSharedUserLabel() {
+        return sharedUserLabel;
+    }
+
+    @NonNull
+    @Override
+    public List<ConfigurationInfo> getConfigPreferences() {
+        return configPreferences;
+    }
+
+    @NonNull
+    @Override
+    public List<FeatureInfo> getReqFeatures() {
+        return reqFeatures;
+    }
+
+    @NonNull
+    @Override
+    public List<FeatureGroupInfo> getFeatureGroups() {
+        return featureGroups;
+    }
+
+    @Nullable
+    @Override
+    public byte[] getRestrictUpdateHash() {
+        return restrictUpdateHash;
+    }
+
+    @NonNull
+    @Override
+    public List<String> getOriginalPackages() {
+        return originalPackages;
+    }
+
+    @NonNull
+    @Override
+    public List<String> getAdoptPermissions() {
+        return adoptPermissions;
+    }
+
+    @NonNull
+    @Override
+    public List<String> getRequestedPermissions() {
+        return requestedPermissions;
+    }
+
+    @NonNull
+    @Override
+    public List<String> getImplicitPermissions() {
+        return implicitPermissions;
+    }
+
+    @NonNull
+    @Override
+    public Set<String> getUpgradeKeySets() {
+        return upgradeKeySets;
+    }
+
+    @NonNull
+    @Override
+    public Map<String,ArraySet<PublicKey>> getKeySetMapping() {
+        return keySetMapping;
+    }
+
+    @NonNull
+    @Override
+    public List<String> getProtectedBroadcasts() {
+        return protectedBroadcasts;
+    }
+
+    @NonNull
+    @Override
+    public List<ParsedActivity> getActivities() {
+        return activities;
+    }
+
+    @NonNull
+    @Override
+    public List<ParsedActivity> getReceivers() {
+        return receivers;
+    }
+
+    @NonNull
+    @Override
+    public List<ParsedService> getServices() {
+        return services;
+    }
+
+    @NonNull
+    @Override
+    public List<ParsedProvider> getProviders() {
+        return providers;
+    }
+
+    @NonNull
+    @Override
+    public List<ParsedFeature> getFeatures() {
+        return features;
+    }
+
+    @NonNull
+    @Override
+    public List<ParsedPermission> getPermissions() {
+        return permissions;
+    }
+
+    @NonNull
+    @Override
+    public List<ParsedPermissionGroup> getPermissionGroups() {
+        return permissionGroups;
+    }
+
+    @NonNull
+    @Override
+    public List<ParsedInstrumentation> getInstrumentations() {
+        return instrumentations;
+    }
+
+    @NonNull
+    @Override
+    public List<Pair<String,ParsedIntentInfo>> getPreferredActivityFilters() {
+        return preferredActivityFilters;
+    }
+
+    @NonNull
+    @Override
+    public Map<String,ParsedProcess> getProcesses() {
+        return processes;
+    }
+
+    @Nullable
+    @Override
+    public Bundle getMetaData() {
+        return metaData;
+    }
+
+    private void addMimeGroupsFromComponent(ParsedComponent component) {
+        for (int i = component.getIntents().size() - 1; i >= 0; i--) {
+            IntentFilter filter = component.getIntents().get(i);
+            for (int groupIndex = filter.countMimeGroups() - 1; groupIndex >= 0; groupIndex--) {
+                mimeGroups = ArrayUtils.add(mimeGroups, filter.getMimeGroup(groupIndex));
+            }
+        }
+    }
+
+    @Override
+    @Nullable
+    public Set<String> getMimeGroups() {
+        return mimeGroups;
+    }
+
+    @Nullable
+    @Override
+    public String getVolumeUuid() {
+        return volumeUuid;
+    }
+
+    @Nullable
+    @Override
+    public PackageParser.SigningDetails getSigningDetails() {
+        return signingDetails;
+    }
+
+    @NonNull
+    @Override
+    public String getCodePath() {
+        return codePath;
+    }
+
+    @Override
+    public boolean isUse32BitAbi() {
+        return use32BitAbi;
+    }
+
+    @Override
+    public boolean isVisibleToInstantApps() {
+        return visibleToInstantApps;
+    }
+
+    @Override
+    public boolean isForceQueryable() {
+        return forceQueryable;
+    }
+
+    @NonNull
+    @Override
+    public List<Intent> getQueriesIntents() {
+        return queriesIntents;
+    }
+
+    @NonNull
+    @Override
+    public List<String> getQueriesPackages() {
+        return queriesPackages;
+    }
+
+    @NonNull
+    @Override
+    public Set<String> getQueriesProviders() {
+        return queriesProviders;
+    }
+
+    @Nullable
+    @Override
+    public String[] getSplitClassLoaderNames() {
+        return splitClassLoaderNames;
+    }
+
+    @Nullable
+    @Override
+    public String[] getSplitCodePaths() {
+        return splitCodePaths;
+    }
+
+    @Nullable
+    @Override
+    public SparseArray<int[]> getSplitDependencies() {
+        return splitDependencies;
+    }
+
+    @Nullable
+    @Override
+    public int[] getSplitFlags() {
+        return splitFlags;
+    }
+
+    @Nullable
+    @Override
+    public String[] getSplitNames() {
+        return splitNames;
+    }
+
+    @Nullable
+    @Override
+    public int[] getSplitRevisionCodes() {
+        return splitRevisionCodes;
+    }
+
+    @Nullable
+    @Override
+    public String getAppComponentFactory() {
+        return appComponentFactory;
+    }
+
+    @Nullable
+    @Override
+    public String getBackupAgentName() {
+        return backupAgentName;
+    }
+
+    @Override
+    public int getBanner() {
+        return banner;
+    }
+
+    @Override
+    public int getCategory() {
+        return category;
+    }
+
+    @Nullable
+    @Override
+    public String getClassLoaderName() {
+        return classLoaderName;
+    }
+
+    @Nullable
+    @Override
+    public String getClassName() {
+        return className;
+    }
+
+    @Override
+    public int getCompatibleWidthLimitDp() {
+        return compatibleWidthLimitDp;
+    }
+
+    @Override
+    public int getDescriptionRes() {
+        return descriptionRes;
+    }
+
+    @Override
+    public boolean isEnabled() {
+        return enabled;
+    }
+
+    @Override
+    public boolean isCrossProfile() {
+        return crossProfile;
+    }
+
+    @Override
+    public int getFullBackupContent() {
+        return fullBackupContent;
+    }
+
+    @Override
+    public int getIconRes() {
+        return iconRes;
+    }
+
+    @Override
+    public int getInstallLocation() {
+        return installLocation;
+    }
+
+    @Override
+    public int getLabelRes() {
+        return labelRes;
+    }
+
+    @Override
+    public int getLargestWidthLimitDp() {
+        return largestWidthLimitDp;
+    }
+
+    @Override
+    public int getLogo() {
+        return logo;
+    }
+
+    @Nullable
+    @Override
+    public String getManageSpaceActivityName() {
+        return manageSpaceActivityName;
+    }
+
+    @Override
+    public float getMaxAspectRatio() {
+        return maxAspectRatio;
+    }
+
+    @Override
+    public float getMinAspectRatio() {
+        return minAspectRatio;
+    }
+
+    @Override
+    public int getMinSdkVersion() {
+        return minSdkVersion;
+    }
+
+    @Override
+    public int getNetworkSecurityConfigRes() {
+        return networkSecurityConfigRes;
+    }
+
+    @Nullable
+    @Override
+    public CharSequence getNonLocalizedLabel() {
+        return nonLocalizedLabel;
+    }
+
+    @Nullable
+    @Override
+    public String getPermission() {
+        return permission;
+    }
+
+    @Override
+    public int getRequiresSmallestWidthDp() {
+        return requiresSmallestWidthDp;
+    }
+
+    @Override
+    public int getRoundIconRes() {
+        return roundIconRes;
+    }
+
+    @Override
+    public int getTargetSandboxVersion() {
+        return targetSandboxVersion;
+    }
+
+    @Override
+    public int getTargetSdkVersion() {
+        return targetSdkVersion;
+    }
+
+    @Nullable
+    @Override
+    public String getTaskAffinity() {
+        return taskAffinity;
+    }
+
+    @Override
+    public int getTheme() {
+        return theme;
+    }
+
+    @Override
+    public int getUiOptions() {
+        return uiOptions;
+    }
+
+    @Nullable
+    @Override
+    public String getZygotePreloadName() {
+        return zygotePreloadName;
+    }
+
+    @Override
+    public boolean isExternalStorage() {
+        return externalStorage;
+    }
+
+    @Override
+    public boolean isBaseHardwareAccelerated() {
+        return baseHardwareAccelerated;
+    }
+
+    @Override
+    public boolean isAllowBackup() {
+        return allowBackup;
+    }
+
+    @Override
+    public boolean isKillAfterRestore() {
+        return killAfterRestore;
+    }
+
+    @Override
+    public boolean isRestoreAnyVersion() {
+        return restoreAnyVersion;
+    }
+
+    @Override
+    public boolean isFullBackupOnly() {
+        return fullBackupOnly;
+    }
+
+    @Override
+    public boolean isPersistent() {
+        return persistent;
+    }
+
+    @Override
+    public boolean isDebuggable() {
+        return debuggable;
+    }
+
+    @Override
+    public boolean isVmSafeMode() {
+        return vmSafeMode;
+    }
+
+    @Override
+    public boolean isHasCode() {
+        return hasCode;
+    }
+
+    @Override
+    public boolean isAllowTaskReparenting() {
+        return allowTaskReparenting;
+    }
+
+    @Override
+    public boolean isAllowClearUserData() {
+        return allowClearUserData;
+    }
+
+    @Override
+    public boolean isLargeHeap() {
+        return largeHeap;
+    }
+
+    @Override
+    public boolean isUsesCleartextTraffic() {
+        return usesCleartextTraffic;
+    }
+
+    @Override
+    public boolean isSupportsRtl() {
+        return supportsRtl;
+    }
+
+    @Override
+    public boolean isTestOnly() {
+        return testOnly;
+    }
+
+    @Override
+    public boolean isMultiArch() {
+        return multiArch;
+    }
+
+    @Override
+    public boolean isExtractNativeLibs() {
+        return extractNativeLibs;
+    }
+
+    @Override
+    public boolean isGame() {
+        return game;
+    }
+
+    /**
+     * @see ParsingPackageRead#getResizeableActivity()
+     */
+    @Nullable
+    @Override
+    public Boolean getResizeableActivity() {
+        return resizeableActivity;
+    }
+
+    @Override
+    public boolean isStaticSharedLibrary() {
+        return staticSharedLibrary;
+    }
+
+    @Override
+    public boolean isOverlay() {
+        return overlay;
+    }
+
+    @Override
+    public boolean isIsolatedSplitLoading() {
+        return isolatedSplitLoading;
+    }
+
+    @Override
+    public boolean isHasDomainUrls() {
+        return hasDomainUrls;
+    }
+
+    @Override
+    public boolean isProfileableByShell() {
+        return profileableByShell;
+    }
+
+    @Override
+    public boolean isBackupInForeground() {
+        return backupInForeground;
+    }
+
+    @Override
+    public boolean isUseEmbeddedDex() {
+        return useEmbeddedDex;
+    }
+
+    @Override
+    public boolean isDefaultToDeviceProtectedStorage() {
+        return defaultToDeviceProtectedStorage;
+    }
+
+    @Override
+    public boolean isDirectBootAware() {
+        return directBootAware;
+    }
+
+    @Override
+    public boolean isPartiallyDirectBootAware() {
+        return partiallyDirectBootAware;
+    }
+
+    @Override
+    public boolean isResizeableActivityViaSdkVersion() {
+        return resizeableActivityViaSdkVersion;
+    }
+
+    @Override
+    public boolean isAllowClearUserDataOnFailedRestore() {
+        return allowClearUserDataOnFailedRestore;
+    }
+
+    @Override
+    public boolean isAllowAudioPlaybackCapture() {
+        return allowAudioPlaybackCapture;
+    }
+
+    @Override
+    public boolean isRequestLegacyExternalStorage() {
+        return requestLegacyExternalStorage;
+    }
+
+    @Override
+    public boolean isUsesNonSdkApi() {
+        return usesNonSdkApi;
+    }
+
+    @Override
+    public boolean isHasFragileUserData() {
+        return hasFragileUserData;
+    }
+
+    @Override
+    public boolean isCantSaveState() {
+        return cantSaveState;
+    }
+
+    @Override
+    public boolean isAllowNativeHeapPointerTagging() {
+        return allowNativeHeapPointerTagging;
+    }
+
+    @Override
+    public boolean hasPreserveLegacyExternalStorage() {
+        return preserveLegacyExternalStorage;
+    }
+
+    @Override
+    public ParsingPackageImpl setBaseRevisionCode(int value) {
+        baseRevisionCode = value;
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setCompileSdkVersion(int value) {
+        compileSdkVersion = value;
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setRequiredForAllUsers(boolean value) {
+        requiredForAllUsers = value;
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setOverlayPriority(int value) {
+        overlayPriority = value;
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setOverlayIsStatic(boolean value) {
+        overlayIsStatic = value;
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setStaticSharedLibVersion(long value) {
+        staticSharedLibVersion = value;
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setSharedUserLabel(int value) {
+        sharedUserLabel = value;
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setRestrictUpdateHash(@Nullable byte... value) {
+        restrictUpdateHash = value;
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setUpgradeKeySets(@NonNull Set<String> value) {
+        upgradeKeySets = value;
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setProcesses(@NonNull Map<String,ParsedProcess> value) {
+        processes = value;
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setMetaData(@Nullable Bundle value) {
+        metaData = value;
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setSigningDetails(@Nullable PackageParser.SigningDetails value) {
+        signingDetails = value;
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setUse32BitAbi(boolean value) {
+        use32BitAbi = value;
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setVisibleToInstantApps(boolean value) {
+        visibleToInstantApps = value;
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setForceQueryable(boolean value) {
+        forceQueryable = value;
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setBanner(int value) {
+        banner = value;
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setCategory(int value) {
+        category = value;
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setCompatibleWidthLimitDp(int value) {
+        compatibleWidthLimitDp = value;
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setDescriptionRes(int value) {
+        descriptionRes = value;
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setEnabled(boolean value) {
+        enabled = value;
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setCrossProfile(boolean value) {
+        crossProfile = value;
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setFullBackupContent(int value) {
+        fullBackupContent = value;
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setIconRes(int value) {
+        iconRes = value;
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setInstallLocation(int value) {
+        installLocation = value;
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setLabelRes(int value) {
+        labelRes = value;
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setLargestWidthLimitDp(int value) {
+        largestWidthLimitDp = value;
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setLogo(int value) {
+        logo = value;
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setMaxAspectRatio(float value) {
+        maxAspectRatio = value;
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setMinAspectRatio(float value) {
+        minAspectRatio = value;
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setMinSdkVersion(int value) {
+        minSdkVersion = value;
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setNetworkSecurityConfigRes(int value) {
+        networkSecurityConfigRes = value;
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setNonLocalizedLabel(@Nullable CharSequence value) {
+        nonLocalizedLabel = value;
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setRequiresSmallestWidthDp(int value) {
+        requiresSmallestWidthDp = value;
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setRoundIconRes(int value) {
+        roundIconRes = value;
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setTargetSandboxVersion(int value) {
+        targetSandboxVersion = value;
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setTargetSdkVersion(int value) {
+        targetSdkVersion = value;
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setTheme(int value) {
+        theme = value;
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setUiOptions(int value) {
+        uiOptions = value;
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setExternalStorage(boolean value) {
+        externalStorage = value;
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setBaseHardwareAccelerated(boolean value) {
+        baseHardwareAccelerated = value;
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setAllowBackup(boolean value) {
+        allowBackup = value;
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setKillAfterRestore(boolean value) {
+        killAfterRestore = value;
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setRestoreAnyVersion(boolean value) {
+        restoreAnyVersion = value;
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setFullBackupOnly(boolean value) {
+        fullBackupOnly = value;
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setPersistent(boolean value) {
+        persistent = value;
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setDebuggable(boolean value) {
+        debuggable = value;
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setVmSafeMode(boolean value) {
+        vmSafeMode = value;
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setHasCode(boolean value) {
+        hasCode = value;
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setAllowTaskReparenting(boolean value) {
+        allowTaskReparenting = value;
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setAllowClearUserData(boolean value) {
+        allowClearUserData = value;
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setLargeHeap(boolean value) {
+        largeHeap = value;
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setUsesCleartextTraffic(boolean value) {
+        usesCleartextTraffic = value;
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setSupportsRtl(boolean value) {
+        supportsRtl = value;
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setTestOnly(boolean value) {
+        testOnly = value;
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setMultiArch(boolean value) {
+        multiArch = value;
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setExtractNativeLibs(boolean value) {
+        extractNativeLibs = value;
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setGame(boolean value) {
+        game = value;
+        return this;
+    }
+
+    /**
+     * @see ParsingPackageRead#getResizeableActivity()
+     */
+    @Override
+    public ParsingPackageImpl setResizeableActivity(@Nullable Boolean value) {
+        resizeableActivity = value;
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setStaticSharedLibrary(boolean value) {
+        staticSharedLibrary = value;
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setOverlay(boolean value) {
+        overlay = value;
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setIsolatedSplitLoading(boolean value) {
+        isolatedSplitLoading = value;
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setHasDomainUrls(boolean value) {
+        hasDomainUrls = value;
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setProfileableByShell(boolean value) {
+        profileableByShell = value;
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setBackupInForeground(boolean value) {
+        backupInForeground = value;
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setUseEmbeddedDex(boolean value) {
+        useEmbeddedDex = value;
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setDefaultToDeviceProtectedStorage(boolean value) {
+        defaultToDeviceProtectedStorage = value;
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setDirectBootAware(boolean value) {
+        directBootAware = value;
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setPartiallyDirectBootAware(boolean value) {
+        partiallyDirectBootAware = value;
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setResizeableActivityViaSdkVersion(boolean value) {
+        resizeableActivityViaSdkVersion = value;
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setAllowClearUserDataOnFailedRestore(boolean value) {
+        allowClearUserDataOnFailedRestore = value;
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setAllowAudioPlaybackCapture(boolean value) {
+        allowAudioPlaybackCapture = value;
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setRequestLegacyExternalStorage(boolean value) {
+        requestLegacyExternalStorage = value;
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setUsesNonSdkApi(boolean value) {
+        usesNonSdkApi = value;
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setHasFragileUserData(boolean value) {
+        hasFragileUserData = value;
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setCantSaveState(boolean value) {
+        cantSaveState = value;
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setAllowNativeHeapPointerTagging(boolean value) {
+        allowNativeHeapPointerTagging = value;
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setPreserveLegacyExternalStorage(boolean value) {
+        preserveLegacyExternalStorage = value;
+        return this;
+    }
+}
diff --git a/core/java/android/content/pm/parsing/ParsingPackageRead.java b/core/java/android/content/pm/parsing/ParsingPackageRead.java
new file mode 100644
index 0000000..048b924
--- /dev/null
+++ b/core/java/android/content/pm/parsing/ParsingPackageRead.java
@@ -0,0 +1,845 @@
+/*
+ * 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.NonNull;
+import android.annotation.Nullable;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.ConfigurationInfo;
+import android.content.pm.FeatureGroupInfo;
+import android.content.pm.FeatureInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageParser;
+import android.content.pm.ServiceInfo;
+import android.content.pm.parsing.component.ParsedActivity;
+import android.content.pm.parsing.component.ParsedFeature;
+import android.content.pm.parsing.component.ParsedInstrumentation;
+import android.content.pm.parsing.component.ParsedIntentInfo;
+import android.content.pm.parsing.component.ParsedPermission;
+import android.content.pm.parsing.component.ParsedPermissionGroup;
+import android.content.pm.parsing.component.ParsedProcess;
+import android.content.pm.parsing.component.ParsedProvider;
+import android.content.pm.parsing.component.ParsedService;
+import android.os.Bundle;
+import android.os.Parcelable;
+import android.util.ArraySet;
+import android.util.Pair;
+import android.util.SparseArray;
+
+import com.android.internal.R;
+
+import java.security.PublicKey;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Everything written by {@link ParsingPackage} and readable back.
+ *
+ * @hide
+ */
+@SuppressWarnings("UnusedReturnValue")
+public interface ParsingPackageRead extends Parcelable {
+
+    /**
+     * @see ActivityInfo
+     * @see PackageInfo#activities
+     */
+    @NonNull
+    List<ParsedActivity> getActivities();
+
+    /**
+     * The names of packages to adopt ownership of permissions from, parsed under
+     * {@link PackageParser#TAG_ADOPT_PERMISSIONS}.
+     * @see R.styleable#AndroidManifestOriginalPackage_name
+     */
+    @NonNull
+    List<String> getAdoptPermissions();
+
+    /**
+     * @see PackageInfo#configPreferences
+     * @see R.styleable#AndroidManifestUsesConfiguration
+     */
+    @NonNull
+    List<ConfigurationInfo> getConfigPreferences();
+
+    @NonNull
+    List<ParsedFeature> getFeatures();
+
+    /**
+     * @see PackageInfo#featureGroups
+     * @see R.styleable#AndroidManifestUsesFeature
+     */
+    @NonNull
+    List<FeatureGroupInfo> getFeatureGroups();
+
+    /**
+     * Permissions requested but not in the manifest. These may have been split or migrated from
+     * previous versions/definitions.
+     */
+    @NonNull
+    List<String> getImplicitPermissions();
+
+    /**
+     * @see android.content.pm.InstrumentationInfo
+     * @see PackageInfo#instrumentation
+     */
+    @NonNull
+    List<ParsedInstrumentation> getInstrumentations();
+
+    /**
+     * For use with {@link com.android.server.pm.KeySetManagerService}. Parsed in
+     * {@link PackageParser#TAG_KEY_SETS}.
+     * @see R.styleable#AndroidManifestKeySet
+     * @see R.styleable#AndroidManifestPublicKey
+     */
+    @NonNull
+    Map<String, ArraySet<PublicKey>> getKeySetMapping();
+
+    /**
+     * Library names this package is declared as, for use by other packages with "uses-library".
+     * @see R.styleable#AndroidManifestLibrary
+     */
+    @NonNull
+    List<String> getLibraryNames();
+
+    /**
+     * For system use to migrate from an old package name to a new one, moving over data
+     * if available.
+     * @see R.styleable#AndroidManifestOriginalPackage}
+     */
+    @NonNull
+    List<String> getOriginalPackages();
+
+    /**
+     * Map of overlayable name to actor name.
+     */
+    @NonNull
+    Map<String, String> getOverlayables();
+
+    /**
+     * @see android.content.pm.PermissionInfo
+     * @see PackageInfo#permissions
+     */
+    @NonNull
+    List<ParsedPermission> getPermissions();
+
+    /**
+     * @see android.content.pm.PermissionGroupInfo
+     */
+    @NonNull
+    List<ParsedPermissionGroup> getPermissionGroups();
+
+    /**
+     * Used to determine the default preferred handler of an {@link Intent}.
+     *
+     * Map of component className to intent info inside that component.
+     * TODO(b/135203078): Is this actually used/working?
+     */
+    @NonNull
+    List<Pair<String, ParsedIntentInfo>> getPreferredActivityFilters();
+
+    /**
+     * System protected broadcasts.
+     * @see R.styleable#AndroidManifestProtectedBroadcast
+     */
+    @NonNull
+    List<String> getProtectedBroadcasts();
+
+    /**
+     * @see android.content.pm.ProviderInfo
+     * @see PackageInfo#providers
+     */
+    @NonNull
+    List<ParsedProvider> getProviders();
+
+    /**
+     * @see android.content.pm.ProcessInfo
+     */
+    @NonNull
+    Map<String, ParsedProcess> getProcesses();
+
+    /**
+     * Since they share several attributes, receivers are parsed as {@link ParsedActivity}, even
+     * though they represent different functionality.
+     * TODO(b/135203078): Reconsider this and maybe make ParsedReceiver so it's not so confusing
+     * @see ActivityInfo
+     * @see PackageInfo#receivers
+     */
+    @NonNull
+    List<ParsedActivity> getReceivers();
+
+    /**
+     * @see PackageInfo#reqFeatures
+     * @see R.styleable#AndroidManifestUsesFeature
+     */
+    @NonNull
+    List<FeatureInfo> getReqFeatures();
+
+    /**
+     * All the permissions declared. This is an effective set, and may include permissions
+     * transformed from split/migrated permissions from previous versions, so may not be exactly
+     * what the package declares in its manifest.
+     * @see PackageInfo#requestedPermissions
+     * @see R.styleable#AndroidManifestUsesPermission
+     */
+    @NonNull
+    List<String> getRequestedPermissions();
+
+    /**
+     * Whether or not the app requested explicitly resizeable Activities.
+     * A null value means nothing was explicitly requested.
+     */
+    @Nullable
+    Boolean getResizeableActivity();
+
+    /**
+     * @see ServiceInfo
+     * @see PackageInfo#services
+     */
+    @NonNull
+    List<ParsedService> getServices();
+
+    /** @see R.styleable#AndroidManifestUsesLibrary */
+    @NonNull
+    List<String> getUsesLibraries();
+
+    /**
+     * Like {@link #getUsesLibraries()}, but marked optional by setting
+     * {@link R.styleable#AndroidManifestUsesLibrary_required} to false . Application is expected
+     * to handle absence manually.
+     * @see R.styleable#AndroidManifestUsesLibrary
+     */
+    @NonNull
+    List<String> getUsesOptionalLibraries();
+
+    /**
+     * TODO(b/135203078): Move static library stuff to an inner data class
+     * @see R.styleable#AndroidManifestUsesStaticLibrary
+     */
+    @NonNull
+    List<String> getUsesStaticLibraries();
+
+    /** @see R.styleable#AndroidManifestUsesStaticLibrary_certDigest */
+    @Nullable
+    String[][] getUsesStaticLibrariesCertDigests();
+
+    /** @see R.styleable#AndroidManifestUsesStaticLibrary_version */
+    @Nullable
+    long[] getUsesStaticLibrariesVersions();
+
+    /**
+     * Intents that this package may query or require and thus requires visibility into.
+     * @see R.styleable#AndroidManifestQueriesIntent
+     */
+    @NonNull
+    List<Intent> getQueriesIntents();
+
+    /**
+     * Other packages that this package may query or require and thus requires visibility into.
+     * @see R.styleable#AndroidManifestQueriesPackage
+     */
+    @NonNull
+    List<String> getQueriesPackages();
+
+    /**
+     * Authorities that this package may query or require and thus requires visibility into.
+     * @see R.styleable#AndroidManifestQueriesProvider
+     */
+    @NonNull
+    Set<String> getQueriesProviders();
+
+    /**
+     * We store the application meta-data independently to avoid multiple unwanted references
+     * TODO(b/135203078): What does this comment mean?
+     * TODO(b/135203078): Make all the Bundles immutable (and non-null by shared empty reference?)
+     */
+    @Nullable
+    Bundle getMetaData();
+
+    /** @see R.styleable#AndroidManifestApplication_forceQueryable */
+    boolean isForceQueryable();
+
+    /**
+     * @see ApplicationInfo#maxAspectRatio
+     * @see R.styleable#AndroidManifestApplication_maxAspectRatio
+     */
+    float getMaxAspectRatio();
+
+    /**
+     * @see ApplicationInfo#minAspectRatio
+     * @see R.styleable#AndroidManifestApplication_minAspectRatio
+     */
+    float getMinAspectRatio();
+
+    /**
+     * @see ApplicationInfo#permission
+     * @see R.styleable#AndroidManifestApplication_permission
+     */
+    @Nullable
+    String getPermission();
+
+    /**
+     * @see ApplicationInfo#processName
+     * @see R.styleable#AndroidManifestApplication_process
+     */
+    @NonNull
+    String getProcessName();
+
+    /**
+     * @see PackageInfo#sharedUserId
+     * @see R.styleable#AndroidManifest_sharedUserId
+     */
+    @Deprecated
+    @Nullable
+    String getSharedUserId();
+
+    /** @see R.styleable#AndroidManifestStaticLibrary_name */
+    @Nullable
+    String getStaticSharedLibName();
+
+    /**
+     * @see ApplicationInfo#taskAffinity
+     * @see R.styleable#AndroidManifestApplication_taskAffinity
+     */
+    @Nullable
+    String getTaskAffinity();
+
+    /**
+     * @see ApplicationInfo#targetSdkVersion
+     * @see R.styleable#AndroidManifestUsesSdk_targetSdkVersion
+     */
+    int getTargetSdkVersion();
+
+    /**
+     * @see ApplicationInfo#uiOptions
+     * @see R.styleable#AndroidManifestApplication_uiOptions
+     */
+    int getUiOptions();
+
+    boolean isCrossProfile();
+
+    boolean isResizeableActivityViaSdkVersion();
+
+    /** @see ApplicationInfo#FLAG_HARDWARE_ACCELERATED */
+    boolean isBaseHardwareAccelerated();
+
+    /**
+     * If omitted from manifest, returns true if {@link #getTargetSdkVersion()} >=
+     * {@link android.os.Build.VERSION_CODES#DONUT}.
+     * @see R.styleable#AndroidManifestSupportsScreens_resizeable
+     * @see ApplicationInfo#FLAG_RESIZEABLE_FOR_SCREENS
+     */
+    boolean isResizeable();
+
+    /** @see ApplicationInfo#PRIVATE_FLAG_ALLOW_AUDIO_PLAYBACK_CAPTURE */
+    boolean isAllowAudioPlaybackCapture();
+
+    /** @see ApplicationInfo#FLAG_ALLOW_BACKUP */
+    boolean isAllowBackup();
+
+    /** @see ApplicationInfo#FLAG_ALLOW_CLEAR_USER_DATA */
+    boolean isAllowClearUserData();
+
+    /** @see ApplicationInfo#PRIVATE_FLAG_ALLOW_CLEAR_USER_DATA_ON_FAILED_RESTORE */
+    boolean isAllowClearUserDataOnFailedRestore();
+
+    /** @see ApplicationInfo#FLAG_ALLOW_TASK_REPARENTING */
+    boolean isAllowTaskReparenting();
+
+    /**
+     * @see ApplicationInfo#PRIVATE_FLAG_IS_RESOURCE_OVERLAY
+     * @see ApplicationInfo#isResourceOverlay()
+     */
+    boolean isOverlay();
+
+    /** @see ApplicationInfo#PRIVATE_FLAG_BACKUP_IN_FOREGROUND */
+    boolean isBackupInForeground();
+
+    /** @see ApplicationInfo#PRIVATE_FLAG_CANT_SAVE_STATE */
+    boolean isCantSaveState();
+
+    /** @see ApplicationInfo#FLAG_DEBUGGABLE */
+    boolean isDebuggable();
+
+    /** @see ApplicationInfo#PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE */
+    boolean isDefaultToDeviceProtectedStorage();
+
+    /** @see ApplicationInfo#PRIVATE_FLAG_DIRECT_BOOT_AWARE */
+    boolean isDirectBootAware();
+
+    /** @see ApplicationInfo#FLAG_EXTERNAL_STORAGE */
+    boolean isExternalStorage();
+
+    /** @see ApplicationInfo#FLAG_EXTRACT_NATIVE_LIBS */
+    boolean isExtractNativeLibs();
+
+    /** @see ApplicationInfo#FLAG_FULL_BACKUP_ONLY */
+    boolean isFullBackupOnly();
+
+    /** @see ApplicationInfo#FLAG_HAS_CODE */
+    boolean isHasCode();
+
+    /** @see ApplicationInfo#PRIVATE_FLAG_HAS_FRAGILE_USER_DATA */
+    boolean isHasFragileUserData();
+
+    /** @see ApplicationInfo#FLAG_IS_GAME */
+    @Deprecated
+    boolean isGame();
+
+    /** @see ApplicationInfo#PRIVATE_FLAG_ISOLATED_SPLIT_LOADING */
+    boolean isIsolatedSplitLoading();
+
+    /** @see ApplicationInfo#FLAG_KILL_AFTER_RESTORE */
+    boolean isKillAfterRestore();
+
+    /** @see ApplicationInfo#FLAG_LARGE_HEAP */
+    boolean isLargeHeap();
+
+    /** @see ApplicationInfo#FLAG_MULTIARCH */
+    boolean isMultiArch();
+
+    /** @see ApplicationInfo#PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE */
+    boolean isPartiallyDirectBootAware();
+
+    /** @see ApplicationInfo#FLAG_PERSISTENT */
+    boolean isPersistent();
+
+    /** @see ApplicationInfo#PRIVATE_FLAG_PROFILEABLE_BY_SHELL */
+    boolean isProfileableByShell();
+
+    /** @see ApplicationInfo#PRIVATE_FLAG_REQUEST_LEGACY_EXTERNAL_STORAGE */
+    boolean isRequestLegacyExternalStorage();
+
+    /** @see ApplicationInfo#FLAG_RESTORE_ANY_VERSION */
+    boolean isRestoreAnyVersion();
+
+    // ParsingPackageRead setSplitHasCode(int splitIndex, boolean splitHasCode);
+
+    /** Flags of any split APKs; ordered by parsed splitName */
+    @Nullable
+    int[] getSplitFlags();
+
+    /** @see ApplicationInfo#splitSourceDirs */
+    @Nullable
+    String[] getSplitCodePaths();
+
+    /** @see ApplicationInfo#splitDependencies */
+    @Nullable
+    SparseArray<int[]> getSplitDependencies();
+
+    /**
+     * @see ApplicationInfo#splitNames
+     * @see PackageInfo#splitNames
+     */
+    @Nullable
+    String[] getSplitNames();
+
+    /** @see PackageInfo#splitRevisionCodes */
+    int[] getSplitRevisionCodes();
+
+    /** @see ApplicationInfo#PRIVATE_FLAG_STATIC_SHARED_LIBRARY */
+    boolean isStaticSharedLibrary();
+
+    /** @see ApplicationInfo#FLAG_SUPPORTS_RTL */
+    boolean isSupportsRtl();
+
+    /** @see ApplicationInfo#FLAG_TEST_ONLY */
+    boolean isTestOnly();
+
+    /** @see ApplicationInfo#PRIVATE_FLAG_USE_EMBEDDED_DEX */
+    boolean isUseEmbeddedDex();
+
+    /** @see ApplicationInfo#FLAG_USES_CLEARTEXT_TRAFFIC */
+    boolean isUsesCleartextTraffic();
+
+    /** @see ApplicationInfo#PRIVATE_FLAG_USES_NON_SDK_API */
+    boolean isUsesNonSdkApi();
+
+    /**
+     * Set if the any of components are visible to instant applications.
+     * @see R.styleable#AndroidManifestActivity_visibleToInstantApps
+     * @see R.styleable#AndroidManifestProvider_visibleToInstantApps
+     * @see R.styleable#AndroidManifestService_visibleToInstantApps
+     */
+    boolean isVisibleToInstantApps();
+
+    /** @see ApplicationInfo#FLAG_VM_SAFE_MODE */
+    boolean isVmSafeMode();
+
+    /**
+     * If omitted from manifest, returns true if {@link #getTargetSdkVersion()} >=
+     * {@link android.os.Build.VERSION_CODES#DONUT}.
+     * @see R.styleable#AndroidManifestSupportsScreens_anyDensity
+     * @see ApplicationInfo#FLAG_SUPPORTS_SCREEN_DENSITIES
+     */
+    boolean isAnyDensity();
+
+    /**
+     * @see ApplicationInfo#appComponentFactory
+     * @see R.styleable#AndroidManifestApplication_appComponentFactory
+     */
+    @Nullable
+    String getAppComponentFactory();
+
+    /**
+     * @see ApplicationInfo#backupAgentName
+     * @see R.styleable#AndroidManifestApplication_backupAgent
+     */
+    @Nullable
+    String getBackupAgentName();
+
+    /**
+     * @see ApplicationInfo#banner
+     * @see R.styleable#AndroidManifestApplication_banner
+     */
+    int getBanner();
+
+    /**
+     * @see ApplicationInfo#category
+     * @see R.styleable#AndroidManifestApplication_appCategory
+     */
+    int getCategory();
+
+    /**
+     * @see ApplicationInfo#classLoaderName
+     * @see R.styleable#AndroidManifestApplication_classLoader
+     */
+    @Nullable
+    String getClassLoaderName();
+
+    /**
+     * @see ApplicationInfo#className
+     * @see R.styleable#AndroidManifestApplication_name
+     */
+    @Nullable
+    String getClassName();
+
+    String getPackageName();
+
+    /** Path of base APK */
+    String getBaseCodePath();
+
+    /**
+     * Path where this package was found on disk. For monolithic packages
+     * this is path to single base APK file; for cluster packages this is
+     * path to the cluster directory.
+     */
+    @NonNull
+    String getCodePath();
+
+    /**
+     * @see ApplicationInfo#compatibleWidthLimitDp
+     * @see R.styleable#AndroidManifestSupportsScreens_compatibleWidthLimitDp
+     */
+    int getCompatibleWidthLimitDp();
+
+    /**
+     * @see ApplicationInfo#descriptionRes
+     * @see R.styleable#AndroidManifestApplication_description
+     */
+    int getDescriptionRes();
+
+    /**
+     * @see ApplicationInfo#enabled
+     * @see R.styleable#AndroidManifestApplication_enabled
+     */
+    boolean isEnabled();
+
+    /**
+     * @see ApplicationInfo#fullBackupContent
+     * @see R.styleable#AndroidManifestApplication_fullBackupContent
+     */
+    int getFullBackupContent();
+
+    /** @see ApplicationInfo#PRIVATE_FLAG_HAS_DOMAIN_URLS */
+    boolean isHasDomainUrls();
+
+    /**
+     * @see ApplicationInfo#iconRes
+     * @see R.styleable#AndroidManifestApplication_icon
+     */
+    int getIconRes();
+
+    /**
+     * @see ApplicationInfo#installLocation
+     * @see R.styleable#AndroidManifest_installLocation
+     */
+    int getInstallLocation();
+
+    /**
+     * @see ApplicationInfo#labelRes
+     * @see R.styleable#AndroidManifestApplication_label
+     */
+    int getLabelRes();
+
+    /**
+     * @see ApplicationInfo#largestWidthLimitDp
+     * @see R.styleable#AndroidManifestSupportsScreens_largestWidthLimitDp
+     */
+    int getLargestWidthLimitDp();
+
+    /**
+     * @see ApplicationInfo#logo
+     * @see R.styleable#AndroidManifestApplication_logo
+     */
+    int getLogo();
+
+    /**
+     * @see ApplicationInfo#manageSpaceActivityName
+     * @see R.styleable#AndroidManifestApplication_manageSpaceActivity
+     */
+    @Nullable
+    String getManageSpaceActivityName();
+
+    /**
+     * @see ApplicationInfo#minSdkVersion
+     * @see R.styleable#AndroidManifestUsesSdk_minSdkVersion
+     */
+    int getMinSdkVersion();
+
+    /**
+     * @see ApplicationInfo#networkSecurityConfigRes
+     * @see R.styleable#AndroidManifestApplication_networkSecurityConfig
+     */
+    int getNetworkSecurityConfigRes();
+
+    /**
+     * If {@link R.styleable#AndroidManifestApplication_label} is a string literal, this is it.
+     * Otherwise, it's stored as {@link #getLabelRes()}.
+     * @see ApplicationInfo#nonLocalizedLabel
+     * @see R.styleable#AndroidManifestApplication_label
+     */
+    @Nullable
+    CharSequence getNonLocalizedLabel();
+
+    /**
+     * @see PackageInfo#overlayCategory
+     * @see R.styleable#AndroidManifestResourceOverlay_category
+     */
+    @Nullable
+    String getOverlayCategory();
+
+    /** @see PackageInfo#mOverlayIsStatic */
+    boolean isOverlayIsStatic();
+
+    /**
+     * @see PackageInfo#overlayPriority
+     * @see R.styleable#AndroidManifestResourceOverlay_priority
+     */
+    int getOverlayPriority();
+
+    /**
+     * @see PackageInfo#overlayTarget
+     * @see R.styleable#AndroidManifestResourceOverlay_targetPackage
+     */
+    @Nullable
+    String getOverlayTarget();
+
+    /**
+     * @see PackageInfo#targetOverlayableName
+     * @see R.styleable#AndroidManifestResourceOverlay_targetName
+     */
+    @Nullable
+    String getOverlayTargetName();
+
+    /**
+     * If a system app declares {@link #getOriginalPackages()}, and the app was previously installed
+     * under one of those original package names, the {@link #getPackageName()} system identifier
+     * will be changed to that previously installed name. This will then be non-null, set to the
+     * manifest package name, for tracking the package under its true name.
+     *
+     * TODO(b/135203078): Remove this in favor of checking originalPackages.isEmpty and
+     *  getManifestPackageName
+     */
+    @Nullable
+    String getRealPackage();
+
+    /**
+     * The required account type without which this application will not function.
+     *
+     * @see PackageInfo#requiredAccountType
+     * @see R.styleable#AndroidManifestApplication_requiredAccountType
+     */
+    @Nullable
+    String getRequiredAccountType();
+
+    /**
+     * @see PackageInfo#requiredForAllUsers
+     * @see R.styleable#AndroidManifestApplication_requiredForAllUsers
+     */
+    boolean isRequiredForAllUsers();
+
+    /**
+     * @see ApplicationInfo#requiresSmallestWidthDp
+     * @see R.styleable#AndroidManifestSupportsScreens_requiresSmallestWidthDp
+     */
+    int getRequiresSmallestWidthDp();
+
+    /**
+     * SHA-512 hash of the only APK that can be used to update a system package.
+     * @see R.styleable#AndroidManifestRestrictUpdate
+     */
+    @Nullable
+    byte[] getRestrictUpdateHash();
+
+    /**
+     * The restricted account authenticator type that is used by this application
+     *
+     * @see PackageInfo#restrictedAccountType
+     * @see R.styleable#AndroidManifestApplication_restrictedAccountType
+     */
+    @Nullable
+    String getRestrictedAccountType();
+
+    /**
+     * @see ApplicationInfo#roundIconRes
+     * @see R.styleable#AndroidManifestApplication_roundIcon
+     */
+    int getRoundIconRes();
+
+    /**
+     * @see PackageInfo#sharedUserLabel
+     * @see R.styleable#AndroidManifest_sharedUserLabel
+     */
+    @Deprecated
+    int getSharedUserLabel();
+
+    /**
+     * The signature data of all APKs in this package, which must be exactly the same across the
+     * base and splits.
+     */
+    PackageParser.SigningDetails getSigningDetails();
+
+    /**
+     * @see ApplicationInfo#splitClassLoaderNames
+     * @see R.styleable#AndroidManifestApplication_classLoader
+     */
+    @Nullable
+    String[] getSplitClassLoaderNames();
+
+    /** @see R.styleable#AndroidManifestStaticLibrary_version */
+    long getStaticSharedLibVersion();
+
+    /**
+     * If omitted from manifest, returns true if {@link #getTargetSdkVersion()} >=
+     * {@link android.os.Build.VERSION_CODES#DONUT}.
+     * @see R.styleable#AndroidManifestSupportsScreens_largeScreens
+     * @see ApplicationInfo#FLAG_SUPPORTS_LARGE_SCREENS
+     */
+    boolean isSupportsLargeScreens();
+
+    /**
+     * If omitted from manifest, returns true.
+     * @see R.styleable#AndroidManifestSupportsScreens_normalScreens
+     * @see ApplicationInfo#FLAG_SUPPORTS_NORMAL_SCREENS
+     */
+    boolean isSupportsNormalScreens();
+
+    /**
+     * If omitted from manifest, returns true if {@link #getTargetSdkVersion()} >=
+     * {@link android.os.Build.VERSION_CODES#DONUT}.
+     * @see R.styleable#AndroidManifestSupportsScreens_smallScreens
+     * @see ApplicationInfo#FLAG_SUPPORTS_SMALL_SCREENS
+     */
+    boolean isSupportsSmallScreens();
+
+    /**
+     * If omitted from manifest, returns true if {@link #getTargetSdkVersion()} >=
+     * {@link android.os.Build.VERSION_CODES#GINGERBREAD}.
+     * @see R.styleable#AndroidManifestSupportsScreens_xlargeScreens
+     * @see ApplicationInfo#FLAG_SUPPORTS_XLARGE_SCREENS
+     */
+    boolean isSupportsExtraLargeScreens();
+
+    /** @see ApplicationInfo#PRIVATE_FLAG_ALLOW_NATIVE_HEAP_POINTER_TAGGING */
+    boolean isAllowNativeHeapPointerTagging();
+
+    boolean hasPreserveLegacyExternalStorage();
+
+    /**
+     * @see ApplicationInfo#targetSandboxVersion
+     * @see R.styleable#AndroidManifest_targetSandboxVersion
+     */
+    @Deprecated
+    int getTargetSandboxVersion();
+
+    /**
+     * @see ApplicationInfo#theme
+     * @see R.styleable#AndroidManifestApplication_theme
+     */
+    int getTheme();
+
+    /**
+     * For use with {@link com.android.server.pm.KeySetManagerService}. Parsed in
+     * {@link PackageParser#TAG_KEY_SETS}.
+     * @see R.styleable#AndroidManifestUpgradeKeySet
+     */
+    @NonNull
+    Set<String> getUpgradeKeySets();
+
+    /**
+     * The install time abi override to choose 32bit abi's when multiple abi's
+     * are present. This is only meaningfull for multiarch applications.
+     * The use32bitAbi attribute is ignored if cpuAbiOverride is also set.
+     */
+    boolean isUse32BitAbi();
+
+    /** @see ApplicationInfo#volumeUuid */
+    @Nullable
+    String getVolumeUuid();
+
+    /** @see ApplicationInfo#zygotePreloadName */
+    @Nullable
+    String getZygotePreloadName();
+
+    /** Revision code of base APK */
+    int getBaseRevisionCode();
+
+    /** @see PackageInfo#versionName */
+    @Nullable
+    String getVersionName();
+
+    /** @see PackageInfo#versionCodeMajor */
+    @Nullable
+    int getVersionCode();
+
+    /** @see PackageInfo#versionCodeMajor */
+    @Nullable
+    int getVersionCodeMajor();
+
+    /**
+     * @see ApplicationInfo#compileSdkVersion
+     * @see R.styleable#AndroidManifest_compileSdkVersion
+     */
+    int getCompileSdkVersion();
+
+    /**
+     * @see ApplicationInfo#compileSdkVersionCodename
+     * @see R.styleable#AndroidManifest_compileSdkVersionCodename
+     */
+    @Nullable
+    String getCompileSdkVersionCodeName();
+
+    @Nullable
+    Set<String> getMimeGroups();
+
+    // TODO(b/135203078): Hide and enforce going through PackageInfoUtils
+    ApplicationInfo toAppInfoWithoutState();
+}
diff --git a/core/java/android/content/pm/parsing/ParsingPackageUtils.java b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
new file mode 100644
index 0000000..40754df
--- /dev/null
+++ b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
@@ -0,0 +1,2673 @@
+/*
+ * 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 static android.content.pm.ActivityInfo.FLAG_SUPPORTS_PICTURE_IN_PICTURE;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
+import static android.content.pm.PackageManager.FEATURE_WATCH;
+import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST;
+import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
+import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_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 android.annotation.AnyRes;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.StyleableRes;
+import android.app.ActivityThread;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.ConfigurationInfo;
+import android.content.pm.FeatureGroupInfo;
+import android.content.pm.FeatureInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageParser;
+import android.content.pm.PackageParser.PackageParserException;
+import android.content.pm.PackageParser.SigningDetails;
+import android.content.pm.Signature;
+import android.content.pm.parsing.component.ComponentParseUtils;
+import android.content.pm.parsing.component.ParsedActivity;
+import android.content.pm.parsing.component.ParsedActivityUtils;
+import android.content.pm.parsing.component.ParsedFeature;
+import android.content.pm.parsing.component.ParsedFeatureUtils;
+import android.content.pm.parsing.component.ParsedInstrumentation;
+import android.content.pm.parsing.component.ParsedInstrumentationUtils;
+import android.content.pm.parsing.component.ParsedIntentInfo;
+import android.content.pm.parsing.component.ParsedIntentInfoUtils;
+import android.content.pm.parsing.component.ParsedMainComponent;
+import android.content.pm.parsing.component.ParsedPermission;
+import android.content.pm.parsing.component.ParsedPermissionGroup;
+import android.content.pm.parsing.component.ParsedPermissionUtils;
+import android.content.pm.parsing.component.ParsedProcess;
+import android.content.pm.parsing.component.ParsedProcessUtils;
+import android.content.pm.parsing.component.ParsedProvider;
+import android.content.pm.parsing.component.ParsedProviderUtils;
+import android.content.pm.parsing.component.ParsedService;
+import android.content.pm.parsing.component.ParsedServiceUtils;
+import android.content.pm.parsing.result.ParseInput;
+import android.content.pm.parsing.result.ParseResult;
+import android.content.pm.permission.SplitPermissionInfoParcelable;
+import android.content.pm.split.DefaultSplitAssetLoader;
+import android.content.pm.split.SplitAssetDependencyLoader;
+import android.content.pm.split.SplitAssetLoader;
+import android.content.res.ApkAssets;
+import android.content.res.AssetManager;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.FileUtils;
+import android.os.RemoteException;
+import android.os.SystemProperties;
+import android.os.Trace;
+import android.os.ext.SdkExtensions;
+import android.text.TextUtils;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.AttributeSet;
+import android.util.DisplayMetrics;
+import android.util.Pair;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.util.TypedValue;
+import android.util.apk.ApkSignatureVerifier;
+
+import com.android.internal.R;
+import com.android.internal.os.ClassLoaderFactory;
+import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.XmlUtils;
+
+import libcore.io.IoUtils;
+import libcore.util.EmptyArray;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.File;
+import java.io.IOException;
+import java.security.PublicKey;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.StringTokenizer;
+
+/**
+ * TODO(b/135203078): Differentiate between parse_ methods and some add_ method for whether it
+ * mutates the passed-in component or not. Or consolidate so all parse_ methods mutate.
+ *
+ * @hide
+ */
+public class ParsingPackageUtils {
+
+    public static final String TAG = ParsingUtils.TAG;
+
+    private boolean mOnlyCoreApps;
+    private String[] mSeparateProcesses;
+    private DisplayMetrics mDisplayMetrics;
+    private Callback mCallback;
+
+    public ParsingPackageUtils(boolean onlyCoreApps, String[] separateProcesses,
+            DisplayMetrics displayMetrics, @NonNull Callback callback) {
+        mOnlyCoreApps = onlyCoreApps;
+        mSeparateProcesses = separateProcesses;
+        mDisplayMetrics = displayMetrics;
+        mCallback = callback;
+    }
+
+    /**
+     * Parse the package at the given location. Automatically detects if the
+     * package is a monolithic style (single APK file) or cluster style
+     * (directory of APKs).
+     * <p>
+     * This performs sanity checking on cluster style packages, such as
+     * requiring identical package name and version codes, a single base APK,
+     * and unique split names.
+     * <p>
+     * Note that this <em>does not</em> perform signature verification; that
+     * must be done separately in {@link #collectCertificates(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
+     * {@code flags}. Note that this method does not check whether {@code packageFile}
+     * has changed since the last parse, it's up to callers to do so.
+     *
+     * @see PackageParser#parsePackageLite(File, int)
+     */
+    public ParseResult<ParsingPackage> parsePackage(ParseInput input, File packageFile,
+            int flags)
+            throws PackageParserException {
+        if (packageFile.isDirectory()) {
+            return parseClusterPackage(input, packageFile, flags);
+        } else {
+            return parseMonolithicPackage(input, packageFile, flags);
+        }
+    }
+
+    /**
+     * Parse all APKs contained in the given directory, treating them as a
+     * single package. This also performs sanity checking, such as requiring
+     * identical package name and version codes, a single base APK, and unique
+     * split names.
+     * <p>
+     * Note that this <em>does not</em> perform signature verification; that
+     * must be done separately in {@link #collectCertificates(ParsingPackageRead, boolean)}.
+     */
+    private ParseResult<ParsingPackage> parseClusterPackage(ParseInput input, File packageDir,
+            int flags) throws PackageParserException {
+        final PackageParser.PackageLite lite = ApkLiteParseUtils.parseClusterPackageLite(packageDir,
+                0);
+        if (mOnlyCoreApps && !lite.coreApp) {
+            return input.error("Not a coreApp: " + packageDir);
+        }
+
+        // Build the split dependency tree.
+        SparseArray<int[]> splitDependencies = null;
+        final SplitAssetLoader assetLoader;
+        if (lite.isolatedSplits && !ArrayUtils.isEmpty(lite.splitNames)) {
+            try {
+                splitDependencies = SplitAssetDependencyLoader.createDependenciesFromPackage(lite);
+                assetLoader = new SplitAssetDependencyLoader(lite, splitDependencies, flags);
+            } catch (SplitAssetDependencyLoader.IllegalDependencyException e) {
+                return input.error(INSTALL_PARSE_FAILED_BAD_MANIFEST, e.getMessage());
+            }
+        } else {
+            assetLoader = new DefaultSplitAssetLoader(lite, flags);
+        }
+
+        try {
+            final AssetManager assets = assetLoader.getBaseAssetManager();
+            final File baseApk = new File(lite.baseCodePath);
+            ParseResult<ParsingPackage> result = parseBaseApk(input, baseApk,
+                    lite.codePath, assets, flags);
+            // TODO(b/135203078): Pass original error up?
+            if (result.isError()) {
+                return input.error(INSTALL_PARSE_FAILED_NOT_APK,
+                        "Failed to parse base APK: " + baseApk);
+            }
+
+            ParsingPackage pkg = result.getResult();
+            if (!ArrayUtils.isEmpty(lite.splitNames)) {
+                pkg.asSplit(
+                        lite.splitNames,
+                        lite.splitCodePaths,
+                        lite.splitRevisionCodes,
+                        splitDependencies
+                );
+                final int num = lite.splitNames.length;
+
+                for (int i = 0; i < num; i++) {
+                    final AssetManager splitAssets = assetLoader.getSplitAssetManager(i);
+                    parseSplitApk(input, pkg, i, splitAssets, flags);
+                }
+            }
+
+            pkg.setUse32BitAbi(lite.use32bitAbi);
+            return input.success(pkg);
+        } finally {
+            IoUtils.closeQuietly(assetLoader);
+        }
+    }
+
+    /**
+     * Parse the given APK file, treating it as as a single monolithic package.
+     * <p>
+     * Note that this <em>does not</em> perform signature verification; that
+     * must be done separately in {@link #collectCertificates(ParsingPackageRead, boolean)}.
+     */
+    private ParseResult<ParsingPackage> parseMonolithicPackage(ParseInput input, File apkFile,
+            int flags) throws PackageParserException {
+        final PackageParser.PackageLite lite = ApkLiteParseUtils.parseMonolithicPackageLite(apkFile,
+                flags);
+        if (mOnlyCoreApps && !lite.coreApp) {
+            return input.error("Not a coreApp: " + apkFile);
+        }
+
+        final SplitAssetLoader assetLoader = new DefaultSplitAssetLoader(lite, flags);
+        try {
+            ParseResult<ParsingPackage> result = parseBaseApk(input,
+                    apkFile,
+                    apkFile.getCanonicalPath(),
+                    assetLoader.getBaseAssetManager(), flags);
+            if (result.isError()) {
+                return input.error(result);
+            }
+
+            return input.success(result.getResult()
+                    .setUse32BitAbi(lite.use32bitAbi));
+        } catch (IOException e) {
+            return input.error(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
+                    "Failed to get path: " + apkFile, e);
+        } finally {
+            IoUtils.closeQuietly(assetLoader);
+        }
+    }
+
+    private ParseResult<ParsingPackage> parseBaseApk(ParseInput input, File apkFile,
+            String codePath, AssetManager assets, int flags) {
+        final String apkPath = apkFile.getAbsolutePath();
+
+        String volumeUuid = null;
+        if (apkPath.startsWith(PackageParser.MNT_EXPAND)) {
+            final int end = apkPath.indexOf('/', PackageParser.MNT_EXPAND.length());
+            volumeUuid = apkPath.substring(PackageParser.MNT_EXPAND.length(), end);
+        }
+
+        if (PackageParser.DEBUG_JAR) Slog.d(TAG, "Scanning base APK: " + apkPath);
+
+        final int cookie = assets.findCookieForPath(apkPath);
+        if (cookie == 0) {
+            return input.error(INSTALL_PARSE_FAILED_BAD_MANIFEST,
+                    "Failed adding asset path: " + apkPath);
+        }
+
+        try (XmlResourceParser parser = assets.openXmlResourceParser(cookie,
+                PackageParser.ANDROID_MANIFEST_FILENAME)) {
+            final Resources res = new Resources(assets, mDisplayMetrics, null);
+
+            ParseResult<ParsingPackage> result = parseBaseApk(input, apkPath, codePath, res,
+                    parser, flags);
+            if (result.isError()) {
+                return input.error(result.getErrorCode(),
+                        apkPath + " (at " + parser.getPositionDescription() + "): "
+                                + result.getErrorMessage());
+            }
+
+            ParsingPackage pkg = result.getResult();
+            ApkAssets apkAssets = assets.getApkAssets()[0];
+            if (apkAssets.definesOverlayable()) {
+                SparseArray<String> packageNames = assets.getAssignedPackageIdentifiers();
+                int size = packageNames.size();
+                for (int index = 0; index < size; index++) {
+                    String packageName = packageNames.get(index);
+                    Map<String, String> overlayableToActor = assets.getOverlayableMap(packageName);
+                    if (overlayableToActor != null && !overlayableToActor.isEmpty()) {
+                        for (String overlayable : overlayableToActor.keySet()) {
+                            pkg.addOverlayable(overlayable, overlayableToActor.get(overlayable));
+                        }
+                    }
+                }
+            }
+
+            pkg.setVolumeUuid(volumeUuid)
+                    .setSigningDetails(SigningDetails.UNKNOWN);
+
+            return input.success(pkg);
+        } catch (Exception e) {
+            return input.error(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
+                    "Failed to read manifest from " + apkPath, e);
+        }
+    }
+
+    private ParseResult<ParsingPackage> parseSplitApk(ParseInput input,
+            ParsingPackage pkg, int splitIndex, AssetManager assets, int flags) {
+        final String apkPath = pkg.getSplitCodePaths()[splitIndex];
+
+        if (PackageParser.DEBUG_JAR) Slog.d(TAG, "Scanning split APK: " + apkPath);
+
+        // This must always succeed, as the path has been added to the AssetManager before.
+        final int cookie = assets.findCookieForPath(apkPath);
+        if (cookie == 0) {
+            return input.error(INSTALL_PARSE_FAILED_BAD_MANIFEST,
+                    "Failed adding asset path: " + apkPath);
+        }
+        try (XmlResourceParser parser = assets.openXmlResourceParser(cookie,
+                PackageParser.ANDROID_MANIFEST_FILENAME)) {
+            Resources res = new Resources(assets, mDisplayMetrics, null);
+            ParseResult<ParsingPackage> parseResult = parseSplitApk(input, pkg, res,
+                    parser, flags, splitIndex);
+            if (parseResult.isError()) {
+                return input.error(parseResult.getErrorCode(),
+                        apkPath + " (at " + parser.getPositionDescription() + "): "
+                                + parseResult.getErrorMessage());
+            }
+
+            return parseResult;
+        } catch (Exception e) {
+            return input.error(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
+                    "Failed to read manifest from " + apkPath, e);
+        }
+    }
+
+    /**
+     * Parse the manifest of a <em>base APK</em>. When adding new features you
+     * need to consider whether they should be supported by split APKs and child
+     * packages.
+     *
+     * @param apkPath The package apk file path
+     * @param res     The resources from which to resolve values
+     * @param parser  The manifest parser
+     * @param flags   Flags how to parse
+     * @return Parsed package or null on error.
+     */
+    private ParseResult<ParsingPackage> parseBaseApk(ParseInput input, String apkPath,
+            String codePath, Resources res, XmlResourceParser parser, int flags)
+            throws XmlPullParserException, IOException {
+        final String splitName;
+        final String pkgName;
+
+        try {
+            Pair<String, String> packageSplit = PackageParser.parsePackageSplitNames(parser,
+                    parser);
+            pkgName = packageSplit.first;
+            splitName = packageSplit.second;
+
+            if (!TextUtils.isEmpty(splitName)) {
+                return input.error(
+                        PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,
+                        "Expected base APK, but found split " + splitName
+                );
+            }
+        } catch (PackageParserException e) {
+            return input.error(PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME);
+        }
+
+        TypedArray manifestArray = res.obtainAttributes(parser, R.styleable.AndroidManifest);
+        try {
+            boolean isCoreApp = parser.getAttributeBooleanValue(null, "coreApp", false);
+
+            ParsingPackage pkg = mCallback.startParsingPackage(pkgName, apkPath, codePath,
+                    manifestArray, isCoreApp);
+
+            ParseResult<ParsingPackage> result = parseBaseApkTags(input, pkg, manifestArray,
+                    res, parser, flags);
+            if (result.isError()) {
+                return result;
+            }
+
+            return input.success(pkg);
+        } finally {
+            manifestArray.recycle();
+        }
+    }
+
+    /**
+     * Parse the manifest of a <em>split APK</em>.
+     * <p>
+     * Note that split APKs have many more restrictions on what they're capable
+     * of doing, so many valid features of a base APK have been carefully
+     * omitted here.
+     *
+     * @param pkg builder to fill
+     * @return false on failure
+     */
+    private ParseResult<ParsingPackage> parseSplitApk(ParseInput input, ParsingPackage pkg,
+            Resources res, XmlResourceParser parser, int flags, int splitIndex)
+            throws XmlPullParserException, IOException, PackageParserException {
+        AttributeSet attrs = parser;
+
+        // We parsed manifest tag earlier; just skip past it
+        PackageParser.parsePackageSplitNames(parser, attrs);
+
+        int type;
+
+        boolean foundApp = false;
+
+        int outerDepth = parser.getDepth();
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
+            if (outerDepth + 1 < parser.getDepth() || type != XmlPullParser.START_TAG) {
+                continue;
+            }
+
+            final ParseResult result;
+            String tagName = parser.getName();
+            if (PackageParser.TAG_APPLICATION.equals(tagName)) {
+                if (foundApp) {
+                    if (PackageParser.RIGID_PARSER) {
+                        result = input.error("<manifest> has more than one <application>");
+                    } else {
+                        Slog.w(TAG, "<manifest> has more than one <application>");
+                        result = input.success(null);
+                    }
+                } else {
+                    foundApp = true;
+                    result = parseSplitApplication(input, pkg, res, parser, flags, splitIndex);
+                }
+            } else {
+                result = ParsingUtils.unknownTag("<manifest>", pkg, parser, input);
+            }
+
+            if (result.isError()) {
+                return input.error(result);
+            }
+        }
+
+        if (!foundApp) {
+            return input.error(
+                    PackageManager.INSTALL_PARSE_FAILED_MANIFEST_EMPTY,
+                    "<manifest> does not contain an <application>"
+            );
+        }
+
+        return input.success(pkg);
+    }
+
+    /**
+     * Parse the {@code application} XML tree at the current parse location in a
+     * <em>split APK</em> manifest.
+     * <p>
+     * Note that split APKs have many more restrictions on what they're capable
+     * of doing, so many valid features of a base APK have been carefully
+     * omitted here.
+     */
+    private ParseResult<ParsingPackage> parseSplitApplication(ParseInput input,
+            ParsingPackage pkg, Resources res, XmlResourceParser parser, int flags, int splitIndex)
+            throws XmlPullParserException, IOException {
+        TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestApplication);
+        try {
+            pkg.setSplitHasCode(splitIndex, sa.getBoolean(
+                    R.styleable.AndroidManifestApplication_hasCode, true));
+
+            final String classLoaderName = sa.getString(
+                    R.styleable.AndroidManifestApplication_classLoader);
+            if (classLoaderName == null || ClassLoaderFactory.isValidClassLoaderName(
+                    classLoaderName)) {
+                pkg.setSplitClassLoaderName(splitIndex, classLoaderName);
+            } else {
+                return input.error("Invalid class loader name: " + classLoaderName);
+            }
+        } finally {
+            sa.recycle();
+        }
+        final int depth = parser.getDepth();
+        int type;
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG
+                || parser.getDepth() > depth)) {
+            if (type != XmlPullParser.START_TAG) {
+                continue;
+            }
+
+            ParsedMainComponent mainComponent = null;
+
+            final ParseResult result;
+            String tagName = parser.getName();
+            boolean isActivity = false;
+            switch (tagName) {
+                case "activity":
+                    isActivity = true;
+                    // fall-through
+                case "receiver":
+                    ParseResult<ParsedActivity> activityResult =
+                            ParsedActivityUtils.parseActivityOrReceiver(mSeparateProcesses, pkg,
+                                    res,
+                                    parser, flags, PackageParser.sUseRoundIcon, input);
+                    if (activityResult.isSuccess()) {
+                        ParsedActivity activity = activityResult.getResult();
+                        if (isActivity) {
+                            pkg.addActivity(activity);
+                        } else {
+                            pkg.addReceiver(activity);
+                        }
+                        mainComponent = activity;
+                    }
+                    result = activityResult;
+                    break;
+                case "service":
+                    ParseResult<ParsedService> serviceResult = ParsedServiceUtils.parseService(
+                            mSeparateProcesses, pkg, res, parser, flags,
+                            PackageParser.sUseRoundIcon, input);
+                    if (serviceResult.isSuccess()) {
+                        ParsedService service = serviceResult.getResult();
+                        pkg.addService(service);
+                        mainComponent = service;
+                    }
+                    result = serviceResult;
+                    break;
+                case "provider":
+                    ParseResult<ParsedProvider> providerResult =
+                            ParsedProviderUtils.parseProvider(mSeparateProcesses, pkg, res, parser,
+                                    flags, PackageParser.sUseRoundIcon, input);
+                    if (providerResult.isSuccess()) {
+                        ParsedProvider provider = providerResult.getResult();
+                        pkg.addProvider(provider);
+                        mainComponent = provider;
+                    }
+                    result = providerResult;
+                    break;
+                case "activity-alias":
+                    activityResult = ParsedActivityUtils.parseActivityAlias(pkg, res, parser,
+                            PackageParser.sUseRoundIcon, input);
+                    if (activityResult.isSuccess()) {
+                        ParsedActivity activity = activityResult.getResult();
+                        pkg.addActivity(activity);
+                        mainComponent = activity;
+                    }
+
+                    result = activityResult;
+                    break;
+                default:
+                    result = parseSplitBaseAppChildTags(input, tagName, pkg, res, parser);
+                    break;
+            }
+
+            if (result.isError()) {
+                return input.error(result);
+            }
+
+            if (mainComponent != null && mainComponent.getSplitName() == null) {
+                // If the loaded component did not specify a split, inherit the split name
+                // based on the split it is defined in.
+                // This is used to later load the correct split when starting this
+                // component.
+                mainComponent.setSplitName(pkg.getSplitNames()[splitIndex]);
+            }
+        }
+
+        return input.success(pkg);
+    }
+
+    /**
+     * For parsing non-MainComponents. Main ones have an order and some special handling which is
+     * done directly in {@link #parseSplitApplication(ParseInput, ParsingPackage, Resources,
+     * XmlResourceParser, int, int)}.
+     */
+    private ParseResult parseSplitBaseAppChildTags(ParseInput input, String tag, ParsingPackage pkg,
+            Resources res, XmlResourceParser parser) throws IOException, XmlPullParserException {
+        switch (tag) {
+            case "meta-data":
+                // note: application meta-data is stored off to the side, so it can
+                // remain null in the primary copy (we like to avoid extra copies because
+                // it can be large)
+                ParseResult<Bundle> metaDataResult = parseMetaData(pkg, res, parser,
+                        pkg.getMetaData(), input);
+                if (metaDataResult.isSuccess()) {
+                    pkg.setMetaData(metaDataResult.getResult());
+                }
+                return metaDataResult;
+            case "uses-static-library":
+                return parseUsesStaticLibrary(input, pkg, res, parser);
+            case "uses-library":
+                return parseUsesLibrary(input, pkg, res, parser);
+            case "uses-package":
+                // Dependencies for app installers; we don't currently try to
+                // enforce this.
+                return input.success(null);
+            default:
+                return ParsingUtils.unknownTag("<application>", pkg, parser, input);
+        }
+    }
+
+    private ParseResult<ParsingPackage> parseBaseApkTags(ParseInput input, ParsingPackage pkg,
+            TypedArray sa, Resources res, XmlResourceParser parser, int flags)
+            throws XmlPullParserException, IOException {
+        ParseResult<ParsingPackage> sharedUserResult = parseSharedUser(input, pkg, sa);
+        if (sharedUserResult.isError()) {
+            return sharedUserResult;
+        }
+
+        pkg.setInstallLocation(anInt(PackageParser.PARSE_DEFAULT_INSTALL_LOCATION,
+                R.styleable.AndroidManifest_installLocation, sa))
+                .setTargetSandboxVersion(anInt(PackageParser.PARSE_DEFAULT_TARGET_SANDBOX,
+                        R.styleable.AndroidManifest_targetSandboxVersion, sa))
+                /* Set the global "on SD card" flag */
+                .setExternalStorage((flags & PackageParser.PARSE_EXTERNAL_STORAGE) != 0)
+                .setIsolatedSplitLoading(
+                        bool(false, R.styleable.AndroidManifest_isolatedSplits, sa));
+
+        boolean foundApp = false;
+        final int depth = parser.getDepth();
+        int type;
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG
+                || parser.getDepth() > depth)) {
+            if (type != XmlPullParser.START_TAG) {
+                continue;
+            }
+
+            String tagName = parser.getName();
+            final ParseResult result;
+
+            // TODO(b/135203078): Convert to instance methods to share variables
+            // <application> has special logic, so it's handled outside the general method
+            if (PackageParser.TAG_APPLICATION.equals(tagName)) {
+                if (foundApp) {
+                    if (PackageParser.RIGID_PARSER) {
+                        result = input.error("<manifest> has more than one <application>");
+                    } else {
+                        Slog.w(TAG, "<manifest> has more than one <application>");
+                        result = input.success(null);
+                    }
+                } else {
+                    foundApp = true;
+                    result = parseBaseApplication(input, pkg, res, parser, flags);
+                }
+            } else {
+                result = parseBaseApkTag(tagName, input, pkg, res, parser, flags);
+            }
+
+            if (result.isError()) {
+                return input.error(result);
+            }
+        }
+
+        if (!foundApp && ArrayUtils.size(pkg.getInstrumentations()) == 0) {
+            return input.error(
+                    PackageManager.INSTALL_PARSE_FAILED_MANIFEST_EMPTY,
+                    "<manifest> does not contain an <application> or <instrumentation>"
+            );
+        }
+
+        if (!ParsedFeature.isCombinationValid(pkg.getFeatures())) {
+            return input.error(
+                    INSTALL_PARSE_FAILED_BAD_MANIFEST,
+                    "Combination <feature> tags are not valid"
+            );
+        }
+
+        convertNewPermissions(pkg);
+
+        convertSplitPermissions(pkg);
+
+        // 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 (pkg.getTargetSdkVersion() < DONUT
+                || (!pkg.isSupportsSmallScreens()
+                && !pkg.isSupportsNormalScreens()
+                && !pkg.isSupportsLargeScreens()
+                && !pkg.isSupportsExtraLargeScreens()
+                && !pkg.isResizeable()
+                && !pkg.isAnyDensity())) {
+            adjustPackageToBeUnresizeableAndUnpipable(pkg);
+        }
+
+        return input.success(pkg);
+    }
+
+    private ParseResult parseBaseApkTag(String tag, ParseInput input,
+            ParsingPackage pkg, Resources res, XmlResourceParser parser, int flags)
+            throws IOException, XmlPullParserException {
+        switch (tag) {
+            case PackageParser.TAG_OVERLAY:
+                return parseOverlay(input, pkg, res, parser);
+            case PackageParser.TAG_KEY_SETS:
+                return parseKeySets(input, pkg, res, parser);
+            case PackageParser.TAG_FEATURE:
+                return parseFeature(input, pkg, res, parser);
+            case PackageParser.TAG_PERMISSION_GROUP:
+                return parsePermissionGroup(input, pkg, res, parser);
+            case PackageParser.TAG_PERMISSION:
+                return parsePermission(input, pkg, res, parser);
+            case PackageParser.TAG_PERMISSION_TREE:
+                return parsePermissionTree(input, pkg, res, parser);
+            case PackageParser.TAG_USES_PERMISSION:
+            case PackageParser.TAG_USES_PERMISSION_SDK_M:
+            case PackageParser.TAG_USES_PERMISSION_SDK_23:
+                return parseUsesPermission(input, pkg, res, parser);
+            case PackageParser.TAG_USES_CONFIGURATION:
+                return parseUsesConfiguration(input, pkg, res, parser);
+            case PackageParser.TAG_USES_FEATURE:
+                return parseUsesFeature(input, pkg, res, parser);
+            case PackageParser.TAG_FEATURE_GROUP:
+                return parseFeatureGroup(input, pkg, res, parser);
+            case PackageParser.TAG_USES_SDK:
+                return parseUsesSdk(input, pkg, res, parser);
+            case PackageParser.TAG_SUPPORT_SCREENS:
+                return parseSupportScreens(input, pkg, res, parser);
+            case PackageParser.TAG_PROTECTED_BROADCAST:
+                return parseProtectedBroadcast(input, pkg, res, parser);
+            case PackageParser.TAG_INSTRUMENTATION:
+                return parseInstrumentation(input, pkg, res, parser);
+            case PackageParser.TAG_ORIGINAL_PACKAGE:
+                return parseOriginalPackage(input, pkg, res, parser);
+            case PackageParser.TAG_ADOPT_PERMISSIONS:
+                return parseAdoptPermissions(input, pkg, res, parser);
+            case PackageParser.TAG_USES_GL_TEXTURE:
+            case PackageParser.TAG_COMPATIBLE_SCREENS:
+            case PackageParser.TAG_SUPPORTS_INPUT:
+            case PackageParser.TAG_EAT_COMMENT:
+                // Just skip this tag
+                XmlUtils.skipCurrentTag(parser);
+                return input.success(pkg);
+            case PackageParser.TAG_RESTRICT_UPDATE:
+                return parseRestrictUpdateHash(flags, input, pkg, res, parser);
+            case PackageParser.TAG_QUERIES:
+                return parseQueries(input, pkg, res, parser);
+            default:
+                return ParsingUtils.unknownTag("<manifest>", pkg, parser, input);
+        }
+    }
+
+    private static ParseResult<ParsingPackage> parseSharedUser(ParseInput input,
+            ParsingPackage pkg, TypedArray sa) {
+        String str = nonConfigString(0, R.styleable.AndroidManifest_sharedUserId, sa);
+        if (TextUtils.isEmpty(str)) {
+            return input.success(pkg);
+        }
+
+        ParseResult nameResult = validateName(input, str, true, true);
+        if (nameResult.isError()) {
+            if ("android".equals(pkg.getPackageName())) {
+                nameResult.ignoreError();
+            } else {
+                return input.error(PackageManager.INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID,
+                        "<manifest> specifies bad sharedUserId name \"" + str + "\": "
+                                + nameResult.getErrorMessage());
+            }
+        }
+
+        return input.success(pkg
+                .setSharedUserId(str.intern())
+                .setSharedUserLabel(resId(R.styleable.AndroidManifest_sharedUserLabel, sa)));
+    }
+
+    private static ParseResult<ParsingPackage> parseKeySets(ParseInput input,
+            ParsingPackage pkg, Resources res, XmlResourceParser parser)
+            throws XmlPullParserException, IOException {
+        // we've encountered the 'key-sets' tag
+        // all the keys and keysets that we want must be defined here
+        // so we're going to iterate over the parser and pull out the things we want
+        int outerDepth = parser.getDepth();
+        int currentKeySetDepth = -1;
+        int type;
+        String currentKeySet = null;
+        ArrayMap<String, PublicKey> publicKeys = new ArrayMap<>();
+        ArraySet<String> upgradeKeySets = new ArraySet<>();
+        ArrayMap<String, ArraySet<String>> definedKeySets = new ArrayMap<>();
+        ArraySet<String> improperKeySets = new ArraySet<>();
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+            if (type == XmlPullParser.END_TAG) {
+                if (parser.getDepth() == currentKeySetDepth) {
+                    currentKeySet = null;
+                    currentKeySetDepth = -1;
+                }
+                continue;
+            }
+            String tagName = parser.getName();
+            switch (tagName) {
+                case "key-set": {
+                    if (currentKeySet != null) {
+                        return input.error("Improperly nested 'key-set' tag at "
+                                + parser.getPositionDescription());
+                    }
+                    TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestKeySet);
+                    try {
+                        final String keysetName = sa.getNonResourceString(
+                                R.styleable.AndroidManifestKeySet_name);
+                        definedKeySets.put(keysetName, new ArraySet<>());
+                        currentKeySet = keysetName;
+                        currentKeySetDepth = parser.getDepth();
+                    } finally {
+                        sa.recycle();
+                    }
+                } break;
+                case "public-key": {
+                    if (currentKeySet == null) {
+                        return input.error("Improperly nested 'key-set' tag at "
+                                + parser.getPositionDescription());
+                    }
+                    TypedArray sa = res.obtainAttributes(parser,
+                            R.styleable.AndroidManifestPublicKey);
+                    try {
+                        final String publicKeyName = nonResString(
+                                R.styleable.AndroidManifestPublicKey_name, sa);
+                        final String encodedKey = nonResString(
+                                R.styleable.AndroidManifestPublicKey_value, sa);
+                        if (encodedKey == null && publicKeys.get(publicKeyName) == null) {
+                            return input.error("'public-key' " + publicKeyName
+                                    + " must define a public-key value on first use at "
+                                    + parser.getPositionDescription());
+                        } else if (encodedKey != null) {
+                            PublicKey currentKey = PackageParser.parsePublicKey(encodedKey);
+                            if (currentKey == null) {
+                                Slog.w(TAG, "No recognized valid key in 'public-key' tag at "
+                                        + parser.getPositionDescription() + " key-set "
+                                        + currentKeySet
+                                        + " will not be added to the package's defined key-sets.");
+                                improperKeySets.add(currentKeySet);
+                                XmlUtils.skipCurrentTag(parser);
+                                continue;
+                            }
+                            if (publicKeys.get(publicKeyName) == null
+                                    || publicKeys.get(publicKeyName).equals(currentKey)) {
+
+                                /* public-key first definition, or matches old definition */
+                                publicKeys.put(publicKeyName, currentKey);
+                            } else {
+                                return input.error("Value of 'public-key' " + publicKeyName
+                                        + " conflicts with previously defined value at "
+                                        + parser.getPositionDescription());
+                            }
+                        }
+                        definedKeySets.get(currentKeySet).add(publicKeyName);
+                        XmlUtils.skipCurrentTag(parser);
+                    } finally {
+                        sa.recycle();
+                    }
+                } break;
+                case "upgrade-key-set": {
+                    TypedArray sa = res.obtainAttributes(parser,
+                            R.styleable.AndroidManifestUpgradeKeySet);
+                    try {
+                        String name = sa.getNonResourceString(
+                                R.styleable.AndroidManifestUpgradeKeySet_name);
+                        upgradeKeySets.add(name);
+                        XmlUtils.skipCurrentTag(parser);
+                    } finally {
+                        sa.recycle();
+                    }
+                } break;
+                default:
+                    ParseResult result = ParsingUtils.unknownTag("<key-sets>", pkg, parser,
+                            input);
+                    if (result.isError()) {
+                        return input.error(result);
+                    }
+                    break;
+            }
+        }
+        String packageName = pkg.getPackageName();
+        Set<String> publicKeyNames = publicKeys.keySet();
+        if (publicKeyNames.removeAll(definedKeySets.keySet())) {
+            return input.error("Package" + packageName
+                    + " AndroidManifest.xml 'key-set' and 'public-key' names must be distinct.");
+        }
+
+        for (ArrayMap.Entry<String, ArraySet<String>> e : definedKeySets.entrySet()) {
+            final String keySetName = e.getKey();
+            if (e.getValue().size() == 0) {
+                Slog.w(TAG, "Package" + packageName + " AndroidManifest.xml "
+                        + "'key-set' " + keySetName + " has no valid associated 'public-key'."
+                        + " Not including in package's defined key-sets.");
+                continue;
+            } else if (improperKeySets.contains(keySetName)) {
+                Slog.w(TAG, "Package" + packageName + " AndroidManifest.xml "
+                        + "'key-set' " + keySetName + " contained improper 'public-key'"
+                        + " tags. Not including in package's defined key-sets.");
+                continue;
+            }
+
+            for (String s : e.getValue()) {
+                pkg.addKeySet(keySetName, publicKeys.get(s));
+            }
+        }
+        if (pkg.getKeySetMapping().keySet().containsAll(upgradeKeySets)) {
+            pkg.setUpgradeKeySets(upgradeKeySets);
+        } else {
+            return input.error("Package" + packageName
+                    + " AndroidManifest.xml does not define all 'upgrade-key-set's .");
+        }
+
+        return input.success(pkg);
+    }
+
+    private static ParseResult<ParsingPackage> parseFeature(ParseInput input, ParsingPackage pkg,
+            Resources res, XmlResourceParser parser) throws IOException, XmlPullParserException {
+        ParseResult<ParsedFeature> result = ParsedFeatureUtils.parseFeature(res, parser, input);
+        if (result.isError()) {
+            return input.error(result);
+        }
+        return input.success(pkg.addFeature(result.getResult()));
+    }
+
+    private static ParseResult<ParsingPackage> parsePermissionGroup(ParseInput input,
+            ParsingPackage pkg, Resources res, XmlResourceParser parser)
+            throws XmlPullParserException, IOException {
+        ParseResult<ParsedPermissionGroup> result = ParsedPermissionUtils.parsePermissionGroup(
+                pkg, res, parser, PackageParser.sUseRoundIcon, input);
+        if (result.isError()) {
+            return input.error(result);
+        }
+        return input.success(pkg.addPermissionGroup(result.getResult()));
+    }
+
+    private static ParseResult<ParsingPackage> parsePermission(ParseInput input,
+            ParsingPackage pkg, Resources res, XmlResourceParser parser)
+            throws XmlPullParserException, IOException {
+        ParseResult<ParsedPermission> result = ParsedPermissionUtils.parsePermission(
+                pkg, res, parser, PackageParser.sUseRoundIcon, input);
+        if (result.isError()) {
+            return input.error(result);
+        }
+        return input.success(pkg.addPermission(result.getResult()));
+    }
+
+    private static ParseResult<ParsingPackage> parsePermissionTree(ParseInput input,
+            ParsingPackage pkg, Resources res, XmlResourceParser parser)
+            throws XmlPullParserException, IOException {
+        ParseResult<ParsedPermission> result = ParsedPermissionUtils.parsePermissionTree(
+                pkg, res, parser, PackageParser.sUseRoundIcon, input);
+        if (result.isError()) {
+            return input.error(result);
+        }
+        return input.success(pkg.addPermission(result.getResult()));
+    }
+
+    private ParseResult<ParsingPackage> parseUsesPermission(ParseInput input,
+            ParsingPackage pkg, Resources res, XmlResourceParser parser)
+            throws IOException, XmlPullParserException {
+        TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestUsesPermission);
+        try {
+            // Note: don't allow this value to be a reference to a resource
+            // that may change.
+            String name = sa.getNonResourceString(
+                    R.styleable.AndroidManifestUsesPermission_name);
+
+            int maxSdkVersion = 0;
+            TypedValue val = sa.peekValue(
+                    R.styleable.AndroidManifestUsesPermission_maxSdkVersion);
+            if (val != null) {
+                if (val.type >= TypedValue.TYPE_FIRST_INT && val.type <= TypedValue.TYPE_LAST_INT) {
+                    maxSdkVersion = val.data;
+                }
+            }
+
+            final String requiredFeature = sa.getNonConfigurationString(
+                    R.styleable.AndroidManifestUsesPermission_requiredFeature, 0);
+
+            final String requiredNotfeature = sa.getNonConfigurationString(
+                    R.styleable.AndroidManifestUsesPermission_requiredNotFeature,
+                    0);
+
+            XmlUtils.skipCurrentTag(parser);
+
+            // Can only succeed from here on out
+            ParseResult<ParsingPackage> success = input.success(pkg);
+
+            if (name == null) {
+                return success;
+            }
+
+            if ((maxSdkVersion != 0) && (maxSdkVersion < Build.VERSION.RESOURCES_SDK_INT)) {
+                return success;
+            }
+
+            // Only allow requesting this permission if the platform supports the given feature.
+            if (requiredFeature != null && mCallback != null && !mCallback.hasFeature(
+                    requiredFeature)) {
+                return success;
+            }
+
+            // Only allow requesting this permission if the platform doesn't support the given
+            // feature.
+            if (requiredNotfeature != null && mCallback != null
+                    && mCallback.hasFeature(requiredNotfeature)) {
+                return success;
+            }
+
+            if (!pkg.getRequestedPermissions().contains(name)) {
+                pkg.addRequestedPermission(name.intern());
+            } else {
+                Slog.w(TAG, "Ignoring duplicate uses-permissions/uses-permissions-sdk-m: "
+                        + name + " in package: " + pkg.getPackageName() + " at: "
+                        + parser.getPositionDescription());
+            }
+
+            return success;
+        } finally {
+            sa.recycle();
+        }
+    }
+
+    private static ParseResult<ParsingPackage> parseUsesConfiguration(ParseInput input,
+            ParsingPackage pkg, Resources res, XmlResourceParser parser) {
+        ConfigurationInfo cPref = new ConfigurationInfo();
+        TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestUsesConfiguration);
+        try {
+            cPref.reqTouchScreen = sa.getInt(
+                    R.styleable.AndroidManifestUsesConfiguration_reqTouchScreen,
+                    Configuration.TOUCHSCREEN_UNDEFINED);
+            cPref.reqKeyboardType = sa.getInt(
+                    R.styleable.AndroidManifestUsesConfiguration_reqKeyboardType,
+                    Configuration.KEYBOARD_UNDEFINED);
+            if (sa.getBoolean(
+                    R.styleable.AndroidManifestUsesConfiguration_reqHardKeyboard,
+                    false)) {
+                cPref.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD;
+            }
+            cPref.reqNavigation = sa.getInt(
+                    R.styleable.AndroidManifestUsesConfiguration_reqNavigation,
+                    Configuration.NAVIGATION_UNDEFINED);
+            if (sa.getBoolean(
+                    R.styleable.AndroidManifestUsesConfiguration_reqFiveWayNav,
+                    false)) {
+                cPref.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV;
+            }
+            pkg.addConfigPreference(cPref);
+            return input.success(pkg);
+        } finally {
+            sa.recycle();
+        }
+    }
+
+    private static ParseResult<ParsingPackage> parseUsesFeature(ParseInput input,
+            ParsingPackage pkg, Resources res, XmlResourceParser parser) {
+        FeatureInfo fi = parseFeatureInfo(res, parser);
+        pkg.addReqFeature(fi);
+
+        if (fi.name == null) {
+            ConfigurationInfo cPref = new ConfigurationInfo();
+            cPref.reqGlEsVersion = fi.reqGlEsVersion;
+            pkg.addConfigPreference(cPref);
+        }
+
+        return input.success(pkg);
+    }
+
+    private static FeatureInfo parseFeatureInfo(Resources res, AttributeSet attrs) {
+        FeatureInfo fi = new FeatureInfo();
+        TypedArray sa = res.obtainAttributes(attrs, R.styleable.AndroidManifestUsesFeature);
+        try {
+            // Note: don't allow this value to be a reference to a resource
+            // that may change.
+            fi.name = sa.getNonResourceString(R.styleable.AndroidManifestUsesFeature_name);
+            fi.version = sa.getInt(R.styleable.AndroidManifestUsesFeature_version, 0);
+            if (fi.name == null) {
+                fi.reqGlEsVersion = sa.getInt(R.styleable.AndroidManifestUsesFeature_glEsVersion,
+                        FeatureInfo.GL_ES_VERSION_UNDEFINED);
+            }
+            if (sa.getBoolean(R.styleable.AndroidManifestUsesFeature_required, true)) {
+                fi.flags |= FeatureInfo.FLAG_REQUIRED;
+            }
+            return fi;
+        } finally {
+            sa.recycle();
+        }
+    }
+
+    private static ParseResult<ParsingPackage> parseFeatureGroup(ParseInput input,
+            ParsingPackage pkg, Resources res, XmlResourceParser parser)
+            throws IOException, XmlPullParserException {
+        FeatureGroupInfo group = new FeatureGroupInfo();
+        ArrayList<FeatureInfo> features = null;
+        final int depth = parser.getDepth();
+        int type;
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG
+                || parser.getDepth() > depth)) {
+            if (type != XmlPullParser.START_TAG) {
+                continue;
+            }
+
+            final String innerTagName = parser.getName();
+            if (innerTagName.equals("uses-feature")) {
+                FeatureInfo featureInfo = parseFeatureInfo(res, parser);
+                // FeatureGroups are stricter and mandate that
+                // any <uses-feature> declared are mandatory.
+                featureInfo.flags |= FeatureInfo.FLAG_REQUIRED;
+                features = ArrayUtils.add(features, featureInfo);
+            } else {
+                Slog.w(TAG,
+                        "Unknown element under <feature-group>: " + innerTagName +
+                                " at " + pkg.getBaseCodePath() + " " +
+                                parser.getPositionDescription());
+            }
+        }
+
+        if (features != null) {
+            group.features = new FeatureInfo[features.size()];
+            group.features = features.toArray(group.features);
+        }
+
+        pkg.addFeatureGroup(group);
+        return input.success(pkg);
+    }
+
+    private static ParseResult<ParsingPackage> parseUsesSdk(ParseInput input,
+            ParsingPackage pkg, Resources res, XmlResourceParser parser)
+            throws IOException, XmlPullParserException {
+        if (PackageParser.SDK_VERSION > 0) {
+            TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestUsesSdk);
+            try {
+                int minVers = 1;
+                String minCode = null;
+                int targetVers = 0;
+                String targetCode = null;
+
+                TypedValue val = sa.peekValue(R.styleable.AndroidManifestUsesSdk_minSdkVersion);
+                if (val != null) {
+                    if (val.type == TypedValue.TYPE_STRING && val.string != null) {
+                        minCode = val.string.toString();
+                    } else {
+                        // If it's not a string, it's an integer.
+                        minVers = val.data;
+                    }
+                }
+
+                val = sa.peekValue(R.styleable.AndroidManifestUsesSdk_targetSdkVersion);
+                if (val != null) {
+                    if (val.type == TypedValue.TYPE_STRING && val.string != null) {
+                        targetCode = val.string.toString();
+                        if (minCode == null) {
+                            minCode = targetCode;
+                        }
+                    } else {
+                        // If it's not a string, it's an integer.
+                        targetVers = val.data;
+                    }
+                } else {
+                    targetVers = minVers;
+                    targetCode = minCode;
+                }
+
+                ParseResult<Integer> minSdkVersionResult = computeMinSdkVersion(minVers, minCode,
+                        PackageParser.SDK_VERSION, PackageParser.SDK_CODENAMES, input);
+                if (minSdkVersionResult.isError()) {
+                    return input.error(minSdkVersionResult);
+                }
+
+                int minSdkVersion = minSdkVersionResult.getResult();
+
+                ParseResult<Integer> targetSdkVersionResult = computeTargetSdkVersion(
+                        targetVers, targetCode, PackageParser.SDK_CODENAMES, input);
+                if (targetSdkVersionResult.isError()) {
+                    return input.error(targetSdkVersionResult);
+                }
+
+                int targetSdkVersion = minSdkVersionResult.getResult();
+
+                pkg.setMinSdkVersion(minSdkVersion)
+                        .setTargetSdkVersion(targetSdkVersion);
+
+                int type;
+                final int innerDepth = parser.getDepth();
+                while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                        && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
+                    if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                        continue;
+                    }
+
+                    final ParseResult result;
+                    if (parser.getName().equals("extension-sdk")) {
+                        result = parseExtensionSdk(input, pkg, res, parser);
+                        XmlUtils.skipCurrentTag(parser);
+                    } else {
+                        result = ParsingUtils.unknownTag("<uses-sdk>", pkg, parser, input);
+                    }
+
+                    if (result.isError()) {
+                        return input.error(result);
+                    }
+                }
+            } finally {
+                sa.recycle();
+            }
+        }
+        return input.success(pkg);
+    }
+
+    private static ParseResult parseExtensionSdk(ParseInput input, ParsingPackage pkg,
+            Resources res, XmlResourceParser parser) {
+        int sdkVersion;
+        int minVersion;
+        TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestExtensionSdk);
+        try {
+            sdkVersion = sa.getInt(R.styleable.AndroidManifestExtensionSdk_sdkVersion, -1);
+            minVersion = sa.getInt(R.styleable.AndroidManifestExtensionSdk_minExtensionVersion, -1);
+        } finally {
+            sa.recycle();
+        }
+
+        if (sdkVersion < 0) {
+            return input.error(
+                    PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                    "<extension-sdk> must specify an sdkVersion >= 0");
+        }
+        if (minVersion < 0) {
+            return input.error(
+                    PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                    "<extension-sdk> must specify minExtensionVersion >= 0");
+        }
+
+        try {
+            int version = SdkExtensions.getExtensionVersion(sdkVersion);
+            if (version < minVersion) {
+                return input.error(
+                        PackageManager.INSTALL_FAILED_OLDER_SDK,
+                        "Package requires " + sdkVersion + " extension version " + minVersion
+                                + " which exceeds device version " + version);
+            }
+        } catch (RuntimeException e) {
+            return input.error(
+                    PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                    "Specified sdkVersion " + sdkVersion + " is not valid");
+        }
+        return input.success(pkg);
+    }
+
+    /**
+     * {@link ParseResult} version of
+     * {@link PackageParser#computeMinSdkVersion(int, String, int, String[], String[])}
+     */
+    public static ParseResult<Integer> computeMinSdkVersion(@IntRange(from = 1) int minVers,
+            @Nullable String minCode, @IntRange(from = 1) int platformSdkVersion,
+            @NonNull String[] platformSdkCodenames, @NonNull ParseInput input) {
+        // If it's a release SDK, make sure we meet the minimum SDK requirement.
+        if (minCode == null) {
+            if (minVers <= platformSdkVersion) {
+                return input.success(minVers);
+            }
+
+            // We don't meet the minimum SDK requirement.
+            return input.error(PackageManager.INSTALL_FAILED_OLDER_SDK,
+                    "Requires newer sdk version #" + minVers
+                            + " (current version is #" + platformSdkVersion + ")");
+        }
+
+        // If it's a pre-release SDK and the codename matches this platform, we
+        // definitely meet the minimum SDK requirement.
+        if (matchTargetCode(platformSdkCodenames, minCode)) {
+            return input.success(Build.VERSION_CODES.CUR_DEVELOPMENT);
+        }
+
+        // Otherwise, we're looking at an incompatible pre-release SDK.
+        if (platformSdkCodenames.length > 0) {
+            return input.error(PackageManager.INSTALL_FAILED_OLDER_SDK,
+                    "Requires development platform " + minCode
+                            + " (current platform is any of "
+                            + Arrays.toString(platformSdkCodenames) + ")");
+        } else {
+            return input.error(PackageManager.INSTALL_FAILED_OLDER_SDK,
+                    "Requires development platform " + minCode
+                            + " but this is a release platform.");
+        }
+    }
+
+    /**
+     * {@link ParseResult} version of
+     * {@link PackageParser#computeTargetSdkVersion(int, String, String[], String[])}
+     */
+    public static ParseResult<Integer> computeTargetSdkVersion(@IntRange(from = 0) int targetVers,
+            @Nullable String targetCode, @NonNull String[] platformSdkCodenames,
+            @NonNull ParseInput input) {
+        // If it's a release SDK, return the version number unmodified.
+        if (targetCode == null) {
+            return input.success(targetVers);
+        }
+
+        // If it's a pre-release SDK and the codename matches this platform, it
+        // definitely targets this SDK.
+        if (matchTargetCode(platformSdkCodenames, targetCode)) {
+            return input.success(Build.VERSION_CODES.CUR_DEVELOPMENT);
+        }
+
+        // Otherwise, we're looking at an incompatible pre-release SDK.
+        if (platformSdkCodenames.length > 0) {
+            return input.error(PackageManager.INSTALL_FAILED_OLDER_SDK,
+                    "Requires development platform " + targetCode
+                            + " (current platform is any of "
+                            + Arrays.toString(platformSdkCodenames) + ")");
+        } else {
+            return input.error(PackageManager.INSTALL_FAILED_OLDER_SDK,
+                    "Requires development platform " + targetCode
+                            + " but this is a release platform.");
+        }
+    }
+
+    /**
+     * Matches a given {@code targetCode} against a set of release codeNames. Target codes can
+     * either be of the form {@code [codename]}" (e.g {@code "Q"}) or of the form
+     * {@code [codename].[fingerprint]} (e.g {@code "Q.cafebc561"}).
+     */
+    private static boolean matchTargetCode(@NonNull String[] codeNames,
+            @NonNull String targetCode) {
+        final String targetCodeName;
+        final int targetCodeIdx = targetCode.indexOf('.');
+        if (targetCodeIdx == -1) {
+            targetCodeName = targetCode;
+        } else {
+            targetCodeName = targetCode.substring(0, targetCodeIdx);
+        }
+        return ArrayUtils.contains(codeNames, targetCodeName);
+    }
+
+    private static ParseResult<ParsingPackage> parseRestrictUpdateHash(int flags, ParseInput input,
+            ParsingPackage pkg, Resources res, XmlResourceParser parser) {
+        if ((flags & PackageParser.PARSE_IS_SYSTEM_DIR) != 0) {
+            TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestRestrictUpdate);
+            try {
+                final String hash = sa.getNonConfigurationString(
+                        R.styleable.AndroidManifestRestrictUpdate_hash,
+                        0);
+
+                if (hash != null) {
+                    final int hashLength = hash.length();
+                    final byte[] hashBytes = new byte[hashLength / 2];
+                    for (int i = 0; i < hashLength; i += 2) {
+                        hashBytes[i / 2] = (byte) ((Character.digit(hash.charAt(i), 16)
+                                << 4)
+                                + Character.digit(hash.charAt(i + 1), 16));
+                    }
+                    pkg.setRestrictUpdateHash(hashBytes);
+                } else {
+                    pkg.setRestrictUpdateHash(null);
+                }
+            } finally {
+                sa.recycle();
+            }
+        }
+        return input.success(pkg);
+    }
+
+    private static ParseResult<ParsingPackage> parseQueries(ParseInput input, ParsingPackage pkg,
+            Resources res, XmlResourceParser parser) throws IOException, XmlPullParserException {
+        final int depth = parser.getDepth();
+        int type;
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG
+                || parser.getDepth() > depth)) {
+            if (type != XmlPullParser.START_TAG) {
+                continue;
+            }
+            if (parser.getName().equals("intent")) {
+                ParseResult<ParsedIntentInfo> result = ParsedIntentInfoUtils.parseIntentInfo(null,
+                        pkg, res, parser, true /*allowGlobs*/, true /*allowAutoVerify*/, input);
+                if (result.isError()) {
+                    return input.error(result);
+                }
+
+                ParsedIntentInfo intentInfo = result.getResult();
+
+                Uri data = null;
+                String dataType = null;
+                String host = "";
+                final int numActions = intentInfo.countActions();
+                final int numSchemes = intentInfo.countDataSchemes();
+                final int numTypes = intentInfo.countDataTypes();
+                final int numHosts = intentInfo.getHosts().length;
+                if ((numSchemes == 0 && numTypes == 0 && numActions == 0)) {
+                    return input.error("intent tags must contain either an action or data.");
+                }
+                if (numActions > 1) {
+                    return input.error("intent tag may have at most one action.");
+                }
+                if (numTypes > 1) {
+                    return input.error("intent tag may have at most one data type.");
+                }
+                if (numSchemes > 1) {
+                    return input.error("intent tag may have at most one data scheme.");
+                }
+                if (numHosts > 1) {
+                    return input.error("intent tag may have at most one data host.");
+                }
+                Intent intent = new Intent();
+                for (int i = 0, max = intentInfo.countCategories(); i < max; i++) {
+                    intent.addCategory(intentInfo.getCategory(i));
+                }
+                if (numHosts == 1) {
+                    host = intentInfo.getHosts()[0];
+                }
+                if (numSchemes == 1) {
+                    data = new Uri.Builder()
+                            .scheme(intentInfo.getDataScheme(0))
+                            .authority(host)
+                            .build();
+                }
+                if (numTypes == 1) {
+                    dataType = intentInfo.getDataType(0);
+                }
+                intent.setDataAndType(data, dataType);
+                if (numActions == 1) {
+                    intent.setAction(intentInfo.getAction(0));
+                }
+                pkg.addQueriesIntent(intent);
+            } else if (parser.getName().equals("package")) {
+                final TypedArray sa = res.obtainAttributes(parser,
+                        R.styleable.AndroidManifestQueriesPackage);
+                final String packageName = sa.getString(
+                        R.styleable.AndroidManifestQueriesPackage_name);
+                if (TextUtils.isEmpty(packageName)) {
+                    return input.error("Package name is missing from package tag.");
+                }
+                pkg.addQueriesPackage(packageName.intern());
+            } else if (parser.getName().equals("provider")) {
+                final TypedArray sa = res.obtainAttributes(parser,
+                        R.styleable.AndroidManifestQueriesProvider);
+                try {
+                    final String authorities =
+                            sa.getString(R.styleable.AndroidManifestQueriesProvider_authorities);
+                    if (TextUtils.isEmpty(authorities)) {
+                        return input.error(
+                                PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                                "Authority missing from provider tag."
+                        );
+                    }
+                    StringTokenizer authoritiesTokenizer = new StringTokenizer(authorities, ";");
+                    while (authoritiesTokenizer.hasMoreElements()) {
+                        pkg.addQueriesProvider(authoritiesTokenizer.nextToken());
+                    }
+                } finally {
+                    sa.recycle();
+                }
+            }
+        }
+        return input.success(pkg);
+    }
+
+    /**
+     * Parse the {@code application} XML tree at the current parse location in a
+     * <em>base APK</em> manifest.
+     * <p>
+     * When adding new features, carefully consider if they should also be
+     * supported by split APKs.
+     *
+     * This method should avoid using a getter for fields set by this method. Prefer assigning
+     * a local variable and using it. Otherwise there's an ordering problem which can be broken
+     * if any code moves around.
+     */
+    private ParseResult<ParsingPackage> parseBaseApplication(ParseInput input,
+            ParsingPackage pkg, Resources res, XmlResourceParser parser, int flags)
+            throws XmlPullParserException, IOException {
+        final String pkgName = pkg.getPackageName();
+        int targetSdk = pkg.getTargetSdkVersion();
+
+        TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestApplication);
+        try {
+            // TODO(b/135203078): Remove this and force unit tests to mock an empty manifest
+            // This case can only happen in unit tests where we sometimes need to create fakes
+            // of various package parser data structures.
+            if (sa == null) {
+                return input.error("<application> does not contain any attributes");
+            }
+
+            String name = sa.getNonConfigurationString(R.styleable.AndroidManifestApplication_name,
+                    0);
+            if (name != null) {
+                String packageName = pkg.getPackageName();
+                String outInfoName = ParsingUtils.buildClassName(packageName, name);
+                if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(outInfoName)) {
+                    return input.error("<application> invalid android:name");
+                } else if (outInfoName == null) {
+                    return input.error("Empty class name in package " + packageName);
+                }
+
+                pkg.setClassName(outInfoName);
+            }
+
+            TypedValue labelValue = sa.peekValue(R.styleable.AndroidManifestApplication_label);
+            if (labelValue != null) {
+                pkg.setLabelRes(labelValue.resourceId);
+                if (labelValue.resourceId == 0) {
+                    pkg.setNonLocalizedLabel(labelValue.coerceToString());
+                }
+            }
+
+            parseBaseAppBasicFlags(pkg, sa);
+
+            String manageSpaceActivity = nonConfigString(Configuration.NATIVE_CONFIG_VERSION,
+                    R.styleable.AndroidManifestApplication_manageSpaceActivity, sa);
+            if (manageSpaceActivity != null) {
+                String manageSpaceActivityName = ParsingUtils.buildClassName(pkgName,
+                        manageSpaceActivity);
+
+                if (manageSpaceActivityName == null) {
+                    return input.error("Empty class name in package " + pkgName);
+                }
+
+                pkg.setManageSpaceActivityName(manageSpaceActivityName);
+            }
+
+            if (pkg.isAllowBackup()) {
+                // backupAgent, killAfterRestore, fullBackupContent, backupInForeground,
+                // and restoreAnyVersion are only relevant if backup is possible for the
+                // given application.
+                String backupAgent = nonConfigString(Configuration.NATIVE_CONFIG_VERSION,
+                        R.styleable.AndroidManifestApplication_backupAgent, sa);
+                if (backupAgent != null) {
+                    String backupAgentName = ParsingUtils.buildClassName(pkgName, backupAgent);
+                    if (backupAgentName == null) {
+                        return input.error("Empty class name in package " + pkgName);
+                    }
+
+                    if (PackageParser.DEBUG_BACKUP) {
+                        Slog.v(TAG, "android:backupAgent = " + backupAgentName
+                                + " from " + pkgName + "+" + backupAgent);
+                    }
+
+                    pkg.setBackupAgentName(backupAgentName)
+                            .setKillAfterRestore(bool(true,
+                                    R.styleable.AndroidManifestApplication_killAfterRestore, sa))
+                            .setRestoreAnyVersion(bool(false,
+                                    R.styleable.AndroidManifestApplication_restoreAnyVersion, sa))
+                            .setFullBackupOnly(bool(false,
+                                    R.styleable.AndroidManifestApplication_fullBackupOnly, sa))
+                            .setBackupInForeground(bool(false,
+                                    R.styleable.AndroidManifestApplication_backupInForeground, sa));
+                }
+
+                TypedValue v = sa.peekValue(
+                        R.styleable.AndroidManifestApplication_fullBackupContent);
+                int fullBackupContent = 0;
+
+                if (v != null) {
+                    fullBackupContent = v.resourceId;
+
+                    if (v.resourceId == 0) {
+                        if (PackageParser.DEBUG_BACKUP) {
+                            Slog.v(TAG, "fullBackupContent specified as boolean=" +
+                                    (v.data == 0 ? "false" : "true"));
+                        }
+                        // "false" => -1, "true" => 0
+                        fullBackupContent = v.data == 0 ? -1 : 0;
+                    }
+
+                    pkg.setFullBackupContent(fullBackupContent);
+                }
+                if (PackageParser.DEBUG_BACKUP) {
+                    Slog.v(TAG, "fullBackupContent=" + fullBackupContent + " for " + pkgName);
+                }
+            }
+
+            if (sa.getBoolean(R.styleable.AndroidManifestApplication_persistent, false)) {
+                // Check if persistence is based on a feature being present
+                final String requiredFeature = sa.getNonResourceString(R.styleable
+                        .AndroidManifestApplication_persistentWhenFeatureAvailable);
+                pkg.setPersistent(requiredFeature == null || mCallback.hasFeature(requiredFeature));
+            }
+
+            // TODO(b/135203078): Should parsing code be responsible for this? Maybe move to a
+            //  util or just have PackageImpl return true if either flag is set
+            // Debuggable implies profileable
+            pkg.setProfileableByShell(pkg.isProfileableByShell() || pkg.isDebuggable());
+
+            if (sa.hasValueOrEmpty(R.styleable.AndroidManifestApplication_resizeableActivity)) {
+                pkg.setResizeableActivity(sa.getBoolean(
+                        R.styleable.AndroidManifestApplication_resizeableActivity, true));
+            } else {
+                pkg.setResizeableActivityViaSdkVersion(
+                        targetSdk >= Build.VERSION_CODES.N);
+            }
+
+            String taskAffinity;
+            if (targetSdk >= Build.VERSION_CODES.FROYO) {
+                taskAffinity = sa.getNonConfigurationString(
+                        R.styleable.AndroidManifestApplication_taskAffinity,
+                        Configuration.NATIVE_CONFIG_VERSION);
+            } else {
+                // Some older apps have been seen to use a resource reference
+                // here that on older builds was ignored (with a warning).  We
+                // need to continue to do this for them so they don't break.
+                taskAffinity = sa.getNonResourceString(
+                        R.styleable.AndroidManifestApplication_taskAffinity);
+            }
+
+            ParseResult<String> taskAffinityResult = ComponentParseUtils.buildTaskAffinityName(
+                    pkgName, pkgName, taskAffinity, input);
+            if (taskAffinityResult.isError()) {
+                return input.error(taskAffinityResult);
+            }
+
+            pkg.setTaskAffinity(taskAffinityResult.getResult());
+            String factory = sa.getNonResourceString(
+                    R.styleable.AndroidManifestApplication_appComponentFactory);
+            if (factory != null) {
+                String appComponentFactory = ParsingUtils.buildClassName(pkgName, factory);
+                if (appComponentFactory == null) {
+                    return input.error("Empty class name in package " + pkgName);
+                }
+
+                pkg.setAppComponentFactory(appComponentFactory);
+            }
+
+            CharSequence pname;
+            if (targetSdk >= Build.VERSION_CODES.FROYO) {
+                pname = sa.getNonConfigurationString(
+                        R.styleable.AndroidManifestApplication_process,
+                        Configuration.NATIVE_CONFIG_VERSION);
+            } else {
+                // Some older apps have been seen to use a resource reference
+                // here that on older builds was ignored (with a warning).  We
+                // need to continue to do this for them so they don't break.
+                pname = sa.getNonResourceString(
+                        R.styleable.AndroidManifestApplication_process);
+            }
+            ParseResult<String> processNameResult = ComponentParseUtils.buildProcessName(
+                    pkgName, null, pname, flags, mSeparateProcesses, input);
+            if (processNameResult.isError()) {
+                return input.error(processNameResult);
+            }
+
+            String processName = processNameResult.getResult();
+            pkg.setProcessName(processName);
+
+            if (pkg.isCantSaveState()) {
+                // A heavy-weight application can not be in a custom process.
+                // We can do direct compare because we intern all strings.
+                if (processName != null && !processName.equals(pkgName)) {
+                    return input.error(
+                            "cantSaveState applications can not use custom processes");
+                }
+            }
+
+            String classLoaderName = pkg.getClassLoaderName();
+            if (classLoaderName != null
+                    && !ClassLoaderFactory.isValidClassLoaderName(classLoaderName)) {
+                return input.error("Invalid class loader name: " + classLoaderName);
+            }
+        } finally {
+            sa.recycle();
+        }
+
+        boolean hasActivityOrder = false;
+        boolean hasReceiverOrder = false;
+        boolean hasServiceOrder = false;
+        final int depth = parser.getDepth();
+        int type;
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG
+                || parser.getDepth() > depth)) {
+            if (type != XmlPullParser.START_TAG) {
+                continue;
+            }
+
+            final ParseResult result;
+            String tagName = parser.getName();
+            boolean isActivity = false;
+            switch (tagName) {
+                case "activity":
+                    isActivity = true;
+                    // fall-through
+                case "receiver":
+                    ParseResult<ParsedActivity> activityResult =
+                            ParsedActivityUtils.parseActivityOrReceiver(mSeparateProcesses, pkg,
+                                    res, parser, flags, PackageParser.sUseRoundIcon, input);
+
+                    if (activityResult.isSuccess()) {
+                        ParsedActivity activity = activityResult.getResult();
+                        if (isActivity) {
+                            hasActivityOrder |= (activity.getOrder() != 0);
+                            pkg.addActivity(activity);
+                        } else {
+                            hasReceiverOrder |= (activity.getOrder() != 0);
+                            pkg.addReceiver(activity);
+                        }
+                    }
+
+                    result = activityResult;
+                    break;
+                case "service":
+                    ParseResult<ParsedService> serviceResult =
+                            ParsedServiceUtils.parseService(mSeparateProcesses, pkg, res, parser,
+                                    flags, PackageParser.sUseRoundIcon, input);
+                    if (serviceResult.isSuccess()) {
+                        ParsedService service = serviceResult.getResult();
+                        hasServiceOrder |= (service.getOrder() != 0);
+                        pkg.addService(service);
+                    }
+
+                    result = serviceResult;
+                    break;
+                case "provider":
+                    ParseResult<ParsedProvider> providerResult =
+                            ParsedProviderUtils.parseProvider(mSeparateProcesses, pkg, res, parser,
+                                    flags, PackageParser.sUseRoundIcon, input);
+                    if (providerResult.isSuccess()) {
+                        pkg.addProvider(providerResult.getResult());
+                    }
+
+                    result = providerResult;
+                    break;
+                case "activity-alias":
+                    activityResult = ParsedActivityUtils.parseActivityAlias(pkg, res,
+                            parser, PackageParser.sUseRoundIcon, input);
+                    if (activityResult.isSuccess()) {
+                        ParsedActivity activity = activityResult.getResult();
+                        hasActivityOrder |= (activity.getOrder() != 0);
+                        pkg.addActivity(activity);
+                    }
+
+                    result = activityResult;
+                    break;
+                default:
+                    result = parseBaseAppChildTag(input, tagName, pkg, res, parser, flags);
+                    break;
+            }
+
+            if (result.isError()) {
+                return input.error(result);
+            }
+        }
+
+        if (TextUtils.isEmpty(pkg.getStaticSharedLibName())) {
+            // Add a hidden app detail activity to normal apps which forwards user to App Details
+            // page.
+            ParseResult<ParsedActivity> a = generateAppDetailsHiddenActivity(input, pkg);
+            // Backwards-compat, assume success
+            pkg.addActivity(a.getResult());
+            a.ignoreError();
+        }
+
+        if (hasActivityOrder) {
+            pkg.sortActivities();
+        }
+        if (hasReceiverOrder) {
+            pkg.sortReceivers();
+        }
+        if (hasServiceOrder) {
+            pkg.sortServices();
+        }
+
+        // Must be run after the entire {@link ApplicationInfo} has been fully processed and after
+        // every activity info has had a chance to set it from its attributes.
+        setMaxAspectRatio(pkg);
+        setMinAspectRatio(pkg);
+
+        pkg.setHasDomainUrls(hasDomainURLs(pkg));
+
+        return input.success(pkg);
+    }
+
+    /**
+     * Collection of single-line, no (or little) logic assignments. Separated for readability.
+     *
+     * Flags are separated by type and by default value. They are sorted alphabetically within each
+     * section.
+     */
+    private void parseBaseAppBasicFlags(ParsingPackage pkg, TypedArray sa) {
+        int targetSdk = pkg.getTargetSdkVersion();
+        //@formatter:off
+        // CHECKSTYLE:off
+        pkg
+                // Default true
+                .setAllowBackup(bool(true, R.styleable.AndroidManifestApplication_allowBackup, sa))
+                .setAllowClearUserData(bool(true, R.styleable.AndroidManifestApplication_allowClearUserData, sa))
+                .setAllowClearUserDataOnFailedRestore(bool(true, R.styleable.AndroidManifestApplication_allowClearUserDataOnFailedRestore, sa))
+                .setAllowNativeHeapPointerTagging(bool(true, R.styleable.AndroidManifestApplication_allowNativeHeapPointerTagging, sa))
+                .setEnabled(bool(true, R.styleable.AndroidManifestApplication_enabled, sa))
+                .setExtractNativeLibs(bool(true, R.styleable.AndroidManifestApplication_extractNativeLibs, sa))
+                .setHasCode(bool(true, R.styleable.AndroidManifestApplication_hasCode, sa))
+                // Default false
+                .setAllowTaskReparenting(bool(false, R.styleable.AndroidManifestApplication_allowTaskReparenting, sa))
+                .setCantSaveState(bool(false, R.styleable.AndroidManifestApplication_cantSaveState, sa))
+                .setDebuggable(bool(false, R.styleable.AndroidManifestApplication_debuggable, sa))
+                .setDefaultToDeviceProtectedStorage(bool(false, R.styleable.AndroidManifestApplication_defaultToDeviceProtectedStorage, sa))
+                .setDirectBootAware(bool(false, R.styleable.AndroidManifestApplication_directBootAware, sa))
+                .setForceQueryable(bool(false, R.styleable.AndroidManifestApplication_forceQueryable, sa))
+                .setGame(bool(false, R.styleable.AndroidManifestApplication_isGame, sa))
+                .setHasFragileUserData(bool(false, R.styleable.AndroidManifestApplication_hasFragileUserData, sa))
+                .setLargeHeap(bool(false, R.styleable.AndroidManifestApplication_largeHeap, sa))
+                .setMultiArch(bool(false, R.styleable.AndroidManifestApplication_multiArch, sa))
+                .setPreserveLegacyExternalStorage(bool(false, R.styleable.AndroidManifestApplication_preserveLegacyExternalStorage, sa))
+                .setRequiredForAllUsers(bool(false, R.styleable.AndroidManifestApplication_requiredForAllUsers, sa))
+                .setSupportsRtl(bool(false, R.styleable.AndroidManifestApplication_supportsRtl, sa))
+                .setTestOnly(bool(false, R.styleable.AndroidManifestApplication_testOnly, sa))
+                .setUseEmbeddedDex(bool(false, R.styleable.AndroidManifestApplication_useEmbeddedDex, sa))
+                .setUsesNonSdkApi(bool(false, R.styleable.AndroidManifestApplication_usesNonSdkApi, sa))
+                .setVmSafeMode(bool(false, R.styleable.AndroidManifestApplication_vmSafeMode, sa))
+                // targetSdkVersion gated
+                .setAllowAudioPlaybackCapture(bool(targetSdk >= Build.VERSION_CODES.Q, R.styleable.AndroidManifestApplication_allowAudioPlaybackCapture, sa))
+                .setBaseHardwareAccelerated(bool(targetSdk >= Build.VERSION_CODES.ICE_CREAM_SANDWICH, R.styleable.AndroidManifestApplication_hardwareAccelerated, sa))
+                .setRequestLegacyExternalStorage(bool(targetSdk < Build.VERSION_CODES.Q, R.styleable.AndroidManifestApplication_requestLegacyExternalStorage, sa))
+                .setUsesCleartextTraffic(bool(targetSdk < Build.VERSION_CODES.P, R.styleable.AndroidManifestApplication_usesCleartextTraffic, sa))
+                // Ints Default 0
+                .setUiOptions(anInt(R.styleable.AndroidManifestApplication_uiOptions, sa))
+                // Ints
+                .setCategory(anInt(ApplicationInfo.CATEGORY_UNDEFINED, R.styleable.AndroidManifestApplication_appCategory, sa))
+                // Floats Default 0f
+                .setMaxAspectRatio(aFloat(R.styleable.AndroidManifestApplication_maxAspectRatio, sa))
+                .setMinAspectRatio(aFloat(R.styleable.AndroidManifestApplication_minAspectRatio, sa))
+                // Resource ID
+                .setBanner(resId(R.styleable.AndroidManifestApplication_banner, sa))
+                .setDescriptionRes(resId(R.styleable.AndroidManifestApplication_description, sa))
+                .setIconRes(resId(R.styleable.AndroidManifestApplication_icon, sa))
+                .setLogo(resId(R.styleable.AndroidManifestApplication_logo, sa))
+                .setNetworkSecurityConfigRes(resId(R.styleable.AndroidManifestApplication_networkSecurityConfig, sa))
+                .setRoundIconRes(resId(R.styleable.AndroidManifestApplication_roundIcon, sa))
+                .setTheme(resId(R.styleable.AndroidManifestApplication_theme, sa))
+                // Strings
+                .setClassLoaderName(string(R.styleable.AndroidManifestApplication_classLoader, sa))
+                .setRequiredAccountType(string(R.styleable.AndroidManifestApplication_requiredAccountType, sa))
+                .setRestrictedAccountType(string(R.styleable.AndroidManifestApplication_restrictedAccountType, sa))
+                .setZygotePreloadName(string(R.styleable.AndroidManifestApplication_zygotePreloadName, sa))
+                // Non-Config String
+                .setPermission(nonConfigString(0, R.styleable.AndroidManifestApplication_permission, sa));
+        // CHECKSTYLE:on
+        //@formatter:on
+    }
+
+    /**
+     * For parsing non-MainComponents. Main ones have an order and some special handling which is
+     * done directly in {@link #parseBaseApplication(ParseInput, ParsingPackage, Resources,
+     * XmlResourceParser, int)}.
+     */
+    private ParseResult parseBaseAppChildTag(ParseInput input, String tag, ParsingPackage pkg,
+            Resources res, XmlResourceParser parser, int flags)
+            throws IOException, XmlPullParserException {
+        switch (tag) {
+            case "meta-data":
+                // TODO(b/135203078): I have no idea what this comment means
+                // note: application meta-data is stored off to the side, so it can
+                // remain null in the primary copy (we like to avoid extra copies because
+                // it can be large)
+                ParseResult<Bundle> metaDataResult = parseMetaData(pkg, res, parser,
+                        pkg.getMetaData(), input);
+                if (metaDataResult.isSuccess()) {
+                    pkg.setMetaData(metaDataResult.getResult());
+                }
+
+                return metaDataResult;
+            case "static-library":
+                return parseStaticLibrary(pkg, res, parser, input);
+            case "library":
+                return parseLibrary(pkg, res, parser, input);
+            case "uses-static-library":
+                return parseUsesStaticLibrary(input, pkg, res, parser);
+            case "uses-library":
+                return parseUsesLibrary(input, pkg, res, parser);
+            case "processes":
+                return parseProcesses(input, pkg, res, parser, mSeparateProcesses, flags);
+            case "uses-package":
+                // Dependencies for app installers; we don't currently try to
+                // enforce this.
+                return input.success(null);
+            case "profileable":
+                return parseProfileable(input, pkg, res, parser);
+            default:
+                return ParsingUtils.unknownTag("<application>", pkg, parser, input);
+        }
+    }
+
+    @NonNull
+    private static ParseResult<ParsingPackage> parseStaticLibrary(
+            ParsingPackage pkg, Resources res,
+            XmlResourceParser parser, ParseInput input) {
+        TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestStaticLibrary);
+        try {
+            // Note: don't allow this value to be a reference to a resource
+            // that may change.
+            String lname = sa.getNonResourceString(
+                    R.styleable.AndroidManifestStaticLibrary_name);
+            final int version = sa.getInt(
+                    R.styleable.AndroidManifestStaticLibrary_version, -1);
+            final int versionMajor = sa.getInt(
+                    R.styleable.AndroidManifestStaticLibrary_versionMajor,
+                    0);
+
+            // Since the app canot run without a static lib - fail if malformed
+            if (lname == null || version < 0) {
+                return input.error("Bad static-library declaration name: " + lname
+                        + " version: " + version);
+            } else if (pkg.getSharedUserId() != null) {
+                return input.error(
+                        PackageManager.INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID,
+                        "sharedUserId not allowed in static shared library"
+                );
+            } else if (pkg.getStaticSharedLibName() != null) {
+                return input.error("Multiple static-shared libs for package "
+                        + pkg.getPackageName());
+            }
+
+            return input.success(pkg.setStaticSharedLibName(lname.intern())
+                    .setStaticSharedLibVersion(
+                            PackageInfo.composeLongVersionCode(versionMajor, version))
+                    .setStaticSharedLibrary(true));
+        } finally {
+            sa.recycle();
+        }
+    }
+
+    @NonNull
+    private static ParseResult<ParsingPackage> parseLibrary(
+            ParsingPackage pkg, Resources res,
+            XmlResourceParser parser, ParseInput input) {
+        TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestLibrary);
+        try {
+            // Note: don't allow this value to be a reference to a resource
+            // that may change.
+            String lname = sa.getNonResourceString(R.styleable.AndroidManifestLibrary_name);
+
+            if (lname != null) {
+                lname = lname.intern();
+                if (!ArrayUtils.contains(pkg.getLibraryNames(), lname)) {
+                    pkg.addLibraryName(lname);
+                }
+            }
+            return input.success(pkg);
+        } finally {
+            sa.recycle();
+        }
+    }
+
+    @NonNull
+    private static ParseResult<ParsingPackage> parseUsesStaticLibrary(ParseInput input,
+            ParsingPackage pkg, Resources res, XmlResourceParser parser)
+            throws XmlPullParserException, IOException {
+        TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestUsesStaticLibrary);
+        try {
+            // Note: don't allow this value to be a reference to a resource that may change.
+            String lname = sa.getNonResourceString(
+                    R.styleable.AndroidManifestUsesLibrary_name);
+            final int version = sa.getInt(
+                    R.styleable.AndroidManifestUsesStaticLibrary_version, -1);
+            String certSha256Digest = sa.getNonResourceString(R.styleable
+                    .AndroidManifestUsesStaticLibrary_certDigest);
+
+            // Since an APK providing a static shared lib can only provide the lib - fail if
+            // malformed
+            if (lname == null || version < 0 || certSha256Digest == null) {
+                return input.error("Bad uses-static-library declaration name: " + lname
+                        + " version: " + version + " certDigest" + certSha256Digest);
+            }
+
+            // Can depend only on one version of the same library
+            List<String> usesStaticLibraries = pkg.getUsesStaticLibraries();
+            if (usesStaticLibraries.contains(lname)) {
+                return input.error(
+                        "Depending on multiple versions of static library " + lname);
+            }
+
+            lname = lname.intern();
+            // We allow ":" delimiters in the SHA declaration as this is the format
+            // emitted by the certtool making it easy for developers to copy/paste.
+            certSha256Digest = certSha256Digest.replace(":", "").toLowerCase();
+
+            // Fot apps targeting O-MR1 we require explicit enumeration of all certs.
+            String[] additionalCertSha256Digests = EmptyArray.STRING;
+            if (pkg.getTargetSdkVersion() >= Build.VERSION_CODES.O_MR1) {
+                ParseResult<String[]> certResult = parseAdditionalCertificates(input, res, parser);
+                if (certResult.isError()) {
+                    return input.error(certResult);
+                }
+                additionalCertSha256Digests = certResult.getResult();
+            }
+
+            final String[] certSha256Digests = new String[additionalCertSha256Digests.length + 1];
+            certSha256Digests[0] = certSha256Digest;
+            System.arraycopy(additionalCertSha256Digests, 0, certSha256Digests,
+                    1, additionalCertSha256Digests.length);
+
+            return input.success(pkg.addUsesStaticLibrary(lname)
+                    .addUsesStaticLibraryVersion(version)
+                    .addUsesStaticLibraryCertDigests(certSha256Digests));
+        } finally {
+            sa.recycle();
+        }
+    }
+
+    @NonNull
+    private static ParseResult<ParsingPackage> parseUsesLibrary(ParseInput input,
+            ParsingPackage pkg, Resources res, XmlResourceParser parser) {
+        TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestUsesLibrary);
+        try {
+            // Note: don't allow this value to be a reference to a resource
+            // that may change.
+            String lname = sa.getNonResourceString(R.styleable.AndroidManifestUsesLibrary_name);
+            boolean req = sa.getBoolean(R.styleable.AndroidManifestUsesLibrary_required, true);
+
+            if (lname != null) {
+                lname = lname.intern();
+                if (req) {
+                    // Upgrade to treat as stronger constraint
+                    pkg.addUsesLibrary(lname)
+                            .removeUsesOptionalLibrary(lname);
+                } else {
+                    // Ignore if someone already defined as required
+                    if (!ArrayUtils.contains(pkg.getUsesLibraries(), lname)) {
+                        pkg.addUsesOptionalLibrary(lname);
+                    }
+                }
+            }
+
+            return input.success(pkg);
+        } finally {
+            sa.recycle();
+        }
+    }
+
+    @NonNull
+    private static ParseResult<ParsingPackage> parseProcesses(ParseInput input, ParsingPackage pkg,
+            Resources res, XmlResourceParser parser, String[] separateProcesses, int flags)
+            throws IOException, XmlPullParserException {
+        ParseResult<ArrayMap<String, ParsedProcess>> result =
+                ParsedProcessUtils.parseProcesses(separateProcesses, pkg, res, parser, flags,
+                        input);
+        if (result.isError()) {
+            return input.error(result);
+        }
+
+        return input.success(pkg.setProcesses(result.getResult()));
+    }
+
+    @NonNull
+    private static ParseResult<ParsingPackage> parseProfileable(ParseInput input,
+            ParsingPackage pkg, Resources res, XmlResourceParser parser) {
+        TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestProfileable);
+        try {
+            return input.success(pkg.setProfileableByShell(pkg.isProfileableByShell()
+                    || bool(false, R.styleable.AndroidManifestProfileable_shell, sa)));
+        } finally {
+            sa.recycle();
+        }
+    }
+
+    private static ParseResult<String[]> parseAdditionalCertificates(ParseInput input,
+            Resources resources, XmlResourceParser parser)
+            throws XmlPullParserException, IOException {
+        String[] certSha256Digests = EmptyArray.STRING;
+        final int depth = parser.getDepth();
+        int type;
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG
+                || parser.getDepth() > depth)) {
+            if (type != XmlPullParser.START_TAG) {
+                continue;
+            }
+
+            final String nodeName = parser.getName();
+            if (nodeName.equals("additional-certificate")) {
+                TypedArray sa = resources.obtainAttributes(parser,
+                        R.styleable.AndroidManifestAdditionalCertificate);
+                try {
+                    String certSha256Digest = sa.getNonResourceString(
+                            R.styleable.AndroidManifestAdditionalCertificate_certDigest);
+
+                    if (TextUtils.isEmpty(certSha256Digest)) {
+                        return input.error("Bad additional-certificate declaration with empty"
+                                + " certDigest:" + certSha256Digest);
+                    }
+
+
+                    // We allow ":" delimiters in the SHA declaration as this is the format
+                    // emitted by the certtool making it easy for developers to copy/paste.
+                    certSha256Digest = certSha256Digest.replace(":", "").toLowerCase();
+                    certSha256Digests = ArrayUtils.appendElement(String.class,
+                            certSha256Digests, certSha256Digest);
+                } finally {
+                    sa.recycle();
+                }
+            }
+        }
+
+        return input.success(certSha256Digests);
+    }
+
+    /**
+     * Generate activity object that forwards user to App Details page automatically.
+     * This activity should be invisible to user and user should not know or see it.
+     */
+    @NonNull
+    private static ParseResult<ParsedActivity> generateAppDetailsHiddenActivity(ParseInput input,
+            ParsingPackage pkg) {
+        String packageName = pkg.getPackageName();
+        ParseResult<String> taskAffinityResult = ComponentParseUtils.buildTaskAffinityName(
+                packageName, packageName, ":app_details", input);
+
+        String taskAffinity;
+        if (taskAffinityResult.isSuccess()) {
+            taskAffinity = taskAffinityResult.getResult();
+        } else {
+            // Backwards-compat, do not fail
+            taskAffinity = null;
+            taskAffinityResult.ignoreError();
+        }
+
+        // Build custom App Details activity info instead of parsing it from xml
+        return input.success(ParsedActivity.makeAppDetailsActivity(packageName,
+                pkg.getProcessName(), pkg.getUiOptions(), taskAffinity,
+                pkg.isBaseHardwareAccelerated()));
+    }
+
+    /**
+     * Check if one of the IntentFilter as both actions DEFAULT / VIEW and a HTTP/HTTPS data URI
+     */
+    private static boolean hasDomainURLs(ParsingPackage pkg) {
+        final List<ParsedActivity> activities = pkg.getActivities();
+        final int activitiesSize = activities.size();
+        for (int index = 0; index < activitiesSize; index++) {
+            ParsedActivity activity = activities.get(index);
+            List<ParsedIntentInfo> filters = activity.getIntents();
+            final int filtersSize = filters.size();
+            for (int filtersIndex = 0; filtersIndex < filtersSize; filtersIndex++) {
+                ParsedIntentInfo aii = filters.get(filtersIndex);
+                if (!aii.hasAction(Intent.ACTION_VIEW)) continue;
+                if (!aii.hasAction(Intent.ACTION_DEFAULT)) continue;
+                if (aii.hasDataScheme(IntentFilter.SCHEME_HTTP) ||
+                        aii.hasDataScheme(IntentFilter.SCHEME_HTTPS)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Sets the max aspect ratio of every child activity that doesn't already have an aspect
+     * ratio set.
+     */
+    private static void setMaxAspectRatio(ParsingPackage pkg) {
+        // Default to (1.86) 16.7:9 aspect ratio for pre-O apps and unset for O and greater.
+        // NOTE: 16.7:9 was the max aspect ratio Android devices can support pre-O per the CDD.
+        float maxAspectRatio = pkg.getTargetSdkVersion() < O
+                ? PackageParser.DEFAULT_PRE_O_MAX_ASPECT_RATIO : 0;
+
+        float packageMaxAspectRatio = pkg.getMaxAspectRatio();
+        if (packageMaxAspectRatio != 0) {
+            // Use the application max aspect ration as default if set.
+            maxAspectRatio = packageMaxAspectRatio;
+        } else {
+            Bundle appMetaData = pkg.getMetaData();
+            if (appMetaData != null && appMetaData.containsKey(
+                    PackageParser.METADATA_MAX_ASPECT_RATIO)) {
+                maxAspectRatio = appMetaData.getFloat(PackageParser.METADATA_MAX_ASPECT_RATIO,
+                        maxAspectRatio);
+            }
+        }
+
+        List<ParsedActivity> activities = pkg.getActivities();
+        int activitiesSize = activities.size();
+        for (int index = 0; index < activitiesSize; index++) {
+            ParsedActivity activity = activities.get(index);
+            // If the max aspect ratio for the activity has already been set, skip.
+            if (activity.getMaxAspectRatio() != null) {
+                continue;
+            }
+
+            // By default we prefer to use a values defined on the activity directly than values
+            // defined on the application. We do not check the styled attributes on the activity
+            // as it would have already been set when we processed the activity. We wait to
+            // process the meta data here since this method is called at the end of processing
+            // the application and all meta data is guaranteed.
+            final float activityAspectRatio = activity.getMetaData() != null
+                    ? activity.getMetaData().getFloat(PackageParser.METADATA_MAX_ASPECT_RATIO,
+                    maxAspectRatio)
+                    : maxAspectRatio;
+
+            activity.setMaxAspectRatio(activity.getResizeMode(), activityAspectRatio);
+        }
+    }
+
+    /**
+     * Sets the min aspect ratio of every child activity that doesn't already have an aspect
+     * ratio set.
+     */
+    private void setMinAspectRatio(ParsingPackage pkg) {
+        final float minAspectRatio;
+        float packageMinAspectRatio = pkg.getMinAspectRatio();
+        if (packageMinAspectRatio != 0) {
+            // Use the application max aspect ration as default if set.
+            minAspectRatio = packageMinAspectRatio;
+        } else {
+            // Default to (1.33) 4:3 aspect ratio for pre-Q apps and unset for Q and greater.
+            // NOTE: 4:3 was the min aspect ratio Android devices can support pre-Q per the CDD,
+            // except for watches which always supported 1:1.
+            minAspectRatio = pkg.getTargetSdkVersion() >= Build.VERSION_CODES.Q
+                    ? 0
+                    : (mCallback != null && mCallback.hasFeature(FEATURE_WATCH))
+                            ? PackageParser.DEFAULT_PRE_Q_MIN_ASPECT_RATIO_WATCH
+                            : PackageParser.DEFAULT_PRE_Q_MIN_ASPECT_RATIO;
+        }
+
+        List<ParsedActivity> activities = pkg.getActivities();
+        int activitiesSize = activities.size();
+        for (int index = 0; index < activitiesSize; index++) {
+            ParsedActivity activity = activities.get(index);
+            if (activity.getMinAspectRatio() == null) {
+                activity.setMinAspectRatio(activity.getResizeMode(), minAspectRatio);
+            }
+        }
+    }
+
+    private static ParseResult<ParsingPackage> parseOverlay(ParseInput input, ParsingPackage pkg,
+            Resources res, XmlResourceParser parser) {
+        TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestResourceOverlay);
+        try {
+            String target = sa.getString(R.styleable.AndroidManifestResourceOverlay_targetPackage);
+            int priority = anInt(0, R.styleable.AndroidManifestResourceOverlay_priority, sa);
+
+            if (target == null) {
+                return input.error("<overlay> does not specify a target package");
+            } else if (priority < 0 || priority > 9999) {
+                return input.error("<overlay> priority must be between 0 and 9999");
+            }
+
+            // check to see if overlay should be excluded based on system property condition
+            String propName = sa.getString(
+                    R.styleable.AndroidManifestResourceOverlay_requiredSystemPropertyName);
+            String propValue = sa.getString(
+                    R.styleable.AndroidManifestResourceOverlay_requiredSystemPropertyValue);
+            if (!checkOverlayRequiredSystemProperty(propName, propValue)) {
+                Slog.i(TAG, "Skipping target and overlay pair " + target + " and "
+                        + pkg.getBaseCodePath()
+                        + ": overlay ignored due to required system property: "
+                        + propName + " with value: " + propValue);
+                return input.error("Skipping target and overlay pair " + target + " and "
+                        + pkg.getBaseCodePath()
+                        + ": overlay ignored due to required system property: "
+                        + propName + " with value: " + propValue);
+            }
+
+            return input.success(pkg.setOverlay(true)
+                    .setOverlayTarget(target)
+                    .setOverlayPriority(priority)
+                    .setOverlayTargetName(
+                            sa.getString(R.styleable.AndroidManifestResourceOverlay_targetName))
+                    .setOverlayCategory(
+                            sa.getString(R.styleable.AndroidManifestResourceOverlay_category))
+                    .setOverlayIsStatic(
+                            bool(false, R.styleable.AndroidManifestResourceOverlay_isStatic, sa)));
+        } finally {
+            sa.recycle();
+        }
+    }
+
+    private static ParseResult<ParsingPackage> parseProtectedBroadcast(ParseInput input,
+            ParsingPackage pkg, Resources res, XmlResourceParser parser) {
+        TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestProtectedBroadcast);
+        try {
+            // Note: don't allow this value to be a reference to a resource
+            // that may change.
+            String name = nonResString(R.styleable.AndroidManifestProtectedBroadcast_name, sa);
+            if (name != null) {
+                pkg.addProtectedBroadcast(name);
+            }
+            return input.success(pkg);
+        } finally {
+            sa.recycle();
+        }
+    }
+
+    private static ParseResult<ParsingPackage> parseSupportScreens(ParseInput input,
+            ParsingPackage pkg, Resources res, XmlResourceParser parser) {
+        TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestSupportsScreens);
+        try {
+            int requiresSmallestWidthDp = anInt(0,
+                    R.styleable.AndroidManifestSupportsScreens_requiresSmallestWidthDp, sa);
+            int compatibleWidthLimitDp = anInt(0,
+                    R.styleable.AndroidManifestSupportsScreens_compatibleWidthLimitDp, sa);
+            int largestWidthLimitDp = anInt(0,
+                    R.styleable.AndroidManifestSupportsScreens_largestWidthLimitDp, sa);
+
+            // This is a trick to get a boolean and still able to detect
+            // if a value was actually set.
+            return input.success(pkg
+                    .setSupportsSmallScreens(
+                            anInt(1, R.styleable.AndroidManifestSupportsScreens_smallScreens, sa))
+                    .setSupportsNormalScreens(
+                            anInt(1, R.styleable.AndroidManifestSupportsScreens_normalScreens, sa))
+                    .setSupportsLargeScreens(
+                            anInt(1, R.styleable.AndroidManifestSupportsScreens_largeScreens, sa))
+                    .setSupportsExtraLargeScreens(
+                            anInt(1, R.styleable.AndroidManifestSupportsScreens_xlargeScreens, sa))
+                    .setResizeable(
+                            anInt(1, R.styleable.AndroidManifestSupportsScreens_resizeable, sa))
+                    .setAnyDensity(
+                            anInt(1, R.styleable.AndroidManifestSupportsScreens_anyDensity, sa))
+                    .setRequiresSmallestWidthDp(requiresSmallestWidthDp)
+                    .setCompatibleWidthLimitDp(compatibleWidthLimitDp)
+                    .setLargestWidthLimitDp(largestWidthLimitDp));
+        } finally {
+            sa.recycle();
+        }
+    }
+
+    private static ParseResult<ParsingPackage> parseInstrumentation(ParseInput input,
+            ParsingPackage pkg, Resources res, XmlResourceParser parser)
+            throws XmlPullParserException, IOException {
+        ParseResult<ParsedInstrumentation> result = ParsedInstrumentationUtils.parseInstrumentation(
+                pkg, res, parser, PackageParser.sUseRoundIcon, input);
+        if (result.isError()) {
+            return input.error(result);
+        }
+        return input.success(pkg.addInstrumentation(result.getResult()));
+    }
+
+    private static ParseResult<ParsingPackage> parseOriginalPackage(ParseInput input,
+            ParsingPackage pkg, Resources res, XmlResourceParser parser) {
+        TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestOriginalPackage);
+        try {
+            String orig = sa.getNonConfigurationString(
+                    R.styleable.AndroidManifestOriginalPackage_name,
+                    0);
+            if (!pkg.getPackageName().equals(orig)) {
+                if (pkg.getOriginalPackages().isEmpty()) {
+                    pkg.setRealPackage(pkg.getPackageName());
+                }
+                pkg.addOriginalPackage(orig);
+            }
+            return input.success(pkg);
+        } finally {
+            sa.recycle();
+        }
+    }
+
+    private static ParseResult<ParsingPackage> parseAdoptPermissions(ParseInput input,
+            ParsingPackage pkg, Resources res, XmlResourceParser parser) {
+        TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestOriginalPackage);
+        try {
+            String name = nonConfigString(0, R.styleable.AndroidManifestOriginalPackage_name, sa);
+            if (name != null) {
+                pkg.addAdoptPermission(name);
+            }
+            return input.success(pkg);
+        } finally {
+            sa.recycle();
+        }
+    }
+
+    private static void convertNewPermissions(ParsingPackage pkg) {
+        final int NP = PackageParser.NEW_PERMISSIONS.length;
+        StringBuilder newPermsMsg = null;
+        for (int ip = 0; ip < NP; ip++) {
+            final PackageParser.NewPermissionInfo npi
+                    = PackageParser.NEW_PERMISSIONS[ip];
+            if (pkg.getTargetSdkVersion() >= npi.sdkVersion) {
+                break;
+            }
+            if (!pkg.getRequestedPermissions().contains(npi.name)) {
+                if (newPermsMsg == null) {
+                    newPermsMsg = new StringBuilder(128);
+                    newPermsMsg.append(pkg.getPackageName());
+                    newPermsMsg.append(": compat added ");
+                } else {
+                    newPermsMsg.append(' ');
+                }
+                newPermsMsg.append(npi.name);
+                pkg.addRequestedPermission(npi.name)
+                        .addImplicitPermission(npi.name);
+            }
+        }
+        if (newPermsMsg != null) {
+            Slog.i(TAG, newPermsMsg.toString());
+        }
+    }
+
+    private static void convertSplitPermissions(ParsingPackage pkg) {
+        List<SplitPermissionInfoParcelable> splitPermissions;
+
+        try {
+            splitPermissions = ActivityThread.getPermissionManager().getSplitPermissions();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+
+        final int listSize = splitPermissions.size();
+        for (int is = 0; is < listSize; is++) {
+            final SplitPermissionInfoParcelable spi = splitPermissions.get(is);
+            List<String> requestedPermissions = pkg.getRequestedPermissions();
+            if (pkg.getTargetSdkVersion() >= spi.getTargetSdk()
+                    || !requestedPermissions.contains(spi.getSplitPermission())) {
+                continue;
+            }
+            final List<String> newPerms = spi.getNewPermissions();
+            for (int in = 0; in < newPerms.size(); in++) {
+                final String perm = newPerms.get(in);
+                if (!requestedPermissions.contains(perm)) {
+                    pkg.addRequestedPermission(perm)
+                            .addImplicitPermission(perm);
+                }
+            }
+        }
+    }
+
+    private static boolean checkOverlayRequiredSystemProperty(String propName, String propValue) {
+        if (TextUtils.isEmpty(propName) || TextUtils.isEmpty(propValue)) {
+            if (!TextUtils.isEmpty(propName) || !TextUtils.isEmpty(propValue)) {
+                // malformed condition - incomplete
+                Slog.w(TAG, "Disabling overlay - incomplete property :'" + propName
+                        + "=" + propValue + "' - require both requiredSystemPropertyName"
+                        + " AND requiredSystemPropertyValue to be specified.");
+                return false;
+            }
+            // no valid condition set - so no exclusion criteria, overlay will be included.
+            return true;
+        }
+
+        // check property value - make sure it is both set and equal to expected value
+        final String currValue = SystemProperties.get(propName);
+        return (currValue != null && currValue.equals(propValue));
+    }
+
+    /**
+     * This is a pre-density application which will get scaled - instead of being pixel perfect.
+     * This type of application is not resizable.
+     *
+     * @param pkg The package which needs to be marked as unresizable.
+     */
+    private static void adjustPackageToBeUnresizeableAndUnpipable(ParsingPackage pkg) {
+        List<ParsedActivity> activities = pkg.getActivities();
+        int activitiesSize = activities.size();
+        for (int index = 0; index < activitiesSize; index++) {
+            ParsedActivity activity = activities.get(index);
+            activity.setResizeMode(RESIZE_MODE_UNRESIZEABLE)
+                    .setFlags(activity.getFlags() & ~FLAG_SUPPORTS_PICTURE_IN_PICTURE);
+        }
+    }
+
+    private static ParseResult validateName(ParseInput input, String name, boolean requireSeparator,
+            boolean requireFilename) {
+        final int N = name.length();
+        boolean hasSep = false;
+        boolean front = true;
+        for (int i = 0; i < N; i++) {
+            final char c = name.charAt(i);
+            if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
+                front = false;
+                continue;
+            }
+            if (!front) {
+                if ((c >= '0' && c <= '9') || c == '_') {
+                    continue;
+                }
+            }
+            if (c == '.') {
+                hasSep = true;
+                front = true;
+                continue;
+            }
+            return input.error("bad character '" + c + "'");
+        }
+        if (requireFilename && !FileUtils.isValidExtFilename(name)) {
+            return input.error("Invalid filename");
+        }
+        return hasSep || !requireSeparator
+                ? input.success(null)
+                : input.error("must have at least one '.' separator");
+    }
+
+    public static ParseResult<Bundle> parseMetaData(ParsingPackage pkg, Resources res,
+            XmlResourceParser parser, Bundle data, ParseInput input) {
+        TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestMetaData);
+        try {
+            if (data == null) {
+                data = new Bundle();
+            }
+
+            String name = TextUtils.safeIntern(
+                    nonConfigString(0, R.styleable.AndroidManifestMetaData_name, sa));
+            if (name == null) {
+                return input.error("<meta-data> requires an android:name attribute");
+            }
+
+            TypedValue v = sa.peekValue(R.styleable.AndroidManifestMetaData_resource);
+            if (v != null && v.resourceId != 0) {
+                //Slog.i(TAG, "Meta data ref " + name + ": " + v);
+                data.putInt(name, v.resourceId);
+            } else {
+                v = sa.peekValue(R.styleable.AndroidManifestMetaData_value);
+                //Slog.i(TAG, "Meta data " + name + ": " + v);
+                if (v != null) {
+                    if (v.type == TypedValue.TYPE_STRING) {
+                        CharSequence cs = v.coerceToString();
+                        data.putString(name, cs != null ? cs.toString() : null);
+                    } else if (v.type == TypedValue.TYPE_INT_BOOLEAN) {
+                        data.putBoolean(name, v.data != 0);
+                    } else if (v.type >= TypedValue.TYPE_FIRST_INT
+                            && v.type <= TypedValue.TYPE_LAST_INT) {
+                        data.putInt(name, v.data);
+                    } else if (v.type == TypedValue.TYPE_FLOAT) {
+                        data.putFloat(name, v.getFloat());
+                    } else {
+                        if (!PackageParser.RIGID_PARSER) {
+                            Slog.w(TAG,
+                                    "<meta-data> only supports string, integer, float, color, "
+                                            + "boolean, and resource reference types: "
+                                            + parser.getName() + " at "
+                                            + pkg.getBaseCodePath() + " "
+                                            + parser.getPositionDescription());
+                        } else {
+                            return input.error("<meta-data> only supports string, integer, float, "
+                                    + "color, boolean, and resource reference types");
+                        }
+                    }
+                } else {
+                    return input.error("<meta-data> requires an android:value "
+                            + "or android:resource attribute");
+                }
+            }
+            return input.success(data);
+        } finally {
+            sa.recycle();
+        }
+    }
+
+    /**
+     * Collect certificates from all the APKs described in the given package. Also asserts that
+     * all APK contents are signed correctly and consistently.
+     */
+    public static SigningDetails collectCertificates(ParsingPackageRead pkg, boolean skipVerify)
+            throws PackageParserException {
+        SigningDetails signingDetails = SigningDetails.UNKNOWN;
+
+        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates");
+        try {
+            signingDetails = collectCertificates(
+                    pkg.getBaseCodePath(),
+                    skipVerify,
+                    pkg.isStaticSharedLibrary(),
+                    signingDetails,
+                    pkg.getTargetSdkVersion()
+            );
+
+            String[] splitCodePaths = pkg.getSplitCodePaths();
+            if (!ArrayUtils.isEmpty(splitCodePaths)) {
+                for (int i = 0; i < splitCodePaths.length; i++) {
+                    signingDetails = collectCertificates(
+                            splitCodePaths[i],
+                            skipVerify,
+                            pkg.isStaticSharedLibrary(),
+                            signingDetails,
+                            pkg.getTargetSdkVersion()
+                    );
+                }
+            }
+            return signingDetails;
+        } finally {
+            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+        }
+    }
+
+    public static SigningDetails collectCertificates(String baseCodePath, boolean skipVerify,
+            boolean isStaticSharedLibrary, @NonNull SigningDetails existingSigningDetails,
+            int targetSdk) throws PackageParserException {
+        int minSignatureScheme = ApkSignatureVerifier.getMinimumSignatureSchemeVersionForTargetSdk(
+                targetSdk);
+        if (isStaticSharedLibrary) {
+            // must use v2 signing scheme
+            minSignatureScheme = SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V2;
+        }
+        SigningDetails verified;
+        if (skipVerify) {
+            // systemDir APKs are already trusted, save time by not verifying
+            verified = ApkSignatureVerifier.unsafeGetCertsWithoutVerification(
+                    baseCodePath, minSignatureScheme);
+        } else {
+            verified = ApkSignatureVerifier.verify(baseCodePath, minSignatureScheme);
+        }
+
+        // Verify that entries are signed consistently with the first pkg
+        // we encountered. Note that for splits, certificates may have
+        // already been populated during an earlier parse of a base APK.
+        if (existingSigningDetails == SigningDetails.UNKNOWN) {
+            return verified;
+        } else {
+            if (!Signature.areExactMatch(existingSigningDetails.signatures, verified.signatures)) {
+                throw new PackageParserException(
+                        INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES,
+                        baseCodePath + " has mismatched certificates");
+            }
+
+            return existingSigningDetails;
+        }
+    }
+
+    /*
+     The following set of methods makes code easier to read by re-ordering the TypedArray methods.
+
+     The first parameter is the default, which is the most important to understand for someone
+     reading through the parsing code.
+
+     That's followed by the attribute name, which is usually irrelevant during reading because
+     it'll look like setSomeValue(true, R.styleable.ReallyLongParentName_SomeValueAttr... and
+     the "setSomeValue" part is enough to communicate what the line does.
+
+     Last comes the TypedArray, which is by far the least important since each try-with-resources
+     should only have 1.
+    */
+
+    // Note there is no variant of bool without a defaultValue parameter, since explicit true/false
+    // is important to specify when adding an attribute.
+    private static boolean bool(boolean defaultValue, @StyleableRes int attribute, TypedArray sa) {
+        return sa.getBoolean(attribute, defaultValue);
+    }
+
+    private static float aFloat(float defaultValue, @StyleableRes int attribute, TypedArray sa) {
+        return sa.getFloat(attribute, defaultValue);
+    }
+
+    private static float aFloat(@StyleableRes int attribute, TypedArray sa) {
+        return sa.getFloat(attribute, 0f);
+    }
+
+    private static int anInt(int defaultValue, @StyleableRes int attribute, TypedArray sa) {
+        return sa.getInt(attribute, defaultValue);
+    }
+
+    private static int anInt(@StyleableRes int attribute, TypedArray sa) {
+        return sa.getInt(attribute, 0);
+    }
+
+    @AnyRes
+    private static int resId(@StyleableRes int attribute, TypedArray sa) {
+        return sa.getResourceId(attribute, 0);
+    }
+
+    private static String string(@StyleableRes int attribute, TypedArray sa) {
+        return sa.getString(attribute);
+    }
+
+    private static String nonConfigString(int allowedChangingConfigs, @StyleableRes int attribute,
+            TypedArray sa) {
+        return sa.getNonConfigurationString(attribute, allowedChangingConfigs);
+    }
+
+    private static String nonResString(@StyleableRes int index, TypedArray sa) {
+        return sa.getNonResourceString(index);
+    }
+
+    /**
+     * 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..ba61de1
--- /dev/null
+++ b/core/java/android/content/pm/parsing/ParsingUtils.java
@@ -0,0 +1,70 @@
+/*
+ * 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.NonNull;
+import android.annotation.Nullable;
+import android.content.pm.PackageParser;
+import android.content.pm.parsing.result.ParseInput;
+import android.content.pm.parsing.result.ParseResult;
+import android.content.res.XmlResourceParser;
+import android.util.Slog;
+
+import com.android.internal.util.XmlUtils;
+
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+
+/** @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;
+    }
+
+    @NonNull
+    public static ParseResult unknownTag(String parentTag, ParsingPackage pkg,
+            XmlResourceParser parser, ParseInput input) throws IOException, XmlPullParserException {
+        if (PackageParser.RIGID_PARSER) {
+            return input.error("Bad element under " + parentTag + ": " + parser.getName());
+        }
+        Slog.w(TAG, "Unknown element under " + parentTag + ": "
+                + parser.getName() + " at " + pkg.getBaseCodePath() + " "
+                + parser.getPositionDescription());
+        XmlUtils.skipCurrentTag(parser);
+        return input.success(null); // Type doesn't matter
+    }
+}
diff --git a/core/java/android/content/pm/parsing/component/ComponentParseUtils.java b/core/java/android/content/pm/parsing/component/ComponentParseUtils.java
new file mode 100644
index 0000000..c4caedc
--- /dev/null
+++ b/core/java/android/content/pm/parsing/component/ComponentParseUtils.java
@@ -0,0 +1,178 @@
+/*
+ * 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.component;
+
+import android.annotation.AttrRes;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Intent;
+import android.content.pm.PackageParser;
+import android.content.pm.PackageUserState;
+import android.content.pm.parsing.ParsingPackage;
+import android.content.pm.parsing.ParsingUtils;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
+import android.text.TextUtils;
+
+import android.content.pm.parsing.ParsingPackageUtils;
+import android.content.pm.parsing.result.ParseInput;
+import android.content.pm.parsing.result.ParseResult;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+
+/** @hide */
+public class ComponentParseUtils {
+
+    private static final String TAG = ParsingPackageUtils.TAG;
+
+    public static boolean isImplicitlyExposedIntent(ParsedIntentInfo intentInfo) {
+        return intentInfo.hasCategory(Intent.CATEGORY_BROWSABLE)
+                || intentInfo.hasAction(Intent.ACTION_SEND)
+                || intentInfo.hasAction(Intent.ACTION_SENDTO)
+                || intentInfo.hasAction(Intent.ACTION_SEND_MULTIPLE);
+    }
+
+    static <Component extends ParsedComponent> ParseResult<Component> parseAllMetaData(
+            ParsingPackage pkg, Resources res, XmlResourceParser parser, String tag,
+            Component component, ParseInput input) throws XmlPullParserException, IOException {
+        final int depth = parser.getDepth();
+        int type;
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG || parser.getDepth() > depth)) {
+            if (type != XmlPullParser.START_TAG) {
+                continue;
+            }
+
+            final ParseResult result;
+            if ("meta-data".equals(parser.getName())) {
+                result = ParsedComponentUtils.addMetaData(component, pkg, res, parser, input);
+            } else {
+                result = ParsingUtils.unknownTag(tag, pkg, parser, input);
+            }
+
+            if (result.isError()) {
+                return input.error(result);
+            }
+        }
+
+        return input.success(component);
+    }
+
+    @NonNull
+    public static ParseResult<String> buildProcessName(@NonNull String pkg, String defProc,
+            CharSequence procSeq, int flags, String[] separateProcesses, ParseInput input) {
+        if ((flags & PackageParser.PARSE_IGNORE_PROCESSES) != 0 && !"system".contentEquals(
+                procSeq)) {
+            return input.success(defProc != null ? defProc : pkg);
+        }
+        if (separateProcesses != null) {
+            for (int i = separateProcesses.length - 1; i >= 0; i--) {
+                String sp = separateProcesses[i];
+                if (sp.equals(pkg) || sp.equals(defProc) || sp.contentEquals(procSeq)) {
+                    return input.success(pkg);
+                }
+            }
+        }
+        if (procSeq == null || procSeq.length() <= 0) {
+            return input.success(defProc);
+        }
+
+        ParseResult<String> nameResult = ComponentParseUtils.buildCompoundName(pkg, procSeq,
+                "process", input);
+        return input.success(TextUtils.safeIntern(nameResult.getResult()));
+    }
+
+    @NonNull
+    public static ParseResult<String> buildTaskAffinityName(String pkg, String defProc,
+            CharSequence procSeq, ParseInput input) {
+        if (procSeq == null) {
+            return input.success(defProc);
+        }
+        if (procSeq.length() <= 0) {
+            return input.success(null);
+        }
+        return buildCompoundName(pkg, procSeq, "taskAffinity", input);
+    }
+
+    public static ParseResult<String> buildCompoundName(String pkg, CharSequence procSeq,
+            String type, ParseInput input) {
+        String proc = procSeq.toString();
+        char c = proc.charAt(0);
+        if (pkg != null && c == ':') {
+            if (proc.length() < 2) {
+                return input.error("Bad " + type + " name " + proc + " in package " + pkg
+                        + ": must be at least two characters");
+            }
+            String subName = proc.substring(1);
+            String nameError = PackageParser.validateName(subName, false, false);
+            if (nameError != null) {
+                return input.error("Invalid " + type + " name " + proc + " in package " + pkg
+                        + ": " + nameError);
+            }
+            return input.success(pkg + proc);
+        }
+        String nameError = PackageParser.validateName(proc, true, false);
+        if (nameError != null && !"system".equals(proc)) {
+            return input.error("Invalid " + type + " name " + proc + " in package " + pkg
+                    + ": " + nameError);
+        }
+        return input.success(proc);
+    }
+
+    public static int flag(int flag, @AttrRes int attribute, TypedArray typedArray) {
+        return typedArray.getBoolean(attribute, false) ? flag : 0;
+    }
+
+    public static int flag(int flag, @AttrRes int attribute, boolean defaultValue,
+            TypedArray typedArray) {
+        return typedArray.getBoolean(attribute, defaultValue) ? flag : 0;
+    }
+
+    /**
+     * This is not state aware. Avoid and access through PackageInfoUtils in the system server.
+     */
+    @Nullable
+    public static CharSequence getNonLocalizedLabel(
+            ParsedComponent component) {
+        return component.nonLocalizedLabel;
+    }
+
+    /**
+     * This is not state aware. Avoid and access through PackageInfoUtils in the system server.
+     *
+     * This is a method of the utility class to discourage use.
+     */
+    public static int getIcon(ParsedComponent component) {
+        return component.icon;
+    }
+
+    public static boolean isMatch(PackageUserState state, boolean isSystem,
+            boolean isPackageEnabled, ParsedMainComponent component, int flags) {
+        return state.isMatch(isSystem, isPackageEnabled, component.isEnabled(),
+                component.isDirectBootAware(), component.getName(), flags);
+    }
+
+    public static boolean isEnabled(PackageUserState state, boolean isPackageEnabled,
+            ParsedMainComponent parsedComponent, int flags) {
+        return state.isEnabled(isPackageEnabled, parsedComponent.isEnabled(),
+                parsedComponent.getName(), flags);
+    }
+}
diff --git a/core/java/android/content/pm/parsing/component/ParsedActivity.java b/core/java/android/content/pm/parsing/component/ParsedActivity.java
new file mode 100644
index 0000000..5495c22
--- /dev/null
+++ b/core/java/android/content/pm/parsing/component/ParsedActivity.java
@@ -0,0 +1,451 @@
+/*
+ * 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.component;
+
+import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+import static android.content.pm.parsing.ParsingPackageImpl.sForString;
+import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_UNSPECIFIED;
+
+import android.annotation.Nullable;
+import android.app.ActivityTaskManager;
+import android.content.ComponentName;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageParser;
+import android.content.pm.parsing.ParsingPackageImpl;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
+
+import com.android.internal.util.DataClass;
+import com.android.internal.util.Parcelling;
+import com.android.internal.util.Parcelling.BuiltIn.ForInternedString;
+
+/** @hide **/
+public class ParsedActivity extends ParsedMainComponent {
+
+    int theme;
+    int uiOptions;
+
+    @Nullable
+    @DataClass.ParcelWith(ForInternedString.class)
+    private String targetActivity;
+
+    @Nullable
+    @DataClass.ParcelWith(ForInternedString.class)
+    private String parentActivityName;
+    @Nullable
+    String taskAffinity;
+    int privateFlags;
+    @Nullable
+    @DataClass.ParcelWith(ForInternedString.class)
+    private String permission;
+
+    int launchMode;
+    int documentLaunchMode;
+    int maxRecents;
+    int configChanges;
+    int softInputMode;
+    int persistableMode;
+    int lockTaskLaunchMode;
+
+    int screenOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+    int resizeMode = ActivityInfo.RESIZE_MODE_RESIZEABLE;
+
+    @Nullable
+    private Float maxAspectRatio;
+
+    @Nullable
+    private Float minAspectRatio;
+
+    @Nullable
+    String requestedVrComponent;
+    int rotationAnimation = -1;
+    int colorMode;
+
+    boolean preferMinimalPostProcessing;
+
+    @Nullable
+    ActivityInfo.WindowLayout windowLayout;
+
+    public ParsedActivity(ParsedActivity other) {
+        super(other);
+        this.theme = other.theme;
+        this.uiOptions = other.uiOptions;
+        this.targetActivity = other.targetActivity;
+        this.parentActivityName = other.parentActivityName;
+        this.taskAffinity = other.taskAffinity;
+        this.privateFlags = other.privateFlags;
+        this.permission = other.permission;
+        this.launchMode = other.launchMode;
+        this.documentLaunchMode = other.documentLaunchMode;
+        this.maxRecents = other.maxRecents;
+        this.configChanges = other.configChanges;
+        this.softInputMode = other.softInputMode;
+        this.persistableMode = other.persistableMode;
+        this.lockTaskLaunchMode = other.lockTaskLaunchMode;
+        this.screenOrientation = other.screenOrientation;
+        this.resizeMode = other.resizeMode;
+        this.maxAspectRatio = other.maxAspectRatio;
+        this.minAspectRatio = other.minAspectRatio;
+        this.requestedVrComponent = other.requestedVrComponent;
+        this.rotationAnimation = other.rotationAnimation;
+        this.colorMode = other.colorMode;
+        this.windowLayout = other.windowLayout;
+    }
+
+    /**
+     * Generate activity object that forwards user to App Details page automatically.
+     * This activity should be invisible to user and user should not know or see it.
+     */
+    public static ParsedActivity makeAppDetailsActivity(String packageName, String processName,
+            int uiOptions, String taskAffinity, boolean hardwareAccelerated) {
+        ParsedActivity activity = new ParsedActivity();
+        activity.setPackageName(packageName);
+        activity.theme = android.R.style.Theme_NoDisplay;
+        activity.exported = true;
+        activity.setName(PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME);
+        activity.setProcessName(processName);
+        activity.uiOptions = uiOptions;
+        activity.taskAffinity = taskAffinity;
+        activity.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
+        activity.documentLaunchMode = ActivityInfo.DOCUMENT_LAUNCH_NONE;
+        activity.maxRecents = ActivityTaskManager.getDefaultAppRecentsLimitStatic();
+        activity.configChanges = PackageParser.getActivityConfigChanges(0, 0);
+        activity.softInputMode = 0;
+        activity.persistableMode = ActivityInfo.PERSIST_NEVER;
+        activity.screenOrientation = SCREEN_ORIENTATION_UNSPECIFIED;
+        activity.resizeMode = RESIZE_MODE_FORCE_RESIZEABLE;
+        activity.lockTaskLaunchMode = 0;
+        activity.setDirectBootAware(false);
+        activity.rotationAnimation = ROTATION_ANIMATION_UNSPECIFIED;
+        activity.colorMode = ActivityInfo.COLOR_MODE_DEFAULT;
+        activity.preferMinimalPostProcessing = ActivityInfo.MINIMAL_POST_PROCESSING_DEFAULT;
+        if (hardwareAccelerated) {
+            activity.setFlags(activity.getFlags() | ActivityInfo.FLAG_HARDWARE_ACCELERATED);
+        }
+        return activity;
+    }
+
+    static ParsedActivity makeAlias(String targetActivityName, ParsedActivity target) {
+        ParsedActivity alias = new ParsedActivity();
+        alias.setPackageName(target.getPackageName());
+        alias.setTargetActivity(targetActivityName);
+        alias.configChanges = target.configChanges;
+        alias.flags = target.flags;
+        alias.privateFlags = target.privateFlags;
+        alias.icon = target.icon;
+        alias.logo = target.logo;
+        alias.banner = target.banner;
+        alias.labelRes = target.labelRes;
+        alias.nonLocalizedLabel = target.nonLocalizedLabel;
+        alias.launchMode = target.launchMode;
+        alias.lockTaskLaunchMode = target.lockTaskLaunchMode;
+        alias.descriptionRes = target.descriptionRes;
+        alias.screenOrientation = target.screenOrientation;
+        alias.taskAffinity = target.taskAffinity;
+        alias.theme = target.theme;
+        alias.softInputMode = target.softInputMode;
+        alias.uiOptions = target.uiOptions;
+        alias.parentActivityName = target.parentActivityName;
+        alias.maxRecents = target.maxRecents;
+        alias.windowLayout = target.windowLayout;
+        alias.resizeMode = target.resizeMode;
+        alias.maxAspectRatio = target.maxAspectRatio;
+        alias.minAspectRatio = target.minAspectRatio;
+        alias.requestedVrComponent = target.requestedVrComponent;
+        alias.directBootAware = target.directBootAware;
+        alias.setProcessName(target.getProcessName());
+        return alias;
+
+        // 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.
+//        alias.enabled = target.enabled;
+//        alias.exported = target.exported;
+//        alias.permission = target.permission;
+//        alias.splitName = target.splitName;
+//        alias.documentLaunchMode = target.documentLaunchMode;
+//        alias.persistableMode = target.persistableMode;
+//        alias.rotationAnimation = target.rotationAnimation;
+//        alias.colorMode = target.colorMode;
+//        alias.intents.addAll(target.intents);
+//        alias.order = target.order;
+//        alias.metaData = target.metaData;
+    }
+
+    public ParsedActivity setMaxAspectRatio(int resizeMode, float maxAspectRatio) {
+        if (resizeMode == ActivityInfo.RESIZE_MODE_RESIZEABLE
+                || resizeMode == ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION) {
+            // Resizeable activities can be put in any aspect ratio.
+            return this;
+        }
+
+        if (maxAspectRatio < 1.0f && maxAspectRatio != 0) {
+            // Ignore any value lesser than 1.0.
+            return this;
+        }
+
+        this.maxAspectRatio = maxAspectRatio;
+        return this;
+    }
+
+    public ParsedActivity setMinAspectRatio(int resizeMode, float minAspectRatio) {
+        if (resizeMode == RESIZE_MODE_RESIZEABLE
+                || resizeMode == RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION) {
+            // Resizeable activities can be put in any aspect ratio.
+            return this;
+        }
+
+        if (minAspectRatio < 1.0f && minAspectRatio != 0) {
+            // Ignore any value lesser than 1.0.
+            return this;
+        }
+
+        this.minAspectRatio = minAspectRatio;
+        return this;
+    }
+
+    public ParsedActivity setFlags(int flags) {
+        this.flags = flags;
+        return this;
+    }
+
+    public ParsedActivity setResizeMode(int resizeMode) {
+        this.resizeMode = resizeMode;
+        return this;
+    }
+
+    public ParsedActivity setTargetActivity(String targetActivity) {
+        this.targetActivity = TextUtils.safeIntern(targetActivity);
+        return this;
+    }
+
+    public ParsedActivity setParentActivity(String parentActivity) {
+        this.parentActivityName = TextUtils.safeIntern(parentActivity);
+        return this;
+    }
+
+    public ParsedActivity setPermission(String permission) {
+        // Empty string must be converted to null
+        this.permission = TextUtils.isEmpty(permission) ? null : permission.intern();
+        return this;
+    }
+
+    public String toString() {
+        StringBuilder sb = new StringBuilder(128);
+        sb.append("Activity{");
+        sb.append(Integer.toHexString(System.identityHashCode(this)));
+        sb.append(' ');
+        ComponentName.appendShortString(sb, getPackageName(), getName());
+        sb.append('}');
+        return sb.toString();
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        super.writeToParcel(dest, flags);
+        dest.writeInt(this.theme);
+        dest.writeInt(this.uiOptions);
+        sForString.parcel(this.targetActivity, dest, flags);
+        sForString.parcel(this.parentActivityName, dest, flags);
+        dest.writeString(this.taskAffinity);
+        dest.writeInt(this.privateFlags);
+        sForString.parcel(this.permission, dest, flags);
+        dest.writeInt(this.launchMode);
+        dest.writeInt(this.documentLaunchMode);
+        dest.writeInt(this.maxRecents);
+        dest.writeInt(this.configChanges);
+        dest.writeInt(this.softInputMode);
+        dest.writeInt(this.persistableMode);
+        dest.writeInt(this.lockTaskLaunchMode);
+        dest.writeInt(this.screenOrientation);
+        dest.writeInt(this.resizeMode);
+        dest.writeValue(this.maxAspectRatio);
+        dest.writeValue(this.minAspectRatio);
+        dest.writeString(this.requestedVrComponent);
+        dest.writeInt(this.rotationAnimation);
+        dest.writeInt(this.colorMode);
+        dest.writeBoolean(this.preferMinimalPostProcessing);
+        dest.writeBundle(this.metaData);
+
+        if (windowLayout != null) {
+            dest.writeBoolean(true);
+            dest.writeInt(windowLayout.width);
+            dest.writeFloat(windowLayout.widthFraction);
+            dest.writeInt(windowLayout.height);
+            dest.writeFloat(windowLayout.heightFraction);
+            dest.writeInt(windowLayout.gravity);
+            dest.writeInt(windowLayout.minWidth);
+            dest.writeInt(windowLayout.minHeight);
+        } else {
+            dest.writeBoolean(false);
+        }
+    }
+
+    public ParsedActivity() {
+    }
+
+    protected ParsedActivity(Parcel in) {
+        super(in);
+        this.theme = in.readInt();
+        this.uiOptions = in.readInt();
+        this.targetActivity = sForString.unparcel(in);
+        this.parentActivityName = sForString.unparcel(in);
+        this.taskAffinity = in.readString();
+        this.privateFlags = in.readInt();
+        this.permission = sForString.unparcel(in);
+        this.launchMode = in.readInt();
+        this.documentLaunchMode = in.readInt();
+        this.maxRecents = in.readInt();
+        this.configChanges = in.readInt();
+        this.softInputMode = in.readInt();
+        this.persistableMode = in.readInt();
+        this.lockTaskLaunchMode = in.readInt();
+        this.screenOrientation = in.readInt();
+        this.resizeMode = in.readInt();
+        this.maxAspectRatio = (Float) in.readValue(Float.class.getClassLoader());
+        this.minAspectRatio = (Float) in.readValue(Float.class.getClassLoader());
+        this.requestedVrComponent = in.readString();
+        this.rotationAnimation = in.readInt();
+        this.colorMode = in.readInt();
+        this.preferMinimalPostProcessing = in.readBoolean();
+        this.metaData = in.readBundle();
+        if (in.readBoolean()) {
+            windowLayout = new ActivityInfo.WindowLayout(in);
+        }
+    }
+
+    public static final Parcelable.Creator<ParsedActivity> CREATOR = new Creator<ParsedActivity>() {
+        @Override
+        public ParsedActivity createFromParcel(Parcel source) {
+            return new ParsedActivity(source);
+        }
+
+        @Override
+        public ParsedActivity[] newArray(int size) {
+            return new ParsedActivity[size];
+        }
+    };
+
+    public int getTheme() {
+        return theme;
+    }
+
+    public int getUiOptions() {
+        return uiOptions;
+    }
+
+    @Nullable
+    public String getTargetActivity() {
+        return targetActivity;
+    }
+
+    @Nullable
+    public String getParentActivityName() {
+        return parentActivityName;
+    }
+
+    @Nullable
+    public String getTaskAffinity() {
+        return taskAffinity;
+    }
+
+    public int getPrivateFlags() {
+        return privateFlags;
+    }
+
+    @Nullable
+    public String getPermission() {
+        return permission;
+    }
+
+    public int getLaunchMode() {
+        return launchMode;
+    }
+
+    public int getDocumentLaunchMode() {
+        return documentLaunchMode;
+    }
+
+    public int getMaxRecents() {
+        return maxRecents;
+    }
+
+    public int getConfigChanges() {
+        return configChanges;
+    }
+
+    public int getSoftInputMode() {
+        return softInputMode;
+    }
+
+    public int getPersistableMode() {
+        return persistableMode;
+    }
+
+    public int getLockTaskLaunchMode() {
+        return lockTaskLaunchMode;
+    }
+
+    public int getScreenOrientation() {
+        return screenOrientation;
+    }
+
+    public int getResizeMode() {
+        return resizeMode;
+    }
+
+    @Nullable
+    public Float getMaxAspectRatio() {
+        return maxAspectRatio;
+    }
+
+    @Nullable
+    public Float getMinAspectRatio() {
+        return minAspectRatio;
+    }
+
+    @Nullable
+    public String getRequestedVrComponent() {
+        return requestedVrComponent;
+    }
+
+    public int getRotationAnimation() {
+        return rotationAnimation;
+    }
+
+    public int getColorMode() {
+        return colorMode;
+    }
+
+    public boolean isPreferMinimalPostProcessing() {
+        return preferMinimalPostProcessing;
+    }
+
+    @Nullable
+    public ActivityInfo.WindowLayout getWindowLayout() {
+        return windowLayout;
+    }
+}
diff --git a/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java b/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java
new file mode 100644
index 0000000..555cdd0
--- /dev/null
+++ b/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java
@@ -0,0 +1,484 @@
+/*
+ * 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.component;
+
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+
+import static android.content.pm.parsing.component.ComponentParseUtils.flag;
+
+import android.annotation.NonNull;
+import android.app.ActivityTaskManager;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageParser;
+
+import android.content.pm.parsing.ParsingPackage;
+import android.content.pm.parsing.ParsingUtils;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
+import android.os.Build;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.util.Slog;
+import android.util.TypedValue;
+import android.view.Gravity;
+import android.view.WindowManager;
+
+import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.ArrayUtils;
+import android.content.pm.parsing.ParsingPackageUtils;
+import android.content.pm.parsing.result.ParseInput;
+import android.content.pm.parsing.result.ParseResult;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Objects;
+
+/** @hide */
+public class ParsedActivityUtils {
+
+    private static final String TAG = ParsingPackageUtils.TAG;
+
+    @NonNull
+    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+    public static ParseResult<ParsedActivity> parseActivityOrReceiver(String[] separateProcesses,
+            ParsingPackage pkg, Resources res, XmlResourceParser parser, int flags,
+            boolean useRoundIcon, ParseInput input)
+            throws XmlPullParserException, IOException {
+        final String packageName = pkg.getPackageName();
+        final ParsedActivity
+                activity = new ParsedActivity();
+
+        boolean receiver = "receiver".equals(parser.getName());
+        String tag = "<" + parser.getName() + ">";
+        TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestActivity);
+        try {
+            ParseResult<ParsedActivity> result =
+                    ParsedMainComponentUtils.parseMainComponent(
+                    activity, tag, separateProcesses,
+                    pkg, sa, flags, useRoundIcon, input,
+                    R.styleable.AndroidManifestActivity_banner,
+                    R.styleable.AndroidManifestActivity_description,
+                    R.styleable.AndroidManifestActivity_directBootAware,
+                    R.styleable.AndroidManifestActivity_enabled,
+                    R.styleable.AndroidManifestActivity_icon,
+                    R.styleable.AndroidManifestActivity_label,
+                    R.styleable.AndroidManifestActivity_logo,
+                    R.styleable.AndroidManifestActivity_name,
+                    R.styleable.AndroidManifestActivity_process,
+                    R.styleable.AndroidManifestActivity_roundIcon,
+                    R.styleable.AndroidManifestActivity_splitName);
+            if (result.isError()) {
+                return result;
+            }
+
+            if (receiver && pkg.isCantSaveState()) {
+                // A heavy-weight application can not have receivers in its main process
+                if (Objects.equals(activity.getProcessName(), packageName)) {
+                    return input.error("Heavy-weight applications can not have receivers "
+                            + "in main process");
+                }
+            }
+
+            // The following section has formatting off to make it easier to read the flags.
+            // Multi-lining them to fit within the column restriction makes it hard to tell what
+            // field is assigned where.
+            // @formatter:off
+            activity.theme = sa.getResourceId(R.styleable.AndroidManifestActivity_theme, 0);
+            activity.uiOptions = sa.getInt(R.styleable.AndroidManifestActivity_uiOptions, pkg.getUiOptions());
+
+            activity.flags |= flag(ActivityInfo.FLAG_ALLOW_TASK_REPARENTING, R.styleable.AndroidManifestActivity_allowTaskReparenting, pkg.isAllowTaskReparenting(), sa)
+                    | flag(ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE, R.styleable.AndroidManifestActivity_alwaysRetainTaskState, sa)
+                    | flag(ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH, R.styleable.AndroidManifestActivity_clearTaskOnLaunch, sa)
+                    | flag(ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS, R.styleable.AndroidManifestActivity_excludeFromRecents, sa)
+                    | flag(ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS, R.styleable.AndroidManifestActivity_finishOnCloseSystemDialogs, sa)
+                    | flag(ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH, R.styleable.AndroidManifestActivity_finishOnTaskLaunch, sa)
+                    | flag(ActivityInfo.FLAG_IMMERSIVE, R.styleable.AndroidManifestActivity_immersive, sa)
+                    | flag(ActivityInfo.FLAG_MULTIPROCESS, R.styleable.AndroidManifestActivity_multiprocess, sa)
+                    | flag(ActivityInfo.FLAG_NO_HISTORY, R.styleable.AndroidManifestActivity_noHistory, sa)
+                    | flag(ActivityInfo.FLAG_SHOW_FOR_ALL_USERS, R.styleable.AndroidManifestActivity_showForAllUsers, sa)
+                    | flag(ActivityInfo.FLAG_SHOW_FOR_ALL_USERS, R.styleable.AndroidManifestActivity_showOnLockScreen, sa)
+                    | flag(ActivityInfo.FLAG_STATE_NOT_NEEDED, R.styleable.AndroidManifestActivity_stateNotNeeded, sa)
+                    | flag(ActivityInfo.FLAG_SYSTEM_USER_ONLY, R.styleable.AndroidManifestActivity_systemUserOnly, sa);
+
+            if (!receiver) {
+                activity.flags |= flag(ActivityInfo.FLAG_HARDWARE_ACCELERATED, R.styleable.AndroidManifestActivity_hardwareAccelerated, pkg.isBaseHardwareAccelerated(), sa)
+                        | flag(ActivityInfo.FLAG_ALLOW_EMBEDDED, R.styleable.AndroidManifestActivity_allowEmbedded, sa)
+                        | flag(ActivityInfo.FLAG_ALWAYS_FOCUSABLE, R.styleable.AndroidManifestActivity_alwaysFocusable, sa)
+                        | flag(ActivityInfo.FLAG_AUTO_REMOVE_FROM_RECENTS, R.styleable.AndroidManifestActivity_autoRemoveFromRecents, sa)
+                        | flag(ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY, R.styleable.AndroidManifestActivity_relinquishTaskIdentity, sa)
+                        | flag(ActivityInfo.FLAG_RESUME_WHILE_PAUSING, R.styleable.AndroidManifestActivity_resumeWhilePausing, sa)
+                        | flag(ActivityInfo.FLAG_SHOW_WHEN_LOCKED, R.styleable.AndroidManifestActivity_showWhenLocked, sa)
+                        | flag(ActivityInfo.FLAG_SUPPORTS_PICTURE_IN_PICTURE, R.styleable.AndroidManifestActivity_supportsPictureInPicture, sa)
+                        | flag(ActivityInfo.FLAG_TURN_SCREEN_ON, R.styleable.AndroidManifestActivity_turnScreenOn, sa);
+
+                activity.privateFlags |= flag(ActivityInfo.FLAG_INHERIT_SHOW_WHEN_LOCKED, R.styleable.AndroidManifestActivity_inheritShowWhenLocked, sa);
+
+                activity.colorMode = sa.getInt(R.styleable.AndroidManifestActivity_colorMode, ActivityInfo.COLOR_MODE_DEFAULT);
+                activity.preferMinimalPostProcessing = sa.getBoolean(R.styleable.AndroidManifestActivity_preferMinimalPostProcessing, ActivityInfo.MINIMAL_POST_PROCESSING_DEFAULT);
+                activity.documentLaunchMode = sa.getInt(R.styleable.AndroidManifestActivity_documentLaunchMode, ActivityInfo.DOCUMENT_LAUNCH_NONE);
+                activity.launchMode = sa.getInt(R.styleable.AndroidManifestActivity_launchMode, ActivityInfo.LAUNCH_MULTIPLE);
+                activity.lockTaskLaunchMode = sa.getInt(R.styleable.AndroidManifestActivity_lockTaskMode, 0);
+                activity.maxRecents = sa.getInt(R.styleable.AndroidManifestActivity_maxRecents, ActivityTaskManager.getDefaultAppRecentsLimitStatic());
+                activity.persistableMode = sa.getInteger(R.styleable.AndroidManifestActivity_persistableMode, ActivityInfo.PERSIST_ROOT_ONLY);
+                activity.requestedVrComponent = sa.getString(R.styleable.AndroidManifestActivity_enableVrMode);
+                activity.rotationAnimation = sa.getInt(R.styleable.AndroidManifestActivity_rotationAnimation, WindowManager.LayoutParams.ROTATION_ANIMATION_UNSPECIFIED);
+                activity.softInputMode = sa.getInt(R.styleable.AndroidManifestActivity_windowSoftInputMode, 0);
+
+                activity.configChanges = PackageParser.getActivityConfigChanges(
+                        sa.getInt(R.styleable.AndroidManifestActivity_configChanges, 0),
+                        sa.getInt(R.styleable.AndroidManifestActivity_recreateOnConfigChanges, 0));
+
+                int screenOrientation = sa.getInt(R.styleable.AndroidManifestActivity_screenOrientation, SCREEN_ORIENTATION_UNSPECIFIED);
+                int resizeMode = getActivityResizeMode(pkg, sa, screenOrientation);
+                activity.screenOrientation = screenOrientation;
+                activity.resizeMode = resizeMode;
+
+                if (sa.hasValue(R.styleable.AndroidManifestActivity_maxAspectRatio)
+                        && sa.getType(R.styleable.AndroidManifestActivity_maxAspectRatio)
+                        == TypedValue.TYPE_FLOAT) {
+                    activity.setMaxAspectRatio(resizeMode,
+                            sa.getFloat(R.styleable.AndroidManifestActivity_maxAspectRatio,
+                                    0 /*default*/));
+                }
+
+                if (sa.hasValue(R.styleable.AndroidManifestActivity_minAspectRatio)
+                        && sa.getType(R.styleable.AndroidManifestActivity_minAspectRatio)
+                        == TypedValue.TYPE_FLOAT) {
+                    activity.setMinAspectRatio(resizeMode,
+                            sa.getFloat(R.styleable.AndroidManifestActivity_minAspectRatio,
+                                    0 /*default*/));
+                }
+            } else {
+                activity.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
+                activity.configChanges = 0;
+                activity.flags |= flag(ActivityInfo.FLAG_SINGLE_USER, R.styleable.AndroidManifestActivity_singleUser, sa);
+            }
+            // @formatter:on
+
+            String taskAffinity = sa.getNonConfigurationString(
+                    R.styleable.AndroidManifestActivity_taskAffinity,
+                    Configuration.NATIVE_CONFIG_VERSION);
+
+            ParseResult<String> affinityNameResult = ComponentParseUtils.buildTaskAffinityName(
+                    packageName, pkg.getTaskAffinity(), taskAffinity, input);
+            if (affinityNameResult.isSuccess()) {
+                activity.taskAffinity = affinityNameResult.getResult();
+            } else {
+                // Backwards-compat, ignore error
+                affinityNameResult.ignoreError();
+            }
+
+            boolean visibleToEphemeral = sa.getBoolean(R.styleable.AndroidManifestActivity_visibleToInstantApps, false);
+            if (visibleToEphemeral) {
+                activity.flags |= ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP;
+                pkg.setVisibleToInstantApps(true);
+            }
+
+            return parseActivityOrAlias(activity, pkg, tag, parser, res, sa, receiver,
+                    false /*isAlias*/, visibleToEphemeral, input,
+                    R.styleable.AndroidManifestActivity_parentActivityName,
+                    R.styleable.AndroidManifestActivity_permission,
+                    R.styleable.AndroidManifestActivity_exported
+            );
+        } finally {
+            sa.recycle();
+        }
+    }
+
+    @NonNull
+    public static ParseResult<ParsedActivity> parseActivityAlias(ParsingPackage pkg, Resources res,
+            XmlResourceParser parser, boolean useRoundIcon, ParseInput input)
+            throws XmlPullParserException, IOException {
+        TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestActivityAlias);
+        try {
+            String targetActivity = sa.getNonConfigurationString(
+                    R.styleable.AndroidManifestActivityAlias_targetActivity,
+                    Configuration.NATIVE_CONFIG_VERSION);
+            if (targetActivity == null) {
+                return input.error("<activity-alias> does not specify android:targetActivity");
+            }
+
+            String packageName = pkg.getPackageName();
+            targetActivity = ParsingUtils.buildClassName(packageName, targetActivity);
+            if (targetActivity == null) {
+                return input.error("Empty class name in package " + packageName);
+            }
+
+            ParsedActivity target = null;
+
+            List<ParsedActivity> activities = pkg.getActivities();
+            final int activitiesSize = ArrayUtils.size(activities);
+            for (int i = 0; i < activitiesSize; i++) {
+                ParsedActivity t = activities.get(i);
+                if (targetActivity.equals(t.getName())) {
+                    target = t;
+                    break;
+                }
+            }
+
+            if (target == null) {
+                return input.error("<activity-alias> target activity " + targetActivity
+                        + " not found in manifest with activities = "
+                        + pkg.getActivities()
+                        + ", parsedActivities = " + activities);
+            }
+
+            ParsedActivity activity = ParsedActivity.makeAlias(targetActivity, target);
+            String tag = "<" + parser.getName() + ">";
+
+            ParseResult<ParsedActivity> result = ParsedMainComponentUtils.parseMainComponent(
+                    activity, tag, null, pkg, sa, 0, useRoundIcon, input,
+                    R.styleable.AndroidManifestActivityAlias_banner,
+                    R.styleable.AndroidManifestActivityAlias_description,
+                    null /*directBootAwareAttr*/,
+                    R.styleable.AndroidManifestActivityAlias_enabled,
+                    R.styleable.AndroidManifestActivityAlias_icon,
+                    R.styleable.AndroidManifestActivityAlias_label,
+                    R.styleable.AndroidManifestActivityAlias_logo,
+                    R.styleable.AndroidManifestActivityAlias_name,
+                    null /*processAttr*/,
+                    R.styleable.AndroidManifestActivityAlias_roundIcon,
+                    null /*splitNameAttr*/);
+            if (result.isError()) {
+                return result;
+            }
+
+            // TODO add visibleToInstantApps attribute to activity alias
+            final boolean visibleToEphemeral =
+                    ((activity.getFlags() & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0);
+
+            return parseActivityOrAlias(activity, pkg, tag, parser, res, sa, false /*isReceiver*/, true /*isAlias*/,
+                    visibleToEphemeral, input,
+                    R.styleable.AndroidManifestActivityAlias_parentActivityName,
+                    R.styleable.AndroidManifestActivityAlias_permission,
+                    R.styleable.AndroidManifestActivityAlias_exported);
+        } finally {
+            sa.recycle();
+        }
+    }
+
+    /**
+     * This method shares parsing logic between Activity/Receiver/alias instances, but requires
+     * passing in booleans for isReceiver/isAlias, since there's no indicator in the other
+     * parameters.
+     *
+     * They're used to filter the parsed tags and their behavior. This makes the method rather
+     * messy, but it's more maintainable than writing 3 separate methods for essentially the same
+     * type of logic.
+     */
+    @NonNull
+    private static ParseResult<ParsedActivity> parseActivityOrAlias(ParsedActivity activity,
+            ParsingPackage pkg, String tag, XmlResourceParser parser, Resources resources,
+            TypedArray array, boolean isReceiver, boolean isAlias, boolean visibleToEphemeral,
+            ParseInput input, int parentActivityNameAttr, int permissionAttr,
+            int exportedAttr) throws IOException, XmlPullParserException {
+        String parentActivityName = array.getNonConfigurationString(parentActivityNameAttr, Configuration.NATIVE_CONFIG_VERSION);
+        if (parentActivityName != null) {
+            String packageName = pkg.getPackageName();
+            String parentClassName = ParsingUtils.buildClassName(packageName, parentActivityName);
+            if (parentClassName == null) {
+                Log.e(TAG, "Activity " + activity.getName()
+                        + " specified invalid parentActivityName " + parentActivityName);
+            } else {
+                activity.setParentActivity(parentClassName);
+            }
+        }
+
+        String permission = array.getNonConfigurationString(permissionAttr, 0);
+        activity.setPermission(permission != null ? permission : pkg.getPermission());
+
+        final boolean setExported = array.hasValue(exportedAttr);
+        if (setExported) {
+            activity.exported = array.getBoolean(exportedAttr, false);
+        }
+
+        final int depth = parser.getDepth();
+        int type;
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG
+                || parser.getDepth() > depth)) {
+            if (type != XmlPullParser.START_TAG) {
+                continue;
+            }
+
+            final ParseResult result;
+            if (parser.getName().equals("intent-filter")) {
+                ParseResult<ParsedIntentInfo> intentResult = parseIntentFilter(pkg, activity,
+                        !isReceiver, visibleToEphemeral, resources, parser, input);
+                if (intentResult.isSuccess()) {
+                    ParsedIntentInfo intent = intentResult.getResult();
+                    if (intent != null) {
+                        activity.order = Math.max(intent.getOrder(), activity.order);
+                        activity.addIntent(intent);
+                        if (PackageParser.LOG_UNSAFE_BROADCASTS && isReceiver
+                                && pkg.getTargetSdkVersion() >= Build.VERSION_CODES.O) {
+                            int actionCount = intent.countActions();
+                            for (int i = 0; i < actionCount; i++) {
+                                final String action = intent.getAction(i);
+                                if (action == null || !action.startsWith("android.")) {
+                                    continue;
+                                }
+
+                                if (!PackageParser.SAFE_BROADCASTS.contains(action)) {
+                                    Slog.w(TAG,
+                                            "Broadcast " + action + " may never be delivered to "
+                                                    + pkg.getPackageName() + " as requested at: "
+                                                    + parser.getPositionDescription());
+                                }
+                            }
+                        }
+                    }
+                }
+                result = intentResult;
+            } else if (parser.getName().equals("meta-data")) {
+                result = ParsedComponentUtils.addMetaData(activity, pkg, resources, parser, input);
+            } else if (!isReceiver && !isAlias && parser.getName().equals("preferred")) {
+                ParseResult<ParsedIntentInfo> intentResult = parseIntentFilter(pkg, activity,
+                        true /*allowImplicitEphemeralVisibility*/, visibleToEphemeral,
+                        resources, parser, input);
+                if (intentResult.isSuccess()) {
+                    ParsedIntentInfo intent = intentResult.getResult();
+                    if (intent != null) {
+                        pkg.addPreferredActivityFilter(activity.getClassName(), intent);
+                    }
+                }
+                result = intentResult;
+            } else if (!isReceiver && !isAlias && parser.getName().equals("layout")) {
+                ParseResult<ActivityInfo.WindowLayout> layoutResult = parseLayout(resources, parser,
+                        input);
+                if (layoutResult.isSuccess()) {
+                    activity.windowLayout = layoutResult.getResult();
+                }
+                result = layoutResult;
+            } else {
+                result = ParsingUtils.unknownTag(tag, pkg, parser, input);
+            }
+
+            if (result.isError()) {
+                return input.error(result);
+            }
+        }
+
+        if (!setExported) {
+            activity.exported = activity.getIntents().size() > 0;
+        }
+
+        return input.success(activity);
+    }
+
+    @NonNull
+    private static ParseResult<ParsedIntentInfo> parseIntentFilter(ParsingPackage pkg,
+            ParsedActivity activity, boolean allowImplicitEphemeralVisibility,
+            boolean visibleToEphemeral, Resources resources, XmlResourceParser parser,
+            ParseInput input) throws IOException, XmlPullParserException {
+        ParseResult<ParsedIntentInfo> result = ParsedMainComponentUtils.parseIntentFilter(activity,
+                pkg, resources, parser, visibleToEphemeral, true /*allowGlobs*/,
+                true /*allowAutoVerify*/, allowImplicitEphemeralVisibility,
+                true /*failOnNoActions*/, input);
+        if (result.isError()) {
+            return input.error(result);
+        }
+
+        ParsedIntentInfo intent = result.getResult();
+        if (intent != null) {
+            if (intent.isVisibleToInstantApp()) {
+                activity.flags |= ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP;
+            }
+            if (intent.isImplicitlyVisibleToInstantApp()) {
+                activity.flags |= ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP;
+            }
+        }
+
+        return input.success(intent);
+    }
+
+    private static int getActivityResizeMode(ParsingPackage pkg, TypedArray sa,
+            int screenOrientation) {
+        Boolean resizeableActivity = pkg.getResizeableActivity();
+
+        if (sa.hasValue(R.styleable.AndroidManifestActivity_resizeableActivity)
+                || resizeableActivity != null) {
+            // Activity or app explicitly set if it is resizeable or not;
+            if (sa.getBoolean(R.styleable.AndroidManifestActivity_resizeableActivity,
+                    resizeableActivity != null && resizeableActivity)) {
+                return ActivityInfo.RESIZE_MODE_RESIZEABLE;
+            } else {
+                return ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
+            }
+        }
+
+        if (pkg.isResizeableActivityViaSdkVersion()) {
+            // The activity or app didn't explicitly set the resizing option, however we want to
+            // make it resize due to the sdk version it is targeting.
+            return ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
+        }
+
+        // resize preference isn't set and target sdk version doesn't support resizing apps by
+        // default. For the app to be resizeable if it isn't fixed orientation or immersive.
+        if (ActivityInfo.isFixedOrientationPortrait(screenOrientation)) {
+            return ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY;
+        } else if (ActivityInfo.isFixedOrientationLandscape(screenOrientation)) {
+            return ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY;
+        } else if (screenOrientation == ActivityInfo.SCREEN_ORIENTATION_LOCKED) {
+            return ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION;
+        } else {
+            return ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE;
+        }
+    }
+
+    @NonNull
+    private static ParseResult<ActivityInfo.WindowLayout> parseLayout(Resources res,
+            AttributeSet attrs, ParseInput input) {
+        TypedArray sw = res.obtainAttributes(attrs, R.styleable.AndroidManifestLayout);
+        try {
+            int width = -1;
+            float widthFraction = -1f;
+            int height = -1;
+            float heightFraction = -1f;
+            final int widthType = sw.getType(R.styleable.AndroidManifestLayout_defaultWidth);
+            if (widthType == TypedValue.TYPE_FRACTION) {
+                widthFraction = sw.getFraction(R.styleable.AndroidManifestLayout_defaultWidth, 1, 1,
+                        -1);
+            } else if (widthType == TypedValue.TYPE_DIMENSION) {
+                width = sw.getDimensionPixelSize(R.styleable.AndroidManifestLayout_defaultWidth,
+                        -1);
+            }
+            final int heightType = sw.getType(R.styleable.AndroidManifestLayout_defaultHeight);
+            if (heightType == TypedValue.TYPE_FRACTION) {
+                heightFraction = sw.getFraction(R.styleable.AndroidManifestLayout_defaultHeight, 1,
+                        1, -1);
+            } else if (heightType == TypedValue.TYPE_DIMENSION) {
+                height = sw.getDimensionPixelSize(R.styleable.AndroidManifestLayout_defaultHeight,
+                        -1);
+            }
+            int gravity = sw.getInt(R.styleable.AndroidManifestLayout_gravity, Gravity.CENTER);
+            int minWidth = sw.getDimensionPixelSize(R.styleable.AndroidManifestLayout_minWidth, -1);
+            int minHeight = sw.getDimensionPixelSize(R.styleable.AndroidManifestLayout_minHeight,
+                    -1);
+            return input.success(new ActivityInfo.WindowLayout(width, widthFraction, height,
+                    heightFraction, gravity, minWidth, minHeight));
+        } finally {
+            sw.recycle();
+        }
+    }
+}
diff --git a/core/java/android/content/pm/parsing/component/ParsedComponent.java b/core/java/android/content/pm/parsing/component/ParsedComponent.java
new file mode 100644
index 0000000..098d620
--- /dev/null
+++ b/core/java/android/content/pm/parsing/component/ParsedComponent.java
@@ -0,0 +1,208 @@
+/*
+ * 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.component;
+
+import static android.content.pm.parsing.ParsingPackageImpl.sForString;
+
+import android.annotation.CallSuper;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
+
+import com.android.internal.util.CollectionUtils;
+import com.android.internal.util.DataClass;
+import com.android.internal.util.Parcelling;
+import com.android.internal.util.Parcelling.BuiltIn.ForInternedString;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/** @hide */
+public abstract class ParsedComponent implements Parcelable {
+
+    private static ParsedIntentInfo.ListParceler sForIntentInfos = Parcelling.Cache.getOrCreate(
+            ParsedIntentInfo.ListParceler.class);
+
+    @NonNull
+    @DataClass.ParcelWith(ForInternedString.class)
+    private String name;
+    int icon;
+    int labelRes;
+    @Nullable
+    CharSequence nonLocalizedLabel;
+    int logo;
+    int banner;
+    int descriptionRes;
+
+    // TODO(b/135203078): Replace flags with individual booleans, scoped by subclass
+    int flags;
+
+    @NonNull
+    @DataClass.ParcelWith(ForInternedString.class)
+    private String packageName;
+
+    @Nullable
+    @DataClass.PluralOf("intent")
+    @DataClass.ParcelWith(ParsedIntentInfo.ListParceler.class)
+    private List<ParsedIntentInfo> intents;
+
+    private ComponentName componentName;
+
+    @Nullable
+    protected Bundle metaData;
+
+    ParsedComponent() {
+
+    }
+
+    @SuppressWarnings("IncompleteCopyConstructor")
+    public ParsedComponent(ParsedComponent other) {
+        this.metaData = other.metaData;
+        this.name = other.name;
+        this.icon = other.getIcon();
+        this.labelRes = other.getLabelRes();
+        this.nonLocalizedLabel = other.getNonLocalizedLabel();
+        this.logo = other.getLogo();
+        this.banner = other.getBanner();
+
+        this.descriptionRes = other.getDescriptionRes();
+
+        this.flags = other.getFlags();
+
+        this.setPackageName(other.packageName);
+        this.intents = new ArrayList<>(other.getIntents());
+    }
+
+    public void addIntent(ParsedIntentInfo intent) {
+        this.intents = CollectionUtils.add(this.intents, intent);
+    }
+
+    @NonNull
+    public List<ParsedIntentInfo> getIntents() {
+        return intents != null ? intents : Collections.emptyList();
+    }
+
+    public ParsedComponent setName(String name) {
+        this.name = TextUtils.safeIntern(name);
+        return this;
+    }
+
+    @CallSuper
+    public void setPackageName(@NonNull String packageName) {
+        this.packageName = TextUtils.safeIntern(packageName);
+        //noinspection ConstantConditions
+        this.componentName = null;
+
+        // Note: this method does not edit name (which can point to a class), because this package
+        // name change is not changing the package in code, but the identifier used by the system.
+    }
+
+    @NonNull
+    public ComponentName getComponentName() {
+        if (componentName == null) {
+            componentName = new ComponentName(getPackageName(), getName());
+        }
+        return componentName;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        sForString.parcel(this.name, dest, flags);
+        dest.writeInt(this.getIcon());
+        dest.writeInt(this.getLabelRes());
+        dest.writeCharSequence(this.getNonLocalizedLabel());
+        dest.writeInt(this.getLogo());
+        dest.writeInt(this.getBanner());
+        dest.writeInt(this.getDescriptionRes());
+        dest.writeInt(this.getFlags());
+        sForString.parcel(this.packageName, dest, flags);
+        sForIntentInfos.parcel(this.getIntents(), dest, flags);
+        dest.writeBundle(this.metaData);
+    }
+
+    protected ParsedComponent(Parcel in) {
+        // We use the boot classloader for all classes that we load.
+        final ClassLoader boot = Object.class.getClassLoader();
+        //noinspection ConstantConditions
+        this.name = sForString.unparcel(in);
+        this.icon = in.readInt();
+        this.labelRes = in.readInt();
+        this.nonLocalizedLabel = in.readCharSequence();
+        this.logo = in.readInt();
+        this.banner = in.readInt();
+        this.descriptionRes = in.readInt();
+        this.flags = in.readInt();
+        //noinspection ConstantConditions
+        this.packageName = sForString.unparcel(in);
+        this.intents = sForIntentInfos.unparcel(in);
+        this.metaData = in.readBundle(boot);
+    }
+
+    @NonNull
+    public String getName() {
+        return name;
+    }
+
+    public int getIcon() {
+        return icon;
+    }
+
+    public int getLabelRes() {
+        return labelRes;
+    }
+
+    @Nullable
+    public CharSequence getNonLocalizedLabel() {
+        return nonLocalizedLabel;
+    }
+
+    public int getLogo() {
+        return logo;
+    }
+
+    public int getBanner() {
+        return banner;
+    }
+
+    public int getDescriptionRes() {
+        return descriptionRes;
+    }
+
+    public int getFlags() {
+        return flags;
+    }
+
+    @NonNull
+    public String getPackageName() {
+        return packageName;
+    }
+
+    @Nullable
+    public Bundle getMetaData() {
+        return metaData;
+    }
+}
diff --git a/core/java/android/content/pm/parsing/component/ParsedComponentUtils.java b/core/java/android/content/pm/parsing/component/ParsedComponentUtils.java
new file mode 100644
index 0000000..b37b617
--- /dev/null
+++ b/core/java/android/content/pm/parsing/component/ParsedComponentUtils.java
@@ -0,0 +1,100 @@
+/*
+ * 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.component;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.pm.PackageManager;
+import android.content.pm.parsing.ParsingPackage;
+import android.content.pm.parsing.ParsingUtils;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
+import android.os.Bundle;
+import android.text.TextUtils;
+import android.util.TypedValue;
+
+import com.android.internal.annotations.VisibleForTesting;
+import android.content.pm.parsing.ParsingPackageUtils;
+import android.content.pm.parsing.result.ParseInput;
+import android.content.pm.parsing.result.ParseResult;
+
+/** @hide */
+class ParsedComponentUtils {
+
+    private static final String TAG = ParsingPackageUtils.TAG;
+
+    @NonNull
+    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+    static <Component extends ParsedComponent> ParseResult<Component> parseComponent(
+            Component component, String tag, ParsingPackage pkg, TypedArray array,
+            boolean useRoundIcon, ParseInput input, int bannerAttr,
+            @Nullable Integer descriptionAttr, int iconAttr, int labelAttr, int logoAttr,
+            int nameAttr, int roundIconAttr) {
+        String name = array.getNonConfigurationString(nameAttr, 0);
+        if (TextUtils.isEmpty(name)) {
+            return input.error(tag + " does not specify android:name");
+        }
+
+        String packageName = pkg.getPackageName();
+        String className = ParsingUtils.buildClassName(packageName, name);
+        if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) {
+            return input.error(tag + " invalid android:name");
+        }
+
+        //noinspection ConstantConditions; null check done above with isEmpty
+        component.setName(className);
+        component.setPackageName(packageName);
+
+        if (useRoundIcon) {
+            component.icon = array.getResourceId(roundIconAttr, 0);
+        }
+
+        if (component.icon == 0) {
+            component.icon = array.getResourceId(iconAttr, 0);
+        }
+
+        component.logo = array.getResourceId(logoAttr, 0);
+        component.banner = array.getResourceId(bannerAttr, 0);
+
+        if (descriptionAttr != null) {
+            component.descriptionRes = array.getResourceId(descriptionAttr, 0);
+        }
+
+        TypedValue v = array.peekValue(labelAttr);
+        if (v != null) {
+            component.labelRes = v.resourceId;
+            if (v.resourceId == 0) {
+                component.nonLocalizedLabel = v.coerceToString();
+            }
+        }
+
+        return input.success(component);
+    }
+
+    static ParseResult<Bundle> addMetaData(ParsedComponent component, ParsingPackage pkg,
+            Resources resources, XmlResourceParser parser, ParseInput input) {
+        ParseResult<Bundle> result = ParsingPackageUtils.parseMetaData(pkg, resources,
+                parser, component.metaData, input);
+        if (result.isError()) {
+            return input.error(result);
+        }
+        Bundle bundle = result.getResult();
+        component.metaData = bundle;
+        return input.success(bundle);
+    }
+}
diff --git a/core/java/android/content/pm/parsing/component/ParsedFeature.java b/core/java/android/content/pm/parsing/component/ParsedFeature.java
new file mode 100644
index 0000000..b8a9098
--- /dev/null
+++ b/core/java/android/content/pm/parsing/component/ParsedFeature.java
@@ -0,0 +1,229 @@
+/*
+ * 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.component;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.StringRes;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.ArraySet;
+
+import com.android.internal.util.DataClass;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A {@link android.R.styleable#AndroidManifestFeature &lt;feature&gt;} tag parsed from the
+ * manifest.
+ *
+ * @hide
+ */
+@DataClass(genAidl = false)
+public class ParsedFeature implements Parcelable {
+    /** Maximum length of featureId */
+    public static final int MAX_FEATURE_ID_LEN = 50;
+
+    /** Maximum amount of features per package */
+    private static final int MAX_NUM_FEATURES = 1000;
+
+    /** Id of the feature */
+    public final @NonNull String id;
+
+    /** User visible label fo the feature */
+    public final @StringRes int label;
+
+    /** Ids of previously declared features this feature inherits from */
+    public final @NonNull List<String> inheritFrom;
+
+    /**
+     * @return Is this set of features a valid combination for a single package?
+     */
+    public static boolean isCombinationValid(@Nullable List<ParsedFeature> features) {
+        if (features == null) {
+            return true;
+        }
+
+        ArraySet<String> featureIds = new ArraySet<>(features.size());
+        ArraySet<String> inheritFromFeatureIds = new ArraySet<>();
+
+        int numFeatures = features.size();
+        if (numFeatures > MAX_NUM_FEATURES) {
+            return false;
+        }
+
+        for (int featureNum = 0; featureNum < numFeatures; featureNum++) {
+            boolean wasAdded = featureIds.add(features.get(featureNum).id);
+            if (!wasAdded) {
+                // feature id is not unique
+                return false;
+            }
+        }
+
+        for (int featureNum = 0; featureNum < numFeatures; featureNum++) {
+            ParsedFeature feature = features.get(featureNum);
+
+            int numInheritFrom = feature.inheritFrom.size();
+            for (int inheritFromNum = 0; inheritFromNum < numInheritFrom; inheritFromNum++) {
+                String inheritFrom = feature.inheritFrom.get(inheritFromNum);
+
+                if (featureIds.contains(inheritFrom)) {
+                    // Cannot inherit from a feature that is still defined
+                    return false;
+                }
+
+                boolean wasAdded = inheritFromFeatureIds.add(inheritFrom);
+                if (!wasAdded) {
+                    // inheritFrom is not unique
+                    return false;
+                }
+            }
+        }
+
+        return true;
+    }
+
+
+
+    // Code below generated by codegen v1.0.14.
+    //
+    // DO NOT MODIFY!
+    // CHECKSTYLE:OFF Generated code
+    //
+    // To regenerate run:
+    // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/parsing/component/ParsedFeature.java
+    //
+    // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+    //   Settings > Editor > Code Style > Formatter Control
+    //@formatter:off
+
+
+    @android.annotation.IntDef(prefix = "MAX_", value = {
+        MAX_FEATURE_ID_LEN,
+        MAX_NUM_FEATURES
+    })
+    @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE)
+    @DataClass.Generated.Member
+    public @interface Max {}
+
+    @DataClass.Generated.Member
+    public static String maxToString(@Max int value) {
+        switch (value) {
+            case MAX_FEATURE_ID_LEN:
+                    return "MAX_FEATURE_ID_LEN";
+            case MAX_NUM_FEATURES:
+                    return "MAX_NUM_FEATURES";
+            default: return Integer.toHexString(value);
+        }
+    }
+
+    /**
+     * Creates a new ParsedFeature.
+     *
+     * @param id
+     *   Id of the feature
+     * @param label
+     *   User visible label fo the feature
+     * @param inheritFrom
+     *   Ids of previously declared features this feature inherits from
+     */
+    @DataClass.Generated.Member
+    public ParsedFeature(
+            @NonNull String id,
+            @StringRes int label,
+            @NonNull List<String> inheritFrom) {
+        this.id = id;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, id);
+        this.label = label;
+        com.android.internal.util.AnnotationValidations.validate(
+                StringRes.class, null, label);
+        this.inheritFrom = inheritFrom;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, inheritFrom);
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        // You can override field parcelling by defining methods like:
+        // void parcelFieldName(Parcel dest, int flags) { ... }
+
+        dest.writeString(id);
+        dest.writeInt(label);
+        dest.writeStringList(inheritFrom);
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public int describeContents() { return 0; }
+
+    /** @hide */
+    @SuppressWarnings({"unchecked", "RedundantCast"})
+    @DataClass.Generated.Member
+    protected ParsedFeature(@NonNull Parcel in) {
+        // You can override field unparcelling by defining methods like:
+        // static FieldType unparcelFieldName(Parcel in) { ... }
+
+        String _id = in.readString();
+        int _label = in.readInt();
+        List<String> _inheritFrom = new ArrayList<>();
+        in.readStringList(_inheritFrom);
+
+        this.id = _id;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, id);
+        this.label = _label;
+        com.android.internal.util.AnnotationValidations.validate(
+                StringRes.class, null, label);
+        this.inheritFrom = _inheritFrom;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, inheritFrom);
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    @DataClass.Generated.Member
+    public static final @NonNull Parcelable.Creator<ParsedFeature> CREATOR
+            = new Parcelable.Creator<ParsedFeature>() {
+        @Override
+        public ParsedFeature[] newArray(int size) {
+            return new ParsedFeature[size];
+        }
+
+        @Override
+        public ParsedFeature createFromParcel(@NonNull Parcel in) {
+            return new ParsedFeature(in);
+        }
+    };
+
+    @DataClass.Generated(
+            time = 1581379861853L,
+            codegenVersion = "1.0.14",
+            sourceFile = "frameworks/base/core/java/android/content/pm/parsing/component/ParsedFeature.java",
+            inputSignatures = "public static final  int MAX_FEATURE_ID_LEN\nprivate static final  int MAX_NUM_FEATURES\npublic final @android.annotation.NonNull java.lang.String id\npublic final @android.annotation.StringRes int label\npublic final @android.annotation.NonNull java.util.List<java.lang.String> inheritFrom\npublic static  boolean isCombinationValid(java.util.List<android.content.pm.parsing.component.ParsedFeature>)\nclass ParsedFeature extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genAidl=false)")
+    @Deprecated
+    private void __metadata() {}
+
+
+    //@formatter:on
+    // End of generated code
+
+}
diff --git a/core/java/android/content/pm/parsing/component/ParsedFeatureUtils.java b/core/java/android/content/pm/parsing/component/ParsedFeatureUtils.java
new file mode 100644
index 0000000..fb52801
--- /dev/null
+++ b/core/java/android/content/pm/parsing/component/ParsedFeatureUtils.java
@@ -0,0 +1,109 @@
+/*
+ * 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.component;
+
+import android.annotation.NonNull;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
+
+import com.android.internal.R;
+import android.content.pm.parsing.result.ParseInput;
+import android.content.pm.parsing.result.ParseResult;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/** @hide */
+public class ParsedFeatureUtils {
+
+    @NonNull
+    public static ParseResult<ParsedFeature> parseFeature(Resources res, XmlResourceParser parser,
+            ParseInput input) throws IOException, XmlPullParserException {
+        String featureId;
+        int label;
+        List<String> inheritFrom = null;
+
+        TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestFeature);
+        if (sa == null) {
+            return input.error("<feature> could not be parsed");
+        }
+
+        try {
+            featureId = sa.getNonConfigurationString(R.styleable.AndroidManifestFeature_featureId,
+                    0);
+            if (featureId == null) {
+                return input.error("<featureId> does not specify android:featureId");
+            }
+            if (featureId.length() > ParsedFeature.MAX_FEATURE_ID_LEN) {
+                return input.error("<featureId> is too long. Max length is "
+                        + ParsedFeature.MAX_FEATURE_ID_LEN);
+            }
+
+            label = sa.getResourceId(R.styleable.AndroidManifestFeature_label, 0);
+            if (label == Resources.ID_NULL) {
+                return input.error("<featureId> does not specify android:label");
+            }
+        } finally {
+            sa.recycle();
+        }
+
+        int type;
+        final int innerDepth = parser.getDepth();
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
+            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                continue;
+            }
+
+            String tagName = parser.getName();
+            if (tagName.equals("inherit-from")) {
+                sa = res.obtainAttributes(parser, R.styleable.AndroidManifestFeatureInheritFrom);
+                if (sa == null) {
+                    return input.error("<inherit-from> could not be parsed");
+                }
+
+                try {
+                    String inheritFromId = sa.getNonConfigurationString(
+                            R.styleable.AndroidManifestFeatureInheritFrom_featureId,0);
+
+                    if (inheritFrom == null) {
+                        inheritFrom = new ArrayList<>();
+                    }
+                    inheritFrom.add(inheritFromId);
+                } finally {
+                    sa.recycle();
+                }
+            } else {
+                return input.error("Bad element under <feature>: " + tagName);
+            }
+        }
+
+        if (inheritFrom == null) {
+            inheritFrom = Collections.emptyList();
+        } else {
+            ((ArrayList) inheritFrom).trimToSize();
+        }
+
+        return input.success(new ParsedFeature(featureId, label, inheritFrom));
+    }
+}
diff --git a/core/java/android/content/pm/parsing/component/ParsedInstrumentation.java b/core/java/android/content/pm/parsing/component/ParsedInstrumentation.java
new file mode 100644
index 0000000..396a145
--- /dev/null
+++ b/core/java/android/content/pm/parsing/component/ParsedInstrumentation.java
@@ -0,0 +1,116 @@
+/*
+ * 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.component;
+
+import static android.content.pm.parsing.ParsingPackageImpl.sForString;
+
+import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
+
+import com.android.internal.util.DataClass;
+import com.android.internal.util.Parcelling;
+import com.android.internal.util.Parcelling.BuiltIn.ForInternedString;
+
+/** @hide */
+public class ParsedInstrumentation extends ParsedComponent {
+
+    @Nullable
+    @DataClass.ParcelWith(ForInternedString.class)
+    private String targetPackage;
+    @Nullable
+    @DataClass.ParcelWith(ForInternedString.class)
+    private String targetProcesses;
+    boolean handleProfiling;
+    boolean functionalTest;
+
+    public ParsedInstrumentation() {
+    }
+
+    public void setTargetPackage(@Nullable String targetPackage) {
+        this.targetPackage = TextUtils.safeIntern(targetPackage);
+    }
+
+    public void setTargetProcesses(@Nullable String targetProcesses) {
+        this.targetProcesses = TextUtils.safeIntern(targetProcesses);
+    }
+
+    public String toString() {
+        StringBuilder sb = new StringBuilder(128);
+        sb.append("Instrumentation{");
+        sb.append(Integer.toHexString(System.identityHashCode(this)));
+        sb.append(' ');
+        ComponentName.appendShortString(sb, getPackageName(), getName());
+        sb.append('}');
+        return sb.toString();
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        super.writeToParcel(dest, flags);
+        sForString.parcel(this.targetPackage, dest, flags);
+        sForString.parcel(this.targetProcesses, dest, flags);
+        dest.writeBoolean(this.handleProfiling);
+        dest.writeBoolean(this.functionalTest);
+    }
+
+    protected ParsedInstrumentation(Parcel in) {
+        super(in);
+        this.targetPackage = sForString.unparcel(in);
+        this.targetProcesses = sForString.unparcel(in);
+        this.handleProfiling = in.readByte() != 0;
+        this.functionalTest = in.readByte() != 0;
+    }
+
+    public static final Parcelable.Creator<ParsedInstrumentation> CREATOR =
+            new Parcelable.Creator<ParsedInstrumentation>() {
+                @Override
+                public ParsedInstrumentation createFromParcel(Parcel source) {
+                    return new ParsedInstrumentation(source);
+                }
+
+                @Override
+                public ParsedInstrumentation[] newArray(int size) {
+                    return new ParsedInstrumentation[size];
+                }
+            };
+
+    @Nullable
+    public String getTargetPackage() {
+        return targetPackage;
+    }
+
+    @Nullable
+    public String getTargetProcesses() {
+        return targetProcesses;
+    }
+
+    public boolean isHandleProfiling() {
+        return handleProfiling;
+    }
+
+    public boolean isFunctionalTest() {
+        return functionalTest;
+    }
+}
diff --git a/core/java/android/content/pm/parsing/component/ParsedInstrumentationUtils.java b/core/java/android/content/pm/parsing/component/ParsedInstrumentationUtils.java
new file mode 100644
index 0000000..89645fc
--- /dev/null
+++ b/core/java/android/content/pm/parsing/component/ParsedInstrumentationUtils.java
@@ -0,0 +1,74 @@
+/*
+ * 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.component;
+
+import android.annotation.NonNull;
+import android.content.pm.parsing.ParsingPackage;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
+
+import com.android.internal.R;
+import android.content.pm.parsing.result.ParseInput;
+import android.content.pm.parsing.result.ParseResult;
+
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+
+/** @hide */
+public class ParsedInstrumentationUtils {
+
+    @NonNull
+    public static ParseResult<ParsedInstrumentation> parseInstrumentation(ParsingPackage pkg,
+            Resources res, XmlResourceParser parser, boolean useRoundIcon,
+            ParseInput input) throws IOException, XmlPullParserException {
+        ParsedInstrumentation
+                instrumentation = new ParsedInstrumentation();
+        String tag = "<" + parser.getName() + ">";
+
+        TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestInstrumentation);
+        try {
+            ParseResult<ParsedInstrumentation> result = ParsedComponentUtils.parseComponent(
+                    instrumentation, tag, pkg, sa, useRoundIcon, input,
+                    R.styleable.AndroidManifestInstrumentation_banner,
+                    null /*descriptionAttr*/,
+                    R.styleable.AndroidManifestInstrumentation_icon,
+                    R.styleable.AndroidManifestInstrumentation_label,
+                    R.styleable.AndroidManifestInstrumentation_logo,
+                    R.styleable.AndroidManifestInstrumentation_name,
+                    R.styleable.AndroidManifestInstrumentation_roundIcon);
+            if (result.isError()) {
+                return result;
+            }
+
+            // @formatter:off
+            // Note: don't allow this value to be a reference to a resource
+            // that may change.
+            instrumentation.setTargetPackage(sa.getNonResourceString(R.styleable.AndroidManifestInstrumentation_targetPackage));
+            instrumentation.setTargetProcesses(sa.getNonResourceString(R.styleable.AndroidManifestInstrumentation_targetProcesses));
+            instrumentation.handleProfiling = sa.getBoolean(R.styleable.AndroidManifestInstrumentation_handleProfiling, false);
+            instrumentation.functionalTest = sa.getBoolean(R.styleable.AndroidManifestInstrumentation_functionalTest, false);
+            // @formatter:on
+        } finally {
+            sa.recycle();
+        }
+
+        return ComponentParseUtils.parseAllMetaData(pkg, res, parser, tag, instrumentation,
+                input);
+    }
+}
diff --git a/core/java/android/content/pm/parsing/component/ParsedIntentInfo.java b/core/java/android/content/pm/parsing/component/ParsedIntentInfo.java
new file mode 100644
index 0000000..0ba92cc
--- /dev/null
+++ b/core/java/android/content/pm/parsing/component/ParsedIntentInfo.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 android.content.pm.parsing.component;
+
+import android.annotation.Nullable;
+import android.content.IntentFilter;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Pair;
+
+import com.android.internal.util.DataClass;
+import com.android.internal.util.Parcelling;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/** @hide **/
+public final class ParsedIntentInfo extends IntentFilter {
+
+    public static final Parceler PARCELER = new Parceler();
+
+    public static class Parceler implements Parcelling<ParsedIntentInfo> {
+
+        @Override
+        public void parcel(ParsedIntentInfo item, Parcel dest, int parcelFlags) {
+            item.writeIntentInfoToParcel(dest, parcelFlags);
+        }
+
+        @Override
+        public ParsedIntentInfo unparcel(Parcel source) {
+            return new ParsedIntentInfo(source);
+        }
+    }
+
+    public static class ListParceler implements Parcelling<List<ParsedIntentInfo>> {
+
+        /**
+         * <p>
+         * Implementation note: The serialized form for the intent list also contains the name
+         * of the concrete class that's stored in the list, and assumes that every element of the
+         * list is of the same type. This is very similar to the original parcelable mechanism.
+         * We cannot use that directly because IntentInfo extends IntentFilter, which is parcelable
+         * and is public API. It also declares Parcelable related methods as final which means
+         * we can't extend them. The approach of using composition instead of inheritance leads to
+         * a large set of cascading changes in the PackageManagerService, which seem undesirable.
+         *
+         * <p>
+         * <b>WARNING: </b> The list of objects returned by this function might need to be fixed up
+         * to make sure their owner fields are consistent. See {@code fixupOwner}.
+         */
+        @Override
+        public void parcel(List<ParsedIntentInfo> item, Parcel dest, int parcelFlags) {
+            if (item == null) {
+                dest.writeInt(-1);
+                return;
+            }
+
+            final int size = item.size();
+            dest.writeInt(size);
+
+            for (int index = 0; index < size; index++) {
+                PARCELER.parcel(item.get(index), dest, parcelFlags);
+            }
+        }
+
+        @Override
+        public List<ParsedIntentInfo> unparcel(Parcel source) {
+            int size = source.readInt();
+            if (size == -1) {
+                return null;
+            }
+
+            if (size == 0) {
+                return new ArrayList<>(0);
+            }
+
+            final ArrayList<ParsedIntentInfo> intentsList = new ArrayList<>(size);
+            for (int i = 0; i < size; ++i) {
+                intentsList.add(PARCELER.unparcel(source));
+            }
+
+            return intentsList;
+        }
+    }
+
+    public static class StringPairListParceler implements Parcelling<List<Pair<String, ParsedIntentInfo>>> {
+
+        @Override
+        public void parcel(List<Pair<String, ParsedIntentInfo>> item, Parcel dest,
+                int parcelFlags) {
+            if (item == null) {
+                dest.writeInt(-1);
+                return;
+            }
+
+            final int size = item.size();
+            dest.writeInt(size);
+
+            for (int index = 0; index < size; index++) {
+                Pair<String, ParsedIntentInfo> pair = item.get(index);
+                dest.writeString(pair.first);
+                PARCELER.parcel(pair.second, dest, parcelFlags);
+            }
+        }
+
+        @Override
+        public List<Pair<String, ParsedIntentInfo>> unparcel(Parcel source) {
+            int size = source.readInt();
+            if (size == -1) {
+                return null;
+            }
+
+            if (size == 0) {
+                return new ArrayList<>(0);
+            }
+
+            final List<Pair<String, ParsedIntentInfo>> list = new ArrayList<>(size);
+            for (int i = 0; i < size; ++i) {
+                list.add(Pair.create(source.readString(), PARCELER.unparcel(source)));
+            }
+
+            return list;
+        }
+    }
+
+    boolean hasDefault;
+    int labelRes;
+    @Nullable
+    CharSequence nonLocalizedLabel;
+    int icon;
+
+    public ParsedIntentInfo() {
+    }
+
+    public ParsedIntentInfo(Parcel in) {
+        super(in);
+        hasDefault = in.readBoolean();
+        labelRes = in.readInt();
+        nonLocalizedLabel = in.readCharSequence();
+        icon = in.readInt();
+    }
+
+    public void writeIntentInfoToParcel(Parcel dest, int flags) {
+        super.writeToParcel(dest, flags);
+        dest.writeBoolean(hasDefault);
+        dest.writeInt(labelRes);
+        dest.writeCharSequence(nonLocalizedLabel);
+        dest.writeInt(icon);
+    }
+
+    public String toString() {
+        return "ProviderIntentInfo{"
+                + Integer.toHexString(System.identityHashCode(this))
+                + '}';
+    }
+
+    public static final Parcelable.Creator<ParsedIntentInfo> CREATOR =
+            new Parcelable.Creator<ParsedIntentInfo>() {
+                @Override
+                public ParsedIntentInfo createFromParcel(Parcel source) {
+                    return new ParsedIntentInfo(source);
+                }
+
+                @Override
+                public ParsedIntentInfo[] newArray(int size) {
+                    return new ParsedIntentInfo[size];
+                }
+            };
+
+    public boolean isHasDefault() {
+        return hasDefault;
+    }
+
+    public int getLabelRes() {
+        return labelRes;
+    }
+
+    @Nullable
+    public CharSequence getNonLocalizedLabel() {
+        return nonLocalizedLabel;
+    }
+
+    public int getIcon() {
+        return icon;
+    }
+}
diff --git a/core/java/android/content/pm/parsing/component/ParsedIntentInfoUtils.java b/core/java/android/content/pm/parsing/component/ParsedIntentInfoUtils.java
new file mode 100644
index 0000000..a7b950b
--- /dev/null
+++ b/core/java/android/content/pm/parsing/component/ParsedIntentInfoUtils.java
@@ -0,0 +1,249 @@
+/*
+ * 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.component;
+
+import android.annotation.NonNull;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageParser;
+import android.content.pm.parsing.ParsingPackage;
+import android.content.pm.parsing.ParsingPackageUtils;
+import android.content.pm.parsing.ParsingUtils;
+import android.content.pm.parsing.result.ParseInput;
+import android.content.pm.parsing.result.ParseResult;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
+import android.os.PatternMatcher;
+import android.text.TextUtils;
+import android.util.Slog;
+import android.util.TypedValue;
+
+import com.android.internal.R;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.util.Iterator;
+
+/** @hide */
+public class ParsedIntentInfoUtils {
+
+    private static final String TAG = ParsingPackageUtils.TAG;
+
+    @NonNull
+    public static ParseResult<ParsedIntentInfo> parseIntentInfo(String className,
+            ParsingPackage pkg, Resources res, XmlResourceParser parser, boolean allowGlobs,
+            boolean allowAutoVerify, ParseInput input)
+            throws XmlPullParserException, IOException {
+        ParsedIntentInfo intentInfo = new ParsedIntentInfo();
+        TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestIntentFilter);
+        try {
+            intentInfo.setPriority(sa.getInt(R.styleable.AndroidManifestIntentFilter_priority, 0));
+            intentInfo.setOrder(sa.getInt(R.styleable.AndroidManifestIntentFilter_order, 0));
+
+            TypedValue v = sa.peekValue(R.styleable.AndroidManifestIntentFilter_label);
+            if (v != null) {
+                intentInfo.labelRes = v.resourceId;
+                if (v.resourceId == 0) {
+                    intentInfo.nonLocalizedLabel = v.coerceToString();
+                }
+            }
+
+            if (PackageParser.sUseRoundIcon) {
+                intentInfo.icon = sa.getResourceId(
+                        R.styleable.AndroidManifestIntentFilter_roundIcon, 0);
+            }
+
+            if (intentInfo.icon == 0) {
+                intentInfo.icon = sa.getResourceId(R.styleable.AndroidManifestIntentFilter_icon, 0);
+            }
+
+            if (allowAutoVerify) {
+                intentInfo.setAutoVerify(sa.getBoolean(
+                        R.styleable.AndroidManifestIntentFilter_autoVerify,
+                        false));
+            }
+        } finally {
+            sa.recycle();
+        }
+        final int depth = parser.getDepth();
+        int type;
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG
+                || parser.getDepth() > depth)) {
+            if (type != XmlPullParser.START_TAG) {
+                continue;
+            }
+
+            final ParseResult result;
+            String nodeName = parser.getName();
+            switch (nodeName) {
+                case "action": {
+                    String value = parser.getAttributeValue(PackageParser.ANDROID_RESOURCES,
+                            "name");
+                    if (TextUtils.isEmpty(value)) {
+                        result = input.error("No value supplied for <android:name>");
+                    } else {
+                        intentInfo.addAction(value);
+                        result = input.success(null);
+                    }
+                    break;
+                }
+                case "category": {
+                    String value = parser.getAttributeValue(PackageParser.ANDROID_RESOURCES,
+                            "name");
+                    if (TextUtils.isEmpty(value)) {
+                        result = input.error("No value supplied for <android:name>");
+                    } else {
+                        intentInfo.addCategory(value);
+                        result = input.success(null);
+                    }
+                    break;
+                }
+                case "data":
+                    result = parseData(intentInfo, res, parser, allowGlobs, input);
+                    break;
+                default:
+                    result = ParsingUtils.unknownTag("<intent-filter>", pkg, parser, input);
+                    break;
+            }
+
+            if (result.isError()) {
+                return input.error(result);
+            }
+        }
+
+        intentInfo.hasDefault = intentInfo.hasCategory(Intent.CATEGORY_DEFAULT);
+
+        if (PackageParser.DEBUG_PARSER) {
+            final StringBuilder cats = new StringBuilder("Intent d=");
+            cats.append(intentInfo.isHasDefault());
+            cats.append(", cat=");
+
+            final Iterator<String> it = intentInfo.categoriesIterator();
+            if (it != null) {
+                while (it.hasNext()) {
+                    cats.append(' ');
+                    cats.append(it.next());
+                }
+            }
+            Slog.d(TAG, cats.toString());
+        }
+
+        return input.success(intentInfo);
+    }
+
+    @NonNull
+    private static ParseResult<ParsedIntentInfo> parseData(ParsedIntentInfo intentInfo,
+            Resources resources, XmlResourceParser parser, boolean allowGlobs, ParseInput input) {
+        TypedArray sa = resources.obtainAttributes(parser, R.styleable.AndroidManifestData);
+        try {
+            String str = sa.getNonConfigurationString(
+                    R.styleable.AndroidManifestData_mimeType, 0);
+            if (str != null) {
+                try {
+                    intentInfo.addDataType(str);
+                } catch (IntentFilter.MalformedMimeTypeException e) {
+                    return input.error(e.toString());
+                }
+            }
+
+            str = sa.getNonConfigurationString(
+                    R.styleable.AndroidManifestData_mimeGroup, 0);
+            if (str != null) {
+                intentInfo.addMimeGroup(str);
+            }
+
+            str = sa.getNonConfigurationString(
+                    R.styleable.AndroidManifestData_scheme, 0);
+            if (str != null) {
+                intentInfo.addDataScheme(str);
+            }
+
+            str = sa.getNonConfigurationString(
+                    R.styleable.AndroidManifestData_ssp, 0);
+            if (str != null) {
+                intentInfo.addDataSchemeSpecificPart(str,
+                        PatternMatcher.PATTERN_LITERAL);
+            }
+
+            str = sa.getNonConfigurationString(
+                    R.styleable.AndroidManifestData_sspPrefix, 0);
+            if (str != null) {
+                intentInfo.addDataSchemeSpecificPart(str,
+                        PatternMatcher.PATTERN_PREFIX);
+            }
+
+            str = sa.getNonConfigurationString(
+                    R.styleable.AndroidManifestData_sspPattern, 0);
+            if (str != null) {
+                if (!allowGlobs) {
+                    return input.error(
+                            "sspPattern not allowed here; ssp must be literal");
+                }
+                intentInfo.addDataSchemeSpecificPart(str,
+                        PatternMatcher.PATTERN_SIMPLE_GLOB);
+            }
+
+            String host = sa.getNonConfigurationString(
+                    R.styleable.AndroidManifestData_host, 0);
+            String port = sa.getNonConfigurationString(
+                    R.styleable.AndroidManifestData_port, 0);
+            if (host != null) {
+                intentInfo.addDataAuthority(host, port);
+            }
+
+            str = sa.getNonConfigurationString(
+                    R.styleable.AndroidManifestData_path, 0);
+            if (str != null) {
+                intentInfo.addDataPath(str, PatternMatcher.PATTERN_LITERAL);
+            }
+
+            str = sa.getNonConfigurationString(
+                    R.styleable.AndroidManifestData_pathPrefix, 0);
+            if (str != null) {
+                intentInfo.addDataPath(str, PatternMatcher.PATTERN_PREFIX);
+            }
+
+            str = sa.getNonConfigurationString(
+                    R.styleable.AndroidManifestData_pathPattern, 0);
+            if (str != null) {
+                if (!allowGlobs) {
+                    return input.error(
+                            "pathPattern not allowed here; path must be literal");
+                }
+                intentInfo.addDataPath(str, PatternMatcher.PATTERN_SIMPLE_GLOB);
+            }
+
+            str = sa.getNonConfigurationString(
+                    R.styleable.AndroidManifestData_pathAdvancedPattern, 0);
+            if (str != null) {
+                if (!allowGlobs) {
+                    return input.error(
+                            "pathAdvancedPattern not allowed here; path must be literal");
+                }
+                intentInfo.addDataPath(str, PatternMatcher.PATTERN_ADVANCED_GLOB);
+            }
+
+            return input.success(null);
+        } finally {
+            sa.recycle();
+        }
+    }
+}
diff --git a/core/java/android/content/pm/parsing/component/ParsedMainComponent.java b/core/java/android/content/pm/parsing/component/ParsedMainComponent.java
new file mode 100644
index 0000000..59e9a84
--- /dev/null
+++ b/core/java/android/content/pm/parsing/component/ParsedMainComponent.java
@@ -0,0 +1,153 @@
+/*
+ * 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.component;
+
+import static android.content.pm.parsing.ParsingPackageImpl.sForString;
+
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
+
+import com.android.internal.util.DataClass;
+import com.android.internal.util.Parcelling;
+import com.android.internal.util.Parcelling.BuiltIn.ForInternedString;
+
+/** @hide */
+public class ParsedMainComponent extends ParsedComponent {
+
+    @Nullable
+    @DataClass.ParcelWith(ForInternedString.class)
+    private String processName;
+    boolean directBootAware;
+    boolean enabled = true;
+    boolean exported;
+    int order;
+
+    @Nullable
+    String splitName;
+
+    public ParsedMainComponent() {
+    }
+
+    public ParsedMainComponent(ParsedMainComponent other) {
+        super(other);
+        this.processName = other.processName;
+        this.directBootAware = other.directBootAware;
+        this.enabled = other.enabled;
+        this.exported = other.exported;
+        this.order = other.order;
+        this.splitName = other.splitName;
+    }
+
+    public ParsedMainComponent setProcessName(String processName) {
+        this.processName = TextUtils.safeIntern(processName);
+        return this;
+    }
+
+    public ParsedMainComponent setEnabled(boolean enabled) {
+        this.enabled = enabled;
+        return this;
+    }
+
+    /**
+     * A main component's name is a class name. This makes code slightly more readable.
+     */
+    public String getClassName() {
+        return getName();
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        super.writeToParcel(dest, flags);
+        sForString.parcel(this.processName, dest, flags);
+        dest.writeBoolean(this.directBootAware);
+        dest.writeBoolean(this.enabled);
+        dest.writeBoolean(this.exported);
+        dest.writeInt(this.order);
+        dest.writeString(this.splitName);
+    }
+
+    protected ParsedMainComponent(Parcel in) {
+        super(in);
+        this.processName = sForString.unparcel(in);
+        this.directBootAware = in.readBoolean();
+        this.enabled = in.readBoolean();
+        this.exported = in.readBoolean();
+        this.order = in.readInt();
+        this.splitName = in.readString();
+    }
+
+    public static final Parcelable.Creator<ParsedMainComponent> CREATOR =
+            new Parcelable.Creator<ParsedMainComponent>() {
+                @Override
+                public ParsedMainComponent createFromParcel(Parcel source) {
+                    return new ParsedMainComponent(source);
+                }
+
+                @Override
+                public ParsedMainComponent[] newArray(int size) {
+                    return new ParsedMainComponent[size];
+                }
+            };
+
+    @Nullable
+    public String getProcessName() {
+        return processName;
+    }
+
+    public boolean isDirectBootAware() {
+        return directBootAware;
+    }
+
+    public boolean isEnabled() {
+        return enabled;
+    }
+
+    public boolean isExported() {
+        return exported;
+    }
+
+    public int getOrder() {
+        return order;
+    }
+
+    @Nullable
+    public String getSplitName() {
+        return splitName;
+    }
+
+    public ParsedMainComponent setDirectBootAware(boolean value) {
+        directBootAware = value;
+        return this;
+    }
+
+    public ParsedMainComponent setExported(boolean value) {
+        exported = value;
+        return this;
+    }
+
+    public ParsedMainComponent setSplitName(@Nullable String value) {
+        splitName = value;
+        return this;
+    }
+}
diff --git a/core/java/android/content/pm/parsing/component/ParsedMainComponentUtils.java b/core/java/android/content/pm/parsing/component/ParsedMainComponentUtils.java
new file mode 100644
index 0000000..6188f89
--- /dev/null
+++ b/core/java/android/content/pm/parsing/component/ParsedMainComponentUtils.java
@@ -0,0 +1,137 @@
+/*
+ * 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.component;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.IntentFilter;
+import android.content.pm.parsing.ParsingPackage;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
+import android.os.Build;
+import android.util.Slog;
+
+import com.android.internal.annotations.VisibleForTesting;
+import android.content.pm.parsing.ParsingPackageUtils;
+import android.content.pm.parsing.result.ParseInput;
+import android.content.pm.parsing.result.ParseResult;
+
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+
+/** @hide */
+class ParsedMainComponentUtils {
+
+    private static final String TAG = ParsingPackageUtils.TAG;
+
+    @NonNull
+    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+    static <Component extends ParsedMainComponent> ParseResult<Component> parseMainComponent(
+            Component component, String tag, String[] separateProcesses, ParsingPackage pkg,
+            TypedArray array, int flags, boolean useRoundIcon, ParseInput input,
+            int bannerAttr, int descriptionAttr, @Nullable Integer directBootAwareAttr,
+            @Nullable Integer enabledAttr, int iconAttr, int labelAttr, int logoAttr, int nameAttr,
+            @Nullable Integer processAttr, int roundIconAttr, @Nullable Integer splitNameAttr) {
+        ParseResult<Component> result = ParsedComponentUtils.parseComponent(component, tag, pkg,
+                array, useRoundIcon, input, bannerAttr, descriptionAttr, iconAttr, labelAttr,
+                logoAttr, nameAttr, roundIconAttr);
+        if (result.isError()) {
+            return result;
+        }
+
+        if (directBootAwareAttr != null) {
+            component.directBootAware = array.getBoolean(directBootAwareAttr, false);
+            if (component.isDirectBootAware()) {
+                pkg.setPartiallyDirectBootAware(true);
+            }
+        }
+
+        if (enabledAttr != null) {
+            component.enabled = array.getBoolean(enabledAttr, true);
+        }
+
+        if (processAttr != null) {
+            CharSequence processName;
+            if (pkg.getTargetSdkVersion() >= Build.VERSION_CODES.FROYO) {
+                processName = array.getNonConfigurationString(processAttr,
+                        Configuration.NATIVE_CONFIG_VERSION);
+            } else {
+                // Some older apps have been seen to use a resource reference
+                // here that on older builds was ignored (with a warning).  We
+                // need to continue to do this for them so they don't break.
+                processName = array.getNonResourceString(processAttr);
+            }
+
+            // Backwards-compat, ignore error
+            ParseResult<String> processNameResult = ComponentParseUtils.buildProcessName(
+                    pkg.getPackageName(), pkg.getProcessName(), processName, flags,
+                    separateProcesses, input);
+            if (processNameResult.isSuccess()) {
+                component.setProcessName(processNameResult.getResult());
+            } else {
+                // Backwards-compat, ignore error
+                processNameResult.ignoreError();
+            }
+        }
+
+        if (splitNameAttr != null) {
+            component.splitName = array.getNonConfigurationString(splitNameAttr, 0);
+        }
+
+        return input.success(component);
+    }
+
+    static ParseResult<ParsedIntentInfo> parseIntentFilter(
+            ParsedMainComponent mainComponent,
+            ParsingPackage pkg, Resources resources, XmlResourceParser parser,
+            boolean visibleToEphemeral, boolean allowGlobs, boolean allowAutoVerify,
+            boolean allowImplicitEphemeralVisibility, boolean failOnNoActions,
+            ParseInput input) throws IOException, XmlPullParserException {
+        ParseResult<ParsedIntentInfo> intentResult = ParsedIntentInfoUtils.parseIntentInfo(
+                mainComponent.getName(), pkg, resources, parser, allowGlobs,
+                allowAutoVerify, input);
+        if (intentResult.isError()) {
+            return input.error(intentResult);
+        }
+
+        ParsedIntentInfo intent = intentResult.getResult();
+        int actionCount = intent.countActions();
+        if (actionCount == 0 && failOnNoActions) {
+            Slog.w(TAG, "No actions in " + parser.getName() + " at " + pkg.getBaseCodePath() + " "
+                    + parser.getPositionDescription());
+            // Backward-compat, do not actually fail
+            return input.success(null);
+        }
+
+        int intentVisibility;
+        if (visibleToEphemeral) {
+            intentVisibility = IntentFilter.VISIBILITY_EXPLICIT;
+        } else if (allowImplicitEphemeralVisibility
+                && ComponentParseUtils.isImplicitlyExposedIntent(intent)){
+            intentVisibility = IntentFilter.VISIBILITY_IMPLICIT;
+        } else {
+            intentVisibility = IntentFilter.VISIBILITY_NONE;
+        }
+        intent.setVisibilityToInstantApp(intentVisibility);
+
+        return input.success(intentResult.getResult());
+    }
+
+}
diff --git a/core/java/android/content/pm/parsing/component/ParsedPermission.java b/core/java/android/content/pm/parsing/component/ParsedPermission.java
new file mode 100644
index 0000000..6c36ecb
--- /dev/null
+++ b/core/java/android/content/pm/parsing/component/ParsedPermission.java
@@ -0,0 +1,194 @@
+/*
+ * 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.component;
+
+import static android.content.pm.parsing.ParsingPackageImpl.sForString;
+
+import android.annotation.Nullable;
+import android.content.pm.PermissionInfo;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.DataClass;
+import com.android.internal.util.Parcelling;
+import com.android.internal.util.Parcelling.BuiltIn.ForInternedString;
+
+/** @hide */
+public class ParsedPermission extends ParsedComponent {
+
+    @Nullable
+    String backgroundPermission;
+    @Nullable
+    @DataClass.ParcelWith(ForInternedString.class)
+    private String group;
+    int requestRes;
+    int protectionLevel;
+    boolean tree;
+    @Nullable
+    private ParsedPermissionGroup parsedPermissionGroup;
+
+    @VisibleForTesting
+    public ParsedPermission() {
+    }
+
+    public ParsedPermission(ParsedPermission other) {
+        super(other);
+        this.backgroundPermission = other.backgroundPermission;
+        this.group = other.group;
+        this.requestRes = other.requestRes;
+        this.protectionLevel = other.protectionLevel;
+        this.tree = other.tree;
+        this.parsedPermissionGroup = other.parsedPermissionGroup;
+    }
+
+    public ParsedPermission(ParsedPermission other, PermissionInfo pendingPermissionInfo,
+            String packageName, String name) {
+        this(other);
+
+        this.flags = pendingPermissionInfo.flags;
+        this.descriptionRes = pendingPermissionInfo.descriptionRes;
+
+        this.backgroundPermission = pendingPermissionInfo.backgroundPermission;
+        this.group = pendingPermissionInfo.group;
+        this.requestRes = pendingPermissionInfo.requestRes;
+        this.protectionLevel = pendingPermissionInfo.protectionLevel;
+
+        setName(name);
+        setPackageName(packageName);
+    }
+
+    public ParsedPermission setGroup(String group) {
+        this.group = TextUtils.safeIntern(group);
+        return this;
+    }
+
+    public ParsedPermission setFlags(int flags) {
+        this.flags = flags;
+        return this;
+    }
+
+    public boolean isRuntime() {
+        return getProtection() == PermissionInfo.PROTECTION_DANGEROUS;
+    }
+
+    public boolean isAppOp() {
+        return (protectionLevel & PermissionInfo.PROTECTION_FLAG_APPOP) != 0;
+    }
+
+    @PermissionInfo.Protection
+    public int getProtection() {
+        return protectionLevel & PermissionInfo.PROTECTION_MASK_BASE;
+    }
+
+    public int getProtectionFlags() {
+        return protectionLevel & ~PermissionInfo.PROTECTION_MASK_BASE;
+    }
+
+    public int calculateFootprint() {
+        int size = getName().length();
+        if (getNonLocalizedLabel() != null) {
+            size += getNonLocalizedLabel().length();
+        }
+        return size;
+    }
+
+    public String toString() {
+        return "Permission{"
+                + Integer.toHexString(System.identityHashCode(this))
+                + " " + getName() + "}";
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        super.writeToParcel(dest, flags);
+        dest.writeString(this.backgroundPermission);
+        sForString.parcel(this.group, dest, flags);
+        dest.writeInt(this.requestRes);
+        dest.writeInt(this.protectionLevel);
+        dest.writeBoolean(this.tree);
+        dest.writeParcelable(this.parsedPermissionGroup, flags);
+    }
+
+    protected ParsedPermission(Parcel in) {
+        super(in);
+        // We use the boot classloader for all classes that we load.
+        final ClassLoader boot = Object.class.getClassLoader();
+        this.backgroundPermission = in.readString();
+        this.group = sForString.unparcel(in);
+        this.requestRes = in.readInt();
+        this.protectionLevel = in.readInt();
+        this.tree = in.readBoolean();
+        this.parsedPermissionGroup = in.readParcelable(boot);
+    }
+
+    public static final Parcelable.Creator<ParsedPermission> CREATOR =
+            new Parcelable.Creator<ParsedPermission>() {
+                @Override
+                public ParsedPermission createFromParcel(Parcel source) {
+                    return new ParsedPermission(source);
+                }
+
+                @Override
+                public ParsedPermission[] newArray(int size) {
+                    return new ParsedPermission[size];
+                }
+            };
+
+    @Nullable
+    public String getBackgroundPermission() {
+        return backgroundPermission;
+    }
+
+    @Nullable
+    public String getGroup() {
+        return group;
+    }
+
+    public int getRequestRes() {
+        return requestRes;
+    }
+
+    public int getProtectionLevel() {
+        return protectionLevel;
+    }
+
+    public boolean isTree() {
+        return tree;
+    }
+
+    @Nullable
+    public ParsedPermissionGroup getParsedPermissionGroup() {
+        return parsedPermissionGroup;
+    }
+
+    public ParsedPermission setProtectionLevel(int value) {
+        protectionLevel = value;
+        return this;
+    }
+
+    public ParsedPermission setParsedPermissionGroup(@Nullable ParsedPermissionGroup value) {
+        parsedPermissionGroup = value;
+        return this;
+    }
+}
diff --git a/core/java/android/content/pm/parsing/component/ParsedPermissionGroup.java b/core/java/android/content/pm/parsing/component/ParsedPermissionGroup.java
new file mode 100644
index 0000000..741c00c
--- /dev/null
+++ b/core/java/android/content/pm/parsing/component/ParsedPermissionGroup.java
@@ -0,0 +1,102 @@
+/*
+ * 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.component;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.DataClass;
+
+/** @hide */
+public class ParsedPermissionGroup extends ParsedComponent {
+
+    int requestDetailResourceId;
+    int backgroundRequestResourceId;
+    int backgroundRequestDetailResourceId;
+    int requestRes;
+    int priority;
+
+    public void setPriority(int priority) {
+        this.priority = priority;
+    }
+
+    public String toString() {
+        return "PermissionGroup{"
+                + Integer.toHexString(System.identityHashCode(this))
+                + " " + getName() + "}";
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        super.writeToParcel(dest, flags);
+        dest.writeInt(this.requestDetailResourceId);
+        dest.writeInt(this.backgroundRequestResourceId);
+        dest.writeInt(this.backgroundRequestDetailResourceId);
+        dest.writeInt(this.requestRes);
+        dest.writeInt(this.priority);
+    }
+
+    public ParsedPermissionGroup() {
+    }
+
+    protected ParsedPermissionGroup(Parcel in) {
+        super(in);
+        this.requestDetailResourceId = in.readInt();
+        this.backgroundRequestResourceId = in.readInt();
+        this.backgroundRequestDetailResourceId = in.readInt();
+        this.requestRes = in.readInt();
+        this.priority = in.readInt();
+    }
+
+    public static final Parcelable.Creator<ParsedPermissionGroup> CREATOR =
+            new Parcelable.Creator<ParsedPermissionGroup>() {
+                @Override
+                public ParsedPermissionGroup createFromParcel(Parcel source) {
+                    return new ParsedPermissionGroup(source);
+                }
+
+                @Override
+                public ParsedPermissionGroup[] newArray(int size) {
+                    return new ParsedPermissionGroup[size];
+                }
+            };
+
+    public int getRequestDetailResourceId() {
+        return requestDetailResourceId;
+    }
+
+    public int getBackgroundRequestResourceId() {
+        return backgroundRequestResourceId;
+    }
+
+    public int getBackgroundRequestDetailResourceId() {
+        return backgroundRequestDetailResourceId;
+    }
+
+    public int getRequestRes() {
+        return requestRes;
+    }
+
+    public int getPriority() {
+        return priority;
+    }
+}
diff --git a/core/java/android/content/pm/parsing/component/ParsedPermissionUtils.java b/core/java/android/content/pm/parsing/component/ParsedPermissionUtils.java
new file mode 100644
index 0000000..1884a1e
--- /dev/null
+++ b/core/java/android/content/pm/parsing/component/ParsedPermissionUtils.java
@@ -0,0 +1,210 @@
+/*
+ * 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.component;
+
+import android.annotation.NonNull;
+import android.content.pm.PermissionInfo;
+import android.content.pm.parsing.ParsingPackage;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
+import android.util.Slog;
+
+import com.android.internal.R;
+import android.content.pm.parsing.ParsingPackageUtils;
+import android.content.pm.parsing.result.ParseInput;
+import android.content.pm.parsing.result.ParseResult;
+
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+
+/** @hide */
+public class ParsedPermissionUtils {
+
+    private static final String TAG = ParsingPackageUtils.TAG;
+
+    @NonNull
+    public static ParseResult<ParsedPermission> parsePermission(ParsingPackage pkg, Resources res,
+            XmlResourceParser parser, boolean useRoundIcon, ParseInput input)
+            throws IOException, XmlPullParserException {
+        String packageName = pkg.getPackageName();
+        ParsedPermission
+                permission = new ParsedPermission();
+        String tag = "<" + parser.getName() + ">";
+        final ParseResult<ParsedPermission> result;
+
+        TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestPermission);
+        try {
+            result = ParsedComponentUtils.parseComponent(
+                    permission, tag, pkg, sa, useRoundIcon, input,
+                    R.styleable.AndroidManifestPermission_banner,
+                    R.styleable.AndroidManifestPermission_description,
+                    R.styleable.AndroidManifestPermission_icon,
+                    R.styleable.AndroidManifestPermission_label,
+                    R.styleable.AndroidManifestPermission_logo,
+                    R.styleable.AndroidManifestPermission_name,
+                    R.styleable.AndroidManifestPermission_roundIcon);
+            if (result.isError()) {
+                return result;
+            }
+
+            if (sa.hasValue(
+                    R.styleable.AndroidManifestPermission_backgroundPermission)) {
+                if ("android".equals(packageName)) {
+                    permission.backgroundPermission = sa.getNonResourceString(
+                            R.styleable
+                                    .AndroidManifestPermission_backgroundPermission);
+                } else {
+                    Slog.w(TAG, packageName + " defines a background permission. Only the "
+                            + "'android' package can do that.");
+                }
+            }
+
+            // Note: don't allow this value to be a reference to a resource
+            // that may change.
+            permission.setGroup(sa.getNonResourceString(
+                    R.styleable.AndroidManifestPermission_permissionGroup));
+
+            permission.requestRes = sa.getResourceId(
+                    R.styleable.AndroidManifestPermission_request, 0);
+
+            permission.protectionLevel = sa.getInt(
+                    R.styleable.AndroidManifestPermission_protectionLevel,
+                    PermissionInfo.PROTECTION_NORMAL);
+
+            permission.flags = sa.getInt(
+                    R.styleable.AndroidManifestPermission_permissionFlags, 0);
+
+            // For now only platform runtime permissions can be restricted
+            if (!permission.isRuntime() || !"android".equals(permission.getPackageName())) {
+                permission.flags &= ~PermissionInfo.FLAG_HARD_RESTRICTED;
+                permission.flags &= ~PermissionInfo.FLAG_SOFT_RESTRICTED;
+            } else {
+                // The platform does not get to specify conflicting permissions
+                if ((permission.flags & PermissionInfo.FLAG_HARD_RESTRICTED) != 0
+                        && (permission.flags & PermissionInfo.FLAG_SOFT_RESTRICTED) != 0) {
+                    throw new IllegalStateException("Permission cannot be both soft and hard"
+                            + " restricted: " + permission.getName());
+                }
+            }
+        } finally {
+            sa.recycle();
+        }
+
+        // TODO(b/135203078): This is impossible because of default value in above getInt
+        if (permission.protectionLevel == -1) {
+            return input.error("<permission> does not specify protectionLevel");
+        }
+
+        permission.protectionLevel = PermissionInfo.fixProtectionLevel(permission.protectionLevel);
+
+        if (permission.getProtectionFlags() != 0) {
+            if ((permission.protectionLevel & PermissionInfo.PROTECTION_FLAG_INSTANT) == 0
+                    && (permission.protectionLevel & PermissionInfo.PROTECTION_FLAG_RUNTIME_ONLY)
+                    == 0
+                    && (permission.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE) !=
+                    PermissionInfo.PROTECTION_SIGNATURE) {
+                return input.error("<permission>  protectionLevel specifies a non-instant flag "
+                        + "but is not based on signature type");
+            }
+        }
+
+        return ComponentParseUtils.parseAllMetaData(pkg, res, parser, tag, permission, input);
+    }
+
+    @NonNull
+    public static ParseResult<ParsedPermission> parsePermissionTree(ParsingPackage pkg, Resources res,
+            XmlResourceParser parser, boolean useRoundIcon, ParseInput input)
+            throws IOException, XmlPullParserException {
+        ParsedPermission permission = new ParsedPermission();
+        String tag = "<" + parser.getName() + ">";
+        final ParseResult<ParsedPermission> result;
+
+        TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestPermissionTree);
+        try {
+            result = ParsedComponentUtils.parseComponent(
+                    permission, tag, pkg, sa, useRoundIcon, input,
+                    R.styleable.AndroidManifestPermissionTree_banner,
+                    null /*descriptionAttr*/,
+                    R.styleable.AndroidManifestPermissionTree_icon,
+                    R.styleable.AndroidManifestPermissionTree_label,
+                    R.styleable.AndroidManifestPermissionTree_logo,
+                    R.styleable.AndroidManifestPermissionTree_name,
+                    R.styleable.AndroidManifestPermissionTree_roundIcon);
+            if (result.isError()) {
+                return result;
+            }
+        } finally {
+            sa.recycle();
+        }
+
+        int index = permission.getName().indexOf('.');
+        if (index > 0) {
+            index = permission.getName().indexOf('.', index + 1);
+        }
+        if (index < 0) {
+            return input.error("<permission-tree> name has less than three segments: "
+                    + permission.getName());
+        }
+
+        permission.protectionLevel = PermissionInfo.PROTECTION_NORMAL;
+        permission.tree = true;
+
+        return ComponentParseUtils.parseAllMetaData(pkg, res, parser, tag, permission,
+                input);
+    }
+
+    @NonNull
+    public static ParseResult<ParsedPermissionGroup> parsePermissionGroup(ParsingPackage pkg,
+            Resources res, XmlResourceParser parser, boolean useRoundIcon, ParseInput input)
+            throws IOException, XmlPullParserException {
+        ParsedPermissionGroup
+                permissionGroup = new ParsedPermissionGroup();
+        String tag = "<" + parser.getName() + ">";
+
+        TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestPermissionGroup);
+        try {
+            ParseResult<ParsedPermissionGroup> result = ParsedComponentUtils.parseComponent(
+                    permissionGroup, tag, pkg, sa, useRoundIcon, input,
+                    R.styleable.AndroidManifestPermissionGroup_banner,
+                    R.styleable.AndroidManifestPermissionGroup_description,
+                    R.styleable.AndroidManifestPermissionGroup_icon,
+                    R.styleable.AndroidManifestPermissionGroup_label,
+                    R.styleable.AndroidManifestPermissionGroup_logo,
+                    R.styleable.AndroidManifestPermissionGroup_name,
+                    R.styleable.AndroidManifestPermissionGroup_roundIcon);
+            if (result.isError()) {
+                return result;
+            }
+
+            // @formatter:off
+            permissionGroup.requestDetailResourceId = sa.getResourceId(R.styleable.AndroidManifestPermissionGroup_requestDetail, 0);
+            permissionGroup.backgroundRequestResourceId = sa.getResourceId(R.styleable.AndroidManifestPermissionGroup_backgroundRequest, 0);
+            permissionGroup.backgroundRequestDetailResourceId = sa.getResourceId(R.styleable.AndroidManifestPermissionGroup_backgroundRequestDetail, 0);
+            permissionGroup.requestRes = sa.getResourceId(R.styleable.AndroidManifestPermissionGroup_request, 0);
+            permissionGroup.flags = sa.getInt(R.styleable.AndroidManifestPermissionGroup_permissionGroupFlags,0);
+            permissionGroup.priority = sa.getInt(R.styleable.AndroidManifestPermissionGroup_priority, 0);
+            // @formatter:on
+        } finally {
+            sa.recycle();
+        }
+
+        return ComponentParseUtils.parseAllMetaData(pkg, res, parser, tag, permissionGroup,
+                input);
+    }
+}
diff --git a/core/java/android/content/pm/parsing/component/ParsedProcess.java b/core/java/android/content/pm/parsing/component/ParsedProcess.java
new file mode 100644
index 0000000..da7bf98
--- /dev/null
+++ b/core/java/android/content/pm/parsing/component/ParsedProcess.java
@@ -0,0 +1,166 @@
+/*
+ * 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.component;
+
+import static java.util.Collections.emptySet;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.ArraySet;
+
+import com.android.internal.util.CollectionUtils;
+import com.android.internal.util.DataClass;
+import com.android.internal.util.Parcelling;
+
+import java.util.Set;
+
+/** @hide */
+@DataClass(genGetters = true, genSetters = false, genParcelable = true, genAidl = false,
+        genBuilder = false)
+public class ParsedProcess implements Parcelable {
+
+    @NonNull
+    protected String name;
+    @NonNull
+    @DataClass.ParcelWith(Parcelling.BuiltIn.ForInternedStringSet.class)
+    protected Set<String> deniedPermissions = emptySet();
+
+    public ParsedProcess() {
+    }
+
+    public ParsedProcess(@NonNull ParsedProcess other) {
+        name = other.name;
+        deniedPermissions = new ArraySet<>(other.deniedPermissions);
+    }
+
+    public void addStateFrom(@NonNull ParsedProcess other) {
+        deniedPermissions = CollectionUtils.addAll(deniedPermissions, other.deniedPermissions);
+    }
+
+
+
+    // Code below generated by codegen v1.0.14.
+    //
+    // DO NOT MODIFY!
+    // CHECKSTYLE:OFF Generated code
+    //
+    // To regenerate run:
+    // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/parsing/component/ParsedProcess.java
+    //
+    // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+    //   Settings > Editor > Code Style > Formatter Control
+    //@formatter:off
+
+
+    @DataClass.Generated.Member
+    public ParsedProcess(
+            @NonNull String name,
+            @NonNull Set<String> deniedPermissions) {
+        this.name = name;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, name);
+        this.deniedPermissions = deniedPermissions;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, deniedPermissions);
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    @DataClass.Generated.Member
+    public @NonNull String getName() {
+        return name;
+    }
+
+    @DataClass.Generated.Member
+    public @NonNull Set<String> getDeniedPermissions() {
+        return deniedPermissions;
+    }
+
+    @DataClass.Generated.Member
+    static Parcelling<Set<String>> sParcellingForDeniedPermissions =
+            Parcelling.Cache.get(
+                    Parcelling.BuiltIn.ForInternedStringSet.class);
+    static {
+        if (sParcellingForDeniedPermissions == null) {
+            sParcellingForDeniedPermissions = Parcelling.Cache.put(
+                    new Parcelling.BuiltIn.ForInternedStringSet());
+        }
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        // You can override field parcelling by defining methods like:
+        // void parcelFieldName(Parcel dest, int flags) { ... }
+
+        dest.writeString(name);
+        sParcellingForDeniedPermissions.parcel(deniedPermissions, dest, flags);
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public int describeContents() { return 0; }
+
+    /** @hide */
+    @SuppressWarnings({"unchecked", "RedundantCast"})
+    @DataClass.Generated.Member
+    protected ParsedProcess(@NonNull Parcel in) {
+        // You can override field unparcelling by defining methods like:
+        // static FieldType unparcelFieldName(Parcel in) { ... }
+
+        String _name = in.readString();
+        Set<String> _deniedPermissions = sParcellingForDeniedPermissions.unparcel(in);
+
+        this.name = _name;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, name);
+        this.deniedPermissions = _deniedPermissions;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, deniedPermissions);
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    @DataClass.Generated.Member
+    public static final @NonNull Parcelable.Creator<ParsedProcess> CREATOR
+            = new Parcelable.Creator<ParsedProcess>() {
+        @Override
+        public ParsedProcess[] newArray(int size) {
+            return new ParsedProcess[size];
+        }
+
+        @Override
+        public ParsedProcess createFromParcel(@NonNull Parcel in) {
+            return new ParsedProcess(in);
+        }
+    };
+
+    @DataClass.Generated(
+            time = 1581452315946L,
+            codegenVersion = "1.0.14",
+            sourceFile = "frameworks/base/core/java/android/content/pm/parsing/component/ParsedProcess.java",
+            inputSignatures = "protected @android.annotation.NonNull java.lang.String name\nprotected @android.annotation.NonNull @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedStringSet.class) java.util.Set<java.lang.String> deniedPermissions\npublic  void addStateFrom(android.content.pm.parsing.component.ParsedProcess)\nclass ParsedProcess extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=false, genParcelable=true, genAidl=false, genBuilder=false)")
+    @Deprecated
+    private void __metadata() {}
+
+
+    //@formatter:on
+    // End of generated code
+
+}
diff --git a/core/java/android/content/pm/parsing/component/ParsedProcessUtils.java b/core/java/android/content/pm/parsing/component/ParsedProcessUtils.java
new file mode 100644
index 0000000..4825066
--- /dev/null
+++ b/core/java/android/content/pm/parsing/component/ParsedProcessUtils.java
@@ -0,0 +1,212 @@
+/*
+ * 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.component;
+
+import android.annotation.NonNull;
+import android.content.pm.parsing.ParsingPackage;
+import android.content.pm.parsing.ParsingUtils;
+import android.content.pm.parsing.result.ParseInput;
+import android.content.pm.parsing.result.ParseResult;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+
+import com.android.internal.R;
+import com.android.internal.util.CollectionUtils;
+import com.android.internal.util.XmlUtils;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.util.Set;
+
+/** @hide */
+public class ParsedProcessUtils {
+
+    private static final String TAG = ParsingUtils.TAG;
+
+    @NonNull
+    private static ParseResult<Set<String>> parseDenyPermission(Set<String> perms,
+            Resources res, XmlResourceParser parser, ParseInput input)
+            throws IOException, XmlPullParserException {
+        TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestDenyPermission);
+        try {
+            String perm = sa.getNonConfigurationString(
+                    R.styleable.AndroidManifestDenyPermission_name, 0);
+            if (perm != null && perm.equals(android.Manifest.permission.INTERNET)) {
+                perms = CollectionUtils.add(perms, perm);
+            }
+        } finally {
+            sa.recycle();
+        }
+        XmlUtils.skipCurrentTag(parser);
+        return input.success(perms);
+    }
+
+    @NonNull
+    private static ParseResult<Set<String>> parseAllowPermission(Set<String> perms, Resources res,
+            XmlResourceParser parser, ParseInput input)
+            throws IOException, XmlPullParserException {
+        TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestAllowPermission);
+        try {
+            String perm = sa.getNonConfigurationString(
+                    R.styleable.AndroidManifestAllowPermission_name, 0);
+            if (perm != null && perm.equals(android.Manifest.permission.INTERNET)) {
+                perms = CollectionUtils.remove(perms, perm);
+            }
+        } finally {
+            sa.recycle();
+        }
+        XmlUtils.skipCurrentTag(parser);
+        return input.success(perms);
+    }
+
+    @NonNull
+    private static ParseResult<ParsedProcess> parseProcess(Set<String> perms, String[] separateProcesses,
+            ParsingPackage pkg, Resources res, XmlResourceParser parser, int flags,
+            ParseInput input) throws IOException, XmlPullParserException {
+        ParsedProcess proc = new ParsedProcess();
+        TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestProcess);
+        try {
+            if (perms != null) {
+                proc.deniedPermissions = new ArraySet<>(perms);
+            }
+
+            proc.name = sa.getNonConfigurationString(
+                    R.styleable.AndroidManifestProcess_process, 0);
+            ParseResult<String> processNameResult = ComponentParseUtils.buildProcessName(
+                    pkg.getPackageName(), pkg.getPackageName(), proc.name, flags, separateProcesses,
+                    input);
+            if (processNameResult.isError()) {
+                return input.error(processNameResult);
+            }
+
+            proc.name = processNameResult.getResult();
+
+            if (proc.name == null || proc.name.length() <= 0) {
+                return input.error("<process> does not specify android:process");
+            }
+        } finally {
+            sa.recycle();
+        }
+
+        int type;
+        final int innerDepth = parser.getDepth();
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
+            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                continue;
+            }
+
+            ParseResult<?> result;
+
+            String tagName = parser.getName();
+            switch (tagName) {
+                case "deny-permission":
+                    ParseResult<Set<String>> denyResult = parseDenyPermission(
+                            proc.deniedPermissions, res, parser, input);
+                    result = denyResult;
+                    if (denyResult.isSuccess()) {
+                        proc.deniedPermissions = denyResult.getResult();
+                    }
+                    break;
+                case "allow-permission":
+                    ParseResult<Set<String>> allowResult = parseAllowPermission(
+                            proc.deniedPermissions, res, parser, input);
+                    result = allowResult;
+                    if (allowResult.isSuccess()) {
+                        proc.deniedPermissions = allowResult.getResult();
+                    }
+                    break;
+                default:
+                    result = ParsingUtils.unknownTag("<process>", pkg, parser, input);
+                    break;
+            }
+
+            if (result.isError()) {
+                return input.error(result);
+            }
+        }
+
+        return input.success(proc);
+    }
+
+    @NonNull
+    public static ParseResult<ArrayMap<String, ParsedProcess>> parseProcesses(
+            String[] separateProcesses, ParsingPackage pkg, Resources res,
+            XmlResourceParser parser, int flags, ParseInput input)
+            throws IOException, XmlPullParserException {
+        Set<String> deniedPerms = null;
+        ArrayMap<String, ParsedProcess> processes = new ArrayMap<>();
+
+        int type;
+        final int innerDepth = parser.getDepth();
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
+            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                continue;
+            }
+
+            ParseResult<?> result;
+
+            String tagName = parser.getName();
+            switch (tagName) {
+                case "deny-permission":
+                    ParseResult<Set<String>> denyResult = parseDenyPermission(deniedPerms, res,
+                            parser, input);
+                    result = denyResult;
+                    if (denyResult.isSuccess()) {
+                        deniedPerms = denyResult.getResult();
+                    }
+                    break;
+                case "allow-permission":
+                    ParseResult<Set<String>> allowResult = parseAllowPermission(deniedPerms, res,
+                            parser, input);
+                    result = allowResult;
+                    if (allowResult.isSuccess()) {
+                        deniedPerms = allowResult.getResult();
+                    }
+                    break;
+                case "process":
+                    ParseResult<ParsedProcess> processResult = parseProcess(deniedPerms,
+                            separateProcesses, pkg, res, parser, flags, input);
+                    result = processResult;
+                    if (processResult.isSuccess()) {
+                        ParsedProcess process = processResult.getResult();
+                        if (processes.put(process.name, process) != null) {
+                            result = input.error(
+                                    "<process> specified existing name '" + process.name + "'");
+                        }
+                    }
+                    break;
+                default:
+                    result = ParsingUtils.unknownTag("<processes>", pkg, parser, input);
+                    break;
+            }
+
+            if (result.isError()) {
+                return input.error(result);
+            }
+
+        }
+
+        return input.success(processes);
+    }
+}
diff --git a/core/java/android/content/pm/parsing/component/ParsedProvider.java b/core/java/android/content/pm/parsing/component/ParsedProvider.java
new file mode 100644
index 0000000..d2c531d
--- /dev/null
+++ b/core/java/android/content/pm/parsing/component/ParsedProvider.java
@@ -0,0 +1,195 @@
+/*
+ * 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.component;
+
+import static android.content.pm.parsing.ParsingPackageImpl.sForString;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.content.pm.PathPermission;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.PatternMatcher;
+import android.text.TextUtils;
+
+import com.android.internal.util.DataClass;
+import com.android.internal.util.Parcelling;
+import com.android.internal.util.Parcelling.BuiltIn.ForInternedString;
+
+/** @hide **/
+public class ParsedProvider extends ParsedMainComponent {
+
+    @NonNull
+    @DataClass.ParcelWith(ForInternedString.class)
+    private String authority;
+    boolean syncable;
+    @Nullable
+    @DataClass.ParcelWith(ForInternedString.class)
+    private String readPermission;
+    @Nullable
+    @DataClass.ParcelWith(ForInternedString.class)
+    private String writePermission;
+    boolean grantUriPermissions;
+    boolean forceUriPermissions;
+    boolean multiProcess;
+    int initOrder;
+    @Nullable
+    PatternMatcher[] uriPermissionPatterns;
+    @Nullable
+    PathPermission[] pathPermissions;
+
+    public ParsedProvider(ParsedProvider other) {
+        super(other);
+
+        this.authority = other.authority;
+        this.syncable = other.syncable;
+        this.readPermission = other.readPermission;
+        this.writePermission = other.writePermission;
+        this.grantUriPermissions = other.grantUriPermissions;
+        this.forceUriPermissions = other.forceUriPermissions;
+        this.multiProcess = other.multiProcess;
+        this.initOrder = other.initOrder;
+        this.uriPermissionPatterns = other.uriPermissionPatterns;
+        this.pathPermissions = other.pathPermissions;
+    }
+
+    public void setAuthority(String authority) {
+        this.authority = TextUtils.safeIntern(authority);
+    }
+
+    public void setSyncable(boolean syncable) {
+        this.syncable = syncable;
+    }
+
+    public void setReadPermission(String readPermission) {
+        // Empty string must be converted to null
+        this.readPermission = TextUtils.isEmpty(readPermission)
+                ? null : readPermission.intern();
+    }
+
+    public void setWritePermission(String writePermission) {
+        // Empty string must be converted to null
+        this.writePermission = TextUtils.isEmpty(writePermission)
+                ? null : writePermission.intern();
+    }
+
+    public String toString() {
+        StringBuilder sb = new StringBuilder(128);
+        sb.append("Provider{");
+        sb.append(Integer.toHexString(System.identityHashCode(this)));
+        sb.append(' ');
+        ComponentName.appendShortString(sb, getPackageName(), getName());
+        sb.append('}');
+        return sb.toString();
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        super.writeToParcel(dest, flags);
+        sForString.parcel(this.authority, dest, flags);
+        dest.writeBoolean(this.syncable);
+        sForString.parcel(this.readPermission, dest, flags);
+        sForString.parcel(this.writePermission, dest, flags);
+        dest.writeBoolean(this.grantUriPermissions);
+        dest.writeBoolean(this.forceUriPermissions);
+        dest.writeBoolean(this.multiProcess);
+        dest.writeInt(this.initOrder);
+        dest.writeTypedArray(this.uriPermissionPatterns, flags);
+        dest.writeTypedArray(this.pathPermissions, flags);
+    }
+
+    public ParsedProvider() {
+    }
+
+    protected ParsedProvider(Parcel in) {
+        super(in);
+        //noinspection ConstantConditions
+        this.authority = sForString.unparcel(in);
+        this.syncable = in.readBoolean();
+        this.readPermission = sForString.unparcel(in);
+        this.writePermission = sForString.unparcel(in);
+        this.grantUriPermissions = in.readBoolean();
+        this.forceUriPermissions = in.readBoolean();
+        this.multiProcess = in.readBoolean();
+        this.initOrder = in.readInt();
+        this.uriPermissionPatterns = in.createTypedArray(PatternMatcher.CREATOR);
+        this.pathPermissions = in.createTypedArray(PathPermission.CREATOR);
+    }
+
+    public static final Parcelable.Creator<ParsedProvider> CREATOR = new Creator<ParsedProvider>() {
+        @Override
+        public ParsedProvider createFromParcel(Parcel source) {
+            return new ParsedProvider(source);
+        }
+
+        @Override
+        public ParsedProvider[] newArray(int size) {
+            return new ParsedProvider[size];
+        }
+    };
+
+    @NonNull
+    public String getAuthority() {
+        return authority;
+    }
+
+    public boolean isSyncable() {
+        return syncable;
+    }
+
+    @Nullable
+    public String getReadPermission() {
+        return readPermission;
+    }
+
+    @Nullable
+    public String getWritePermission() {
+        return writePermission;
+    }
+
+    public boolean isGrantUriPermissions() {
+        return grantUriPermissions;
+    }
+
+    public boolean isForceUriPermissions() {
+        return forceUriPermissions;
+    }
+
+    public boolean isMultiProcess() {
+        return multiProcess;
+    }
+
+    public int getInitOrder() {
+        return initOrder;
+    }
+
+    @Nullable
+    public PatternMatcher[] getUriPermissionPatterns() {
+        return uriPermissionPatterns;
+    }
+
+    @Nullable
+    public PathPermission[] getPathPermissions() {
+        return pathPermissions;
+    }
+}
diff --git a/core/java/android/content/pm/parsing/component/ParsedProviderUtils.java b/core/java/android/content/pm/parsing/component/ParsedProviderUtils.java
new file mode 100644
index 0000000..aa5ea8d
--- /dev/null
+++ b/core/java/android/content/pm/parsing/component/ParsedProviderUtils.java
@@ -0,0 +1,355 @@
+/*
+ * 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.component;
+
+import static android.content.pm.parsing.component.ComponentParseUtils.flag;
+
+import android.annotation.NonNull;
+import android.content.pm.PackageParser;
+import android.content.pm.PathPermission;
+import android.content.pm.ProviderInfo;
+import android.content.pm.parsing.ParsingPackage;
+import android.content.pm.parsing.ParsingPackageUtils;
+import android.content.pm.parsing.ParsingUtils;
+import android.content.pm.parsing.result.ParseInput;
+import android.content.pm.parsing.result.ParseResult;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
+import android.os.Build;
+import android.os.PatternMatcher;
+import android.util.Slog;
+
+import com.android.internal.R;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.util.Objects;
+
+/** @hide */
+public class ParsedProviderUtils {
+
+    private static final String TAG = ParsingPackageUtils.TAG;
+
+    @NonNull
+    public static ParseResult<ParsedProvider> parseProvider(String[] separateProcesses,
+            ParsingPackage pkg, Resources res, XmlResourceParser parser, int flags,
+            boolean useRoundIcon, ParseInput input)
+            throws IOException, XmlPullParserException {
+        String authority;
+        boolean visibleToEphemeral;
+
+        final int targetSdkVersion = pkg.getTargetSdkVersion();
+        final String packageName = pkg.getPackageName();
+        final ParsedProvider provider = new ParsedProvider();
+        final String tag = parser.getName();
+
+        TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestProvider);
+        try {
+            ParseResult<ParsedProvider> result =
+                    ParsedMainComponentUtils.parseMainComponent(provider, tag, separateProcesses,
+                    pkg, sa, flags, useRoundIcon, input,
+                    R.styleable.AndroidManifestProvider_banner,
+                    R.styleable.AndroidManifestProvider_description,
+                    R.styleable.AndroidManifestProvider_directBootAware,
+                    R.styleable.AndroidManifestProvider_enabled,
+                    R.styleable.AndroidManifestProvider_icon,
+                    R.styleable.AndroidManifestProvider_label,
+                    R.styleable.AndroidManifestProvider_logo,
+                    R.styleable.AndroidManifestProvider_name,
+                    R.styleable.AndroidManifestProvider_process,
+                    R.styleable.AndroidManifestProvider_roundIcon,
+                    R.styleable.AndroidManifestProvider_splitName);
+            if (result.isError()) {
+                return result;
+            }
+
+            authority = sa.getNonConfigurationString(R.styleable.AndroidManifestProvider_authorities, 0);
+
+            // For compatibility, applications targeting API level 16 or lower
+            // should have their content providers exported by default, unless they
+            // specify otherwise.
+            provider.exported = sa.getBoolean(R.styleable.AndroidManifestProvider_exported,
+                    targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR1);
+
+            provider.syncable = sa.getBoolean(R.styleable.AndroidManifestProvider_syncable, false);
+
+            String permission = sa.getNonConfigurationString(
+                    R.styleable.AndroidManifestProvider_permission, 0);
+            String readPermission = sa.getNonConfigurationString(
+                    R.styleable.AndroidManifestProvider_readPermission, 0);
+            if (readPermission == null) {
+                readPermission = permission;
+            }
+            if (readPermission == null) {
+                provider.setReadPermission(pkg.getPermission());
+            } else {
+                provider.setReadPermission(readPermission);
+            }
+            String writePermission = sa.getNonConfigurationString(
+                    R.styleable.AndroidManifestProvider_writePermission, 0);
+            if (writePermission == null) {
+                writePermission = permission;
+            }
+            if (writePermission == null) {
+                provider.setWritePermission(pkg.getPermission());
+            } else {
+                provider.setWritePermission(writePermission);
+            }
+
+            provider.grantUriPermissions = sa.getBoolean(R.styleable.AndroidManifestProvider_grantUriPermissions, false);
+            provider.forceUriPermissions = sa.getBoolean(R.styleable.AndroidManifestProvider_forceUriPermissions, false);
+            provider.multiProcess = sa.getBoolean(R.styleable.AndroidManifestProvider_multiprocess, false);
+            provider.initOrder = sa.getInt(R.styleable.AndroidManifestProvider_initOrder, 0);
+
+            provider.flags |= flag(ProviderInfo.FLAG_SINGLE_USER, R.styleable.AndroidManifestProvider_singleUser, sa);
+
+            visibleToEphemeral = sa.getBoolean(R.styleable.AndroidManifestProvider_visibleToInstantApps, false);
+            if (visibleToEphemeral) {
+                provider.flags |= ProviderInfo.FLAG_VISIBLE_TO_INSTANT_APP;
+                pkg.setVisibleToInstantApps(true);
+            }
+        } finally {
+            sa.recycle();
+        }
+
+        if (pkg.isCantSaveState()) {
+            // A heavy-weight application can not have providers in its main process
+            if (Objects.equals(provider.getProcessName(), packageName)) {
+                return input.error("Heavy-weight applications can not have providers"
+                        + " in main process");
+            }
+        }
+
+        if (authority == null) {
+            return input.error("<provider> does not include authorities attribute");
+        }
+        if (authority.length() <= 0) {
+            return input.error("<provider> has empty authorities attribute");
+        }
+        provider.setAuthority(authority);
+
+        return parseProviderTags(pkg, tag, res, parser, visibleToEphemeral, provider, input);
+    }
+
+    @NonNull
+    private static ParseResult<ParsedProvider> parseProviderTags(ParsingPackage pkg, String tag,
+            Resources res, XmlResourceParser parser, boolean visibleToEphemeral,
+            ParsedProvider provider, ParseInput input)
+            throws XmlPullParserException, IOException {
+        final int depth = parser.getDepth();
+        int type;
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG
+                || parser.getDepth() > depth)) {
+            if (type != XmlPullParser.START_TAG) {
+                continue;
+            }
+
+            String name = parser.getName();
+            final ParseResult result;
+            switch (name) {
+                case "intent-filter":
+                    ParseResult<ParsedIntentInfo> intentResult = ParsedMainComponentUtils
+                            .parseIntentFilter(provider, pkg, res, parser, visibleToEphemeral,
+                                    true /*allowGlobs*/, false /*allowAutoVerify*/,
+                                    false /*allowImplicitEphemeralVisibility*/,
+                                    false /*failOnNoActions*/, input);
+                    result = intentResult;
+                    if (intentResult.isSuccess()) {
+                        ParsedIntentInfo intent = intentResult.getResult();
+                        provider.order = Math.max(intent.getOrder(), provider.order);
+                        provider.addIntent(intent);
+                    }
+                    break;
+                case "meta-data":
+                    result = ParsedComponentUtils.addMetaData(provider, pkg, res, parser, input);
+                    break;
+                case "grant-uri-permission": {
+                    result = parseGrantUriPermission(provider, pkg, res, parser, input);
+                    break;
+                }
+                case "path-permission": {
+                    result = parsePathPermission(provider, pkg, res, parser, input);
+                    break;
+                }
+                default:
+                    result = ParsingUtils.unknownTag(tag, pkg, parser, input);
+                    break;
+            }
+
+            if (result.isError()) {
+                return input.error(result);
+            }
+        }
+
+        return input.success(provider);
+    }
+
+    @NonNull
+    private static ParseResult<ParsedProvider> parseGrantUriPermission(ParsedProvider provider,
+            ParsingPackage pkg, Resources resources, XmlResourceParser parser, ParseInput input) {
+        TypedArray sa = resources.obtainAttributes(parser,
+                R.styleable.AndroidManifestGrantUriPermission);
+        try {
+            String name = parser.getName();
+            // Pattern has priority over prefix over literal path
+            PatternMatcher pa = null;
+            String str = sa.getNonConfigurationString(
+                    R.styleable.AndroidManifestGrantUriPermission_pathPattern, 0);
+            if (str != null) {
+                pa = new PatternMatcher(str, PatternMatcher.PATTERN_SIMPLE_GLOB);
+            } else {
+                str = sa.getNonConfigurationString(
+                        R.styleable.AndroidManifestGrantUriPermission_pathPrefix, 0);
+                if (str != null) {
+                    pa = new PatternMatcher(str, PatternMatcher.PATTERN_PREFIX);
+                } else {
+                    str = sa.getNonConfigurationString(
+                            R.styleable.AndroidManifestGrantUriPermission_path, 0);
+                    if (str != null) {
+                        pa = new PatternMatcher(str, PatternMatcher.PATTERN_LITERAL);
+                    }
+                }
+            }
+
+            if (pa != null) {
+                if (provider.uriPermissionPatterns == null) {
+                    provider.uriPermissionPatterns = new PatternMatcher[1];
+                    provider.uriPermissionPatterns[0] = pa;
+                } else {
+                    final int N = provider.uriPermissionPatterns.length;
+                    PatternMatcher[] newp = new PatternMatcher[N + 1];
+                    System.arraycopy(provider.uriPermissionPatterns, 0, newp, 0, N);
+                    newp[N] = pa;
+                    provider.uriPermissionPatterns = newp;
+                }
+                provider.grantUriPermissions = true;
+            } else {
+                if (PackageParser.RIGID_PARSER) {
+                    return input.error("No path, pathPrefix, or pathPattern for <path-permission>");
+                }
+
+                Slog.w(TAG, "Unknown element under <path-permission>: " + name + " at "
+                        + pkg.getBaseCodePath() + " " + parser.getPositionDescription());
+            }
+
+            return input.success(provider);
+        } finally {
+            sa.recycle();
+        }
+    }
+
+    @NonNull
+    private static ParseResult<ParsedProvider> parsePathPermission(ParsedProvider provider,
+            ParsingPackage pkg, Resources resources, XmlResourceParser parser, ParseInput input) {
+        TypedArray sa = resources.obtainAttributes(parser,
+                R.styleable.AndroidManifestPathPermission);
+        try {
+            String name = parser.getName();
+
+            String permission = sa.getNonConfigurationString(
+                    R.styleable.AndroidManifestPathPermission_permission, 0);
+            String readPermission = sa.getNonConfigurationString(
+                    R.styleable.AndroidManifestPathPermission_readPermission, 0);
+            if (readPermission == null) {
+                readPermission = permission;
+            }
+            String writePermission = sa.getNonConfigurationString(
+                    R.styleable.AndroidManifestPathPermission_writePermission, 0);
+            if (writePermission == null) {
+                writePermission = permission;
+            }
+
+            boolean havePerm = false;
+            if (readPermission != null) {
+                readPermission = readPermission.intern();
+                havePerm = true;
+            }
+            if (writePermission != null) {
+                writePermission = writePermission.intern();
+                havePerm = true;
+            }
+
+            if (!havePerm) {
+                if (PackageParser.RIGID_PARSER) {
+                    return input.error(
+                            "No readPermission or writePermission for <path-permission>");
+                }
+                Slog.w(TAG, "No readPermission or writePermission for <path-permission>: "
+                        + name + " at " + pkg.getBaseCodePath() + " " + parser.getPositionDescription());
+                return input.success(provider);
+            }
+
+            // Advanced has priority over simply over prefix over literal
+            PathPermission pa = null;
+            String path = sa.getNonConfigurationString(R.styleable.AndroidManifestPathPermission_pathAdvancedPattern, 0);
+            if (path != null) {
+                pa = new PathPermission(path, PatternMatcher.PATTERN_ADVANCED_GLOB, readPermission,
+                        writePermission);
+            } else {
+                path = sa.getNonConfigurationString(R.styleable.AndroidManifestPathPermission_pathPattern, 0);
+                if (path != null) {
+                    pa = new PathPermission(path, PatternMatcher.PATTERN_SIMPLE_GLOB,
+                            readPermission, writePermission);
+                } else {
+                    path = sa.getNonConfigurationString(
+                            R.styleable.AndroidManifestPathPermission_pathPrefix, 0);
+                    if (path != null) {
+                        pa = new PathPermission(path, PatternMatcher.PATTERN_PREFIX, readPermission,
+                                writePermission);
+                    } else {
+                        path = sa.getNonConfigurationString(R.styleable.AndroidManifestPathPermission_path, 0);
+                        if (path != null) {
+                            pa = new PathPermission(path, PatternMatcher.PATTERN_LITERAL,
+                                    readPermission, writePermission);
+                        }
+                    }
+                }
+            }
+
+            if (pa != null) {
+                if (provider.pathPermissions == null) {
+                    provider.pathPermissions = new PathPermission[1];
+                    provider.pathPermissions[0] = pa;
+                } else {
+                    final int N = provider.pathPermissions.length;
+                    PathPermission[] newp = new PathPermission[N + 1];
+                    System.arraycopy(provider.pathPermissions, 0, newp, 0, N);
+                    newp[N] = pa;
+                    provider.pathPermissions = newp;
+                }
+            } else {
+                if (PackageParser.RIGID_PARSER) {
+                    return input.error(
+                            "No path, pathPrefix, or pathPattern for <path-permission>");
+                }
+
+                Slog.w(TAG, "No path, pathPrefix, or pathPattern for <path-permission>: "
+                        + name + " at " + pkg.getBaseCodePath()
+                        + " "
+                        + parser.getPositionDescription());
+            }
+
+            return input.success(provider);
+        } finally {
+            sa.recycle();
+        }
+    }
+}
diff --git a/core/java/android/content/pm/parsing/component/ParsedService.java b/core/java/android/content/pm/parsing/component/ParsedService.java
new file mode 100644
index 0000000..591eef7
--- /dev/null
+++ b/core/java/android/content/pm/parsing/component/ParsedService.java
@@ -0,0 +1,102 @@
+/*
+ * 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.component;
+
+import static android.content.pm.parsing.ParsingPackageImpl.sForString;
+
+import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
+
+import com.android.internal.util.DataClass;
+import com.android.internal.util.Parcelling;
+import com.android.internal.util.Parcelling.BuiltIn.ForInternedString;
+
+/** @hide **/
+public class ParsedService extends ParsedMainComponent {
+
+    int foregroundServiceType;
+    @Nullable
+    @DataClass.ParcelWith(ForInternedString.class)
+    private String permission;
+
+    public ParsedService(ParsedService other) {
+        super(other);
+        this.foregroundServiceType = other.foregroundServiceType;
+        this.permission = other.permission;
+    }
+
+    public ParsedMainComponent setPermission(String permission) {
+        // Empty string must be converted to null
+        this.permission = TextUtils.isEmpty(permission) ? null : permission.intern();
+        return this;
+    }
+
+    public String toString() {
+        StringBuilder sb = new StringBuilder(128);
+        sb.append("Service{");
+        sb.append(Integer.toHexString(System.identityHashCode(this)));
+        sb.append(' ');
+        ComponentName.appendShortString(sb, getPackageName(), getName());
+        sb.append('}');
+        return sb.toString();
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        super.writeToParcel(dest, flags);
+        dest.writeInt(this.foregroundServiceType);
+        sForString.parcel(this.permission, dest, flags);
+    }
+
+    public ParsedService() {
+    }
+
+    protected ParsedService(Parcel in) {
+        super(in);
+        this.foregroundServiceType = in.readInt();
+        this.permission = sForString.unparcel(in);
+    }
+
+    public static final Parcelable.Creator<ParsedService> CREATOR = new Creator<ParsedService>() {
+        @Override
+        public ParsedService createFromParcel(Parcel source) {
+            return new ParsedService(source);
+        }
+
+        @Override
+        public ParsedService[] newArray(int size) {
+            return new ParsedService[size];
+        }
+    };
+
+    public int getForegroundServiceType() {
+        return foregroundServiceType;
+    }
+
+    @Nullable
+    public String getPermission() {
+        return permission;
+    }
+}
diff --git a/core/java/android/content/pm/parsing/component/ParsedServiceUtils.java b/core/java/android/content/pm/parsing/component/ParsedServiceUtils.java
new file mode 100644
index 0000000..8a8a066
--- /dev/null
+++ b/core/java/android/content/pm/parsing/component/ParsedServiceUtils.java
@@ -0,0 +1,165 @@
+/*
+ * 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.component;
+
+import static android.content.pm.parsing.component.ComponentParseUtils.flag;
+
+import android.annotation.NonNull;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ServiceInfo;
+import android.content.pm.parsing.ParsingPackage;
+import android.content.pm.parsing.ParsingPackageUtils;
+import android.content.pm.parsing.ParsingUtils;
+import android.content.pm.parsing.result.ParseInput;
+import android.content.pm.parsing.result.ParseResult;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
+
+import com.android.internal.R;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.util.Objects;
+
+/** @hide */
+public class ParsedServiceUtils {
+
+    private static final String TAG = ParsingPackageUtils.TAG;
+
+    @NonNull
+    public static ParseResult<ParsedService> parseService(String[] separateProcesses,
+            ParsingPackage pkg, Resources res, XmlResourceParser parser, int flags,
+            boolean useRoundIcon, ParseInput input)
+            throws XmlPullParserException, IOException {
+        boolean visibleToEphemeral;
+        boolean setExported;
+
+        final String packageName = pkg.getPackageName();
+        final ParsedService service = new ParsedService();
+        String tag = parser.getName();
+
+        TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestService);
+        try {
+            ParseResult<ParsedService> result = ParsedMainComponentUtils.parseMainComponent(
+                    service, tag, separateProcesses, pkg, sa, flags, useRoundIcon, input,
+                    R.styleable.AndroidManifestService_banner,
+                    R.styleable.AndroidManifestService_description,
+                    R.styleable.AndroidManifestService_directBootAware,
+                    R.styleable.AndroidManifestService_enabled,
+                    R.styleable.AndroidManifestService_icon,
+                    R.styleable.AndroidManifestService_label,
+                    R.styleable.AndroidManifestService_logo,
+                    R.styleable.AndroidManifestService_name,
+                    R.styleable.AndroidManifestService_process,
+                    R.styleable.AndroidManifestService_roundIcon,
+                    R.styleable.AndroidManifestService_splitName
+            );
+
+            if (result.isError()) {
+                return result;
+            }
+
+            setExported = sa.hasValue(R.styleable.AndroidManifestService_exported);
+            if (setExported) {
+                service.exported = sa.getBoolean(R.styleable.AndroidManifestService_exported,
+                        false);
+            }
+
+            String permission = sa.getNonConfigurationString(
+                    R.styleable.AndroidManifestService_permission, 0);
+            service.setPermission(permission != null ? permission : pkg.getPermission());
+
+            service.foregroundServiceType = sa.getInt(
+                    R.styleable.AndroidManifestService_foregroundServiceType,
+                    ServiceInfo.FOREGROUND_SERVICE_TYPE_NONE);
+
+            service.flags |= flag(ServiceInfo.FLAG_STOP_WITH_TASK,
+                    R.styleable.AndroidManifestService_stopWithTask, sa)
+                    | flag(ServiceInfo.FLAG_ISOLATED_PROCESS,
+                    R.styleable.AndroidManifestService_isolatedProcess, sa)
+                    | flag(ServiceInfo.FLAG_EXTERNAL_SERVICE,
+                    R.styleable.AndroidManifestService_externalService, sa)
+                    | flag(ServiceInfo.FLAG_USE_APP_ZYGOTE,
+                    R.styleable.AndroidManifestService_useAppZygote, sa)
+                    | flag(ServiceInfo.FLAG_SINGLE_USER,
+                    R.styleable.AndroidManifestService_singleUser, sa);
+
+            visibleToEphemeral = sa.getBoolean(
+                    R.styleable.AndroidManifestService_visibleToInstantApps, false);
+            if (visibleToEphemeral) {
+                service.flags |= ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP;
+                pkg.setVisibleToInstantApps(true);
+            }
+        } finally {
+            sa.recycle();
+        }
+
+        if (pkg.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(service.getProcessName(), packageName)) {
+                return input.error("Heavy-weight applications can not have services "
+                        + "in main process");
+            }
+        }
+        final int depth = parser.getDepth();
+        int type;
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG
+                || parser.getDepth() > depth)) {
+            if (type != XmlPullParser.START_TAG) {
+                continue;
+            }
+
+            final ParseResult parseResult;
+            switch (parser.getName()) {
+                case "intent-filter":
+                    ParseResult<ParsedIntentInfo> intentResult = ParsedMainComponentUtils
+                            .parseIntentFilter(service, pkg, res, parser, visibleToEphemeral,
+                                    true /*allowGlobs*/, false /*allowAutoVerify*/,
+                                    false /*allowImplicitEphemeralVisibility*/,
+                                    false /*failOnNoActions*/, input);
+                    parseResult = intentResult;
+                    if (intentResult.isSuccess()) {
+                        ParsedIntentInfo intent = intentResult.getResult();
+                        service.order = Math.max(intent.getOrder(), service.order);
+                        service.addIntent(intent);
+                    }
+                    break;
+                case "meta-data":
+                    parseResult = ParsedComponentUtils.addMetaData(service, pkg, res, parser, input);
+                    break;
+                default:
+                    parseResult = ParsingUtils.unknownTag(tag, pkg, parser, input);
+                    break;
+            }
+
+            if (parseResult.isError()) {
+                return input.error(parseResult);
+            }
+        }
+
+        if (!setExported) {
+            service.exported = service.getIntents().size() > 0;
+        }
+
+        return input.success(service);
+    }
+}
diff --git a/core/java/android/content/pm/parsing/result/ParseInput.java b/core/java/android/content/pm/parsing/result/ParseInput.java
new file mode 100644
index 0000000..c468506
--- /dev/null
+++ b/core/java/android/content/pm/parsing/result/ParseInput.java
@@ -0,0 +1,70 @@
+/*
+ * 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.result;
+
+import android.annotation.Hide;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.pm.PackageManager;
+
+/**
+ * Used as a method parameter which is then transformed into a {@link ParseResult}. This is
+ * generalized as it doesn't matter what type this input is for. It's simply to hide the
+ * methods of {@link ParseResult}.
+ *
+ * @hide
+ */
+public interface ParseInput {
+
+    <ResultType> ParseResult<ResultType> success(ResultType result);
+
+    /** @see #error(int, String, Exception) */
+    <ResultType> ParseResult<ResultType> error(int parseError);
+
+    /**
+     * This will assign errorCode to {@link PackageManager#INSTALL_PARSE_FAILED_MANIFEST_MALFORMED}.
+     * @see #error(int, String, Exception)
+     */
+    <ResultType> ParseResult<ResultType> error(@NonNull String parseError);
+
+    /** @see #error(int, String, Exception) */
+    <ResultType> ParseResult<ResultType> error(int parseError, @Nullable String errorMessage);
+
+    /**
+     * Marks this as an error result. When this method is called, the return value <b>must</b>
+     * be returned to the exit of the parent method that took in this {@link ParseInput} as a
+     * parameter.
+     *
+     * The calling site of that method is then expected to check the result for error, and
+     * continue to bubble up if it is an error.
+     *
+     * Or, if the code explicitly handles an error,
+     * {@link ParseResult#ignoreError()} should be called.
+     *
+     * If the result {@link ParseResult#isSuccess()}, then it can be used as-is, as
+     * overlapping/consecutive successes are allowed.
+     */
+    <ResultType> ParseResult<ResultType> error(int parseError, @Nullable String errorMessage,
+            @Nullable Exception exception);
+
+    /**
+     * Moves the error in {@param result} to this input's type. In practice this does nothing
+     * but cast the type of the {@link ParseResult} for type safety, since the parameter
+     * and the receiver should be the same object.
+     */
+    <ResultType> ParseResult<ResultType> error(ParseResult result);
+}
diff --git a/core/java/android/content/pm/parsing/result/ParseResult.java b/core/java/android/content/pm/parsing/result/ParseResult.java
new file mode 100644
index 0000000..338048c
--- /dev/null
+++ b/core/java/android/content/pm/parsing/result/ParseResult.java
@@ -0,0 +1,76 @@
+/*
+ * 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.result;
+
+import android.annotation.Nullable;
+import android.content.pm.PackageParser;
+
+/**
+ * The output side of {@link ParseInput}, which must result from a method call on
+ * {@link ParseInput}.
+ *
+ * When using this class, keep in mind that all {@link ParseInput}s and {@link ParseResult}s
+ * are the exact same object, scoped to a per {@link PackageParser} instance, per thread basis,
+ * thrown around and casted everywhere for type safety.
+ *
+ * @hide
+ */
+public interface ParseResult<ResultType> {
+
+    /**
+     * Un-marks this result as an error, also allowing it to be re-used as {@link ParseInput}.
+     *
+     * This should only be used in cases where it's absolutely certain that error handling is
+     * irrelevant. Such as for backwards compatibility where it previously didn't fail and that
+     * behavior has to be maintained.
+     *
+     * Mostly an alias for readability.
+     */
+    void ignoreError();
+
+    /**
+     * Returns true if the result is not an error and thus contains a valid object.
+     *
+     * For backwards-compat reasons, it's possible to have a successful result with a null
+     * result object, depending on the behavior of the parsing method.
+     *
+     * It is expected that every method calls this to check for an error state to bubble up
+     * the error to its parent method after every parse method call.
+     *
+     * It is not always necessary to check this, as it is valid to return any ParseResult from
+     * a method so long as the type matches <b>without casting it</b>.
+     *
+     * The infrastructure is set up such that as long as a result is the proper type and
+     * the right side of success vs. error, it can be bubble up through all its parent methods.
+     */
+    boolean isSuccess();
+
+    /**
+     * Opposite of {@link #isSuccess()} for readability.
+     */
+    boolean isError();
+
+    ResultType getResult();
+
+    int getErrorCode();
+
+    @Nullable
+    String getErrorMessage();
+
+    @Nullable
+    Exception getException();
+}
diff --git a/core/java/android/content/pm/parsing/result/ParseTypeImpl.java b/core/java/android/content/pm/parsing/result/ParseTypeImpl.java
new file mode 100644
index 0000000..9b22f09
--- /dev/null
+++ b/core/java/android/content/pm/parsing/result/ParseTypeImpl.java
@@ -0,0 +1,145 @@
+/*
+ * 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.result;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.pm.PackageManager;
+import android.content.pm.parsing.ParsingUtils;
+import android.util.Log;
+
+import java.util.Arrays;
+
+/** @hide */
+public class ParseTypeImpl implements ParseInput, ParseResult<Object> {
+
+    private static final String TAG = ParsingUtils.TAG;
+
+    private static final boolean DEBUG_FILL_STACK_TRACE = false;
+
+    private static final boolean DEBUG_LOG_ON_ERROR = false;
+
+    private Object result;
+
+    private int errorCode = PackageManager.INSTALL_SUCCEEDED;
+
+    @Nullable
+    private String errorMessage;
+
+    @Nullable
+    private Exception exception;
+
+    public ParseInput reset() {
+        this.result = null;
+        this.errorCode = PackageManager.INSTALL_SUCCEEDED;
+        this.errorMessage = null;
+        this.exception = null;
+        return this;
+    }
+
+    @Override
+    public void ignoreError() {
+        reset();
+    }
+
+    @Override
+    public <ResultType> ParseResult<ResultType> success(ResultType result) {
+        if (errorCode != PackageManager.INSTALL_SUCCEEDED || errorMessage != null) {
+            throw new IllegalStateException("Cannot set to success after set to error, was "
+                    + errorMessage, exception);
+        }
+        this.result = result;
+        //noinspection unchecked
+        return (ParseResult<ResultType>) this;
+    }
+
+    @Override
+    public <ResultType> ParseResult<ResultType> error(int parseError) {
+        return error(parseError, null);
+    }
+
+    @Override
+    public <ResultType> ParseResult<ResultType> error(@NonNull String parseError) {
+        return error(PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, parseError);
+    }
+
+    @Override
+    public <ResultType> ParseResult<ResultType> error(int errorCode,
+            @Nullable String errorMessage) {
+        return error(errorCode, errorMessage, null);
+    }
+
+    @Override
+    public <ResultType> ParseResult<ResultType> error(ParseResult intentResult) {
+        return error(intentResult.getErrorCode(), intentResult.getErrorMessage());
+    }
+
+    @Override
+    public <ResultType> ParseResult<ResultType> error(int errorCode, @Nullable String errorMessage,
+            Exception exception) {
+        this.errorCode = errorCode;
+        this.errorMessage = errorMessage;
+        this.exception = exception;
+
+        if (DEBUG_FILL_STACK_TRACE) {
+            if (exception == null) {
+                this.exception = new Exception();
+            }
+        }
+
+        if (DEBUG_LOG_ON_ERROR) {
+            Exception exceptionToLog = this.exception != null ? this.exception : new Exception();
+            Log.w(TAG, "ParseInput set to error " + errorCode + ", " + errorMessage,
+                    exceptionToLog);
+        }
+
+        //noinspection unchecked
+        return (ParseResult<ResultType>) this;
+    }
+
+    @Override
+    public Object getResult() {
+        return this.result;
+    }
+
+    @Override
+    public boolean isSuccess() {
+        return errorCode == PackageManager.INSTALL_SUCCEEDED;
+    }
+
+    @Override
+    public boolean isError() {
+        return !isSuccess();
+    }
+
+    @Override
+    public int getErrorCode() {
+        return errorCode;
+    }
+
+    @Nullable
+    @Override
+    public String getErrorMessage() {
+        return errorMessage;
+    }
+
+    @Nullable
+    @Override
+    public Exception getException() {
+        return exception;
+    }
+}
diff --git a/core/java/android/debug/AdbManager.java b/core/java/android/debug/AdbManager.java
index 0a76bed..7714dd8 100644
--- a/core/java/android/debug/AdbManager.java
+++ b/core/java/android/debug/AdbManager.java
@@ -31,6 +31,114 @@
 public class AdbManager {
     private static final String TAG = "AdbManager";
 
+    /**
+     * Action indicating the state change of wireless debugging. Can be either
+     *   STATUS_CONNECTED
+     *   STATUS_DISCONNECTED
+     *
+     * @hide
+     */
+    public static final String WIRELESS_DEBUG_STATE_CHANGED_ACTION =
+            "com.android.server.adb.WIRELESS_DEBUG_STATUS";
+
+    /**
+     * Contains the list of paired devices.
+     *
+     * @hide
+     */
+    public static final String WIRELESS_DEBUG_PAIRED_DEVICES_ACTION =
+            "com.android.server.adb.WIRELESS_DEBUG_PAIRED_DEVICES";
+
+    /**
+     * Action indicating the status of a pairing. Can be either
+     *   WIRELESS_STATUS_FAIL
+     *   WIRELESS_STATUS_SUCCESS
+     *   WIRELESS_STATUS_CANCELLED
+     *   WIRELESS_STATUS_PAIRING_CODE
+     *   WIRELESS_STATUS_CONNECTED
+     *
+     * @hide
+     */
+    public static final String WIRELESS_DEBUG_PAIRING_RESULT_ACTION =
+            "com.android.server.adb.WIRELESS_DEBUG_PAIRING_RESULT";
+
+    /**
+     * Extra containing the PairDevice map of paired/pairing devices.
+     *
+     * @hide
+     */
+    public static final String WIRELESS_DEVICES_EXTRA = "devices_map";
+
+    /**
+     * The status of the pairing/unpairing.
+     *
+     * @hide
+     */
+    public static final String WIRELESS_STATUS_EXTRA = "status";
+
+    /**
+     * The PairDevice.
+     *
+     * @hide
+     */
+    public static final String WIRELESS_PAIR_DEVICE_EXTRA = "pair_device";
+
+    /**
+     * The six-digit pairing code.
+     *
+     * @hide
+     */
+    public static final String WIRELESS_PAIRING_CODE_EXTRA = "pairing_code";
+
+    /**
+     * The adb connection/pairing port that was opened.
+     *
+     * @hide
+     */
+    public static final String WIRELESS_DEBUG_PORT_EXTRA = "adb_port";
+
+    /**
+     * Status indicating the pairing/unpairing failed.
+     *
+     * @hide
+     */
+    public static final int WIRELESS_STATUS_FAIL = 0;
+
+    /**
+     * Status indicating the pairing/unpairing succeeded.
+     *
+     * @hide
+     */
+    public static final int WIRELESS_STATUS_SUCCESS = 1;
+
+    /**
+     * Status indicating the pairing/unpairing was cancelled.
+     *
+     * @hide
+     */
+    public static final int WIRELESS_STATUS_CANCELLED = 2;
+
+    /**
+     * Status indicating the pairing code for pairing.
+     *
+     * @hide
+     */
+    public static final int WIRELESS_STATUS_PAIRING_CODE = 3;
+
+    /**
+     * Status indicating wireless debugging is connected.
+     *
+     * @hide
+     */
+    public static final int WIRELESS_STATUS_CONNECTED = 4;
+
+    /**
+     * Status indicating wireless debugging is disconnected.
+     *
+     * @hide
+     */
+    public static final int WIRELESS_STATUS_DISCONNECTED = 5;
+
     private final Context mContext;
     private final IAdbManager mService;
 
diff --git a/core/java/android/debug/AdbManagerInternal.java b/core/java/android/debug/AdbManagerInternal.java
index 51eb7fc..0bd9f19 100644
--- a/core/java/android/debug/AdbManagerInternal.java
+++ b/core/java/android/debug/AdbManagerInternal.java
@@ -42,7 +42,7 @@
     /**
      * Returns {@code true} if ADB debugging is enabled.
      */
-    public abstract boolean isAdbEnabled();
+    public abstract boolean isAdbEnabled(byte transportType);
 
     /**
      * Returns the file that contains all of the ADB keys used by the device.
diff --git a/core/java/android/debug/AdbTransportType.aidl b/core/java/android/debug/AdbTransportType.aidl
new file mode 100644
index 0000000..6904615
--- /dev/null
+++ b/core/java/android/debug/AdbTransportType.aidl
@@ -0,0 +1,25 @@
+/*
+ * 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.debug;
+
+/** @hide */
+@Backing(type="byte")
+enum AdbTransportType {
+    USB,
+    WIFI,
+}
+
diff --git a/core/java/android/debug/IAdbManager.aidl b/core/java/android/debug/IAdbManager.aidl
index c48fc07..aea7633 100644
--- a/core/java/android/debug/IAdbManager.aidl
+++ b/core/java/android/debug/IAdbManager.aidl
@@ -43,6 +43,62 @@
     void clearDebuggingKeys();
 
     /**
+     * Allow ADB wireless debugging on the connected network. If {@code alwaysAllow}
+     * is {@code true}, add {@code bssid} to list of networks that the user has
+     * approved.
+     *
+     * @param alwaysAllow if true, add permanently to list of allowed networks
+     * @param bssid BSSID of the network
+     */
+    void allowWirelessDebugging(boolean alwaysAllow, String bssid);
+
+    /**
+     * Deny ADB wireless debugging on the connected network.
+     */
+    void denyWirelessDebugging();
+
+    /**
+     * Returns a Map<String, PairDevice> with the key fingerprint mapped to the device information.
+     */
+    Map getPairedDevices();
+
+    /**
+     * Unpair the device identified by the key fingerprint it uses.
+     *
+     * @param fingerprint fingerprint of the key the device is using.
+     */
+    void unpairDevice(String fingerprint);
+
+    /**
+     * Enables pairing by pairing code. The result of the enable will be sent via intent action
+     * {@link android.debug.AdbManager#WIRELESS_DEBUG_ENABLE_DISCOVER_ACTION}. Furthermore, the
+     * pairing code will also be sent in the intent as an extra
+     * @{link android.debug.AdbManager#WIRELESS_PAIRING_CODE_EXTRA}. Note that only one
+     * pairing method can be enabled at a time, either by pairing code, or by QR code.
+     */
+    void enablePairingByPairingCode();
+
+    /**
+     * Enables pairing by QR code. The result of the enable will be sent via intent action
+     * {@link android.debug.AdbManager#WIRELESS_DEBUG_ENABLE_DISCOVER_ACTION}. Note that only one
+     * pairing method can be enabled at a time, either by pairing code, or by QR code.
+     *
+     * @param serviceName The MDNS service name parsed from the QR code.
+     * @param password The password parsed from the QR code.
+     */
+    void enablePairingByQrCode(String serviceName, String password);
+
+    /**
+     * Returns the network port that adb wireless server is running on.
+     */
+    int getAdbWirelessPort();
+
+    /**
+     * Disables pairing.
+     */
+    void disablePairing();
+
+    /**
      * Returns true if device supports secure Adb over Wi-Fi.
      */
     boolean isAdbWifiSupported();
diff --git a/core/java/android/debug/IAdbTransport.aidl b/core/java/android/debug/IAdbTransport.aidl
index 77211fc93..f018813 100644
--- a/core/java/android/debug/IAdbTransport.aidl
+++ b/core/java/android/debug/IAdbTransport.aidl
@@ -16,7 +16,9 @@
 
 package android.debug;
 
+import android.debug.AdbTransportType;
+
 /** @hide */
 interface IAdbTransport {
-    void onAdbEnabled(boolean enabled);
+    void onAdbEnabled(boolean enabled, in AdbTransportType type);
 }
diff --git a/core/java/android/debug/PairDevice.java b/core/java/android/debug/PairDevice.java
new file mode 100644
index 0000000..2d5b446
--- /dev/null
+++ b/core/java/android/debug/PairDevice.java
@@ -0,0 +1,112 @@
+/*
+ * 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.debug;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.annotations.Immutable;
+import com.android.internal.util.Preconditions;
+
+/**
+ * Contains information about the client in an ADB connection.
+ * @hide
+ */
+@Immutable
+public class PairDevice implements Parcelable {
+    /**
+     * The human-readable name of the device.
+     */
+    @NonNull private final String mName;
+
+    /**
+     * The device's guid.
+     */
+    @NonNull private final String mGuid;
+
+    /**
+     * Indicates whether the device is currently connected to adbd.
+     */
+    private final boolean mConnected;
+
+    public PairDevice(@NonNull String name, @NonNull String guid, boolean connected) {
+        Preconditions.checkStringNotEmpty(name);
+        Preconditions.checkStringNotEmpty(guid);
+        mName = name;
+        mGuid = guid;
+        mConnected = connected;
+    }
+
+    /**
+     * @return the device name.
+     */
+    @NonNull
+    public String getDeviceName() {
+        return mName;
+    }
+
+    /**
+     * @return the device GUID.
+     */
+    @NonNull
+    public String getGuid() {
+        return mGuid;
+    }
+
+    /**
+     * @return the adb connection state of the device.
+     */
+    public boolean isConnected() {
+        return mConnected;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeString(mName);
+        dest.writeString(mGuid);
+        dest.writeBoolean(mConnected);
+    }
+
+    /**
+     * @return Human-readable info about the object.
+     */
+    @Override
+    public String toString() {
+        return "\n" + mName + "\n" + mGuid + "\n" + mConnected;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @NonNull
+    public static final Parcelable.Creator<PairDevice> CREATOR =
+            new Creator<PairDevice>() {
+                @Override
+                public PairDevice createFromParcel(Parcel source) {
+                    return new PairDevice(source.readString(), source.readString(),
+                            source.readBoolean());
+                }
+
+                @Override
+                public PairDevice[] newArray(int size) {
+                    return new PairDevice[size];
+                }
+            };
+}
diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java
index 24d9311..cc0c1a30 100644
--- a/core/java/android/hardware/camera2/CameraDevice.java
+++ b/core/java/android/hardware/camera2/CameraDevice.java
@@ -688,17 +688,19 @@
      * <tr><th colspan="5">Concurrent stream guaranteed configurations</th></tr>
      * <tr><th colspan="2" id="rb">Target 1</th><th colspan="2" id="rb">Target 2</th><th rowspan="2">Sample use case(s)</th> </tr>
      * <tr><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th> </tr>
-     * <tr> <td>{@code YUV}</td><td id="rb">{@code MAXIMUM}</td>  <td colspan="2" id="rb"></td> <td>In-app video / image processing.</td> </tr>
-     * <tr> <td>{@code PRIV}</td><td id="rb">{@code MAXIMUM}</td>  <td colspan="2" id="rb"></td> <td>In-app viewfinder analysis.</td> </tr>
-     * <tr> <td>{@code YUV}</td><td id="rb">{@code MAXIMUM}</td> <td>{@code YUV }</td><td id="rb">{@code MAXIMUM}</td> <td>In-app video / processing with preview.</td> </tr>
-     * <tr> <td>{@code YUV}</td><td id="rb">{@code MAXIMUM}</td> <td>{@code PRIV }</td><td id="rb">{@code MAXIMUM}</td> <td>In-app video / processing with preview.</td> </tr>
-     * <tr> <td>{@code PRIV}</td><td id="rb">{@code MAXIMUM}</td> <td>{@code PRIV }</td><td id="rb">{@code MAXIMUM}</td> <td>Standard Recording.</td> </tr>
+     * <tr> <td>{@code YUV}</td><td id="rb">{@code s1440p}</td>  <td colspan="2" id="rb"></td> <td>In-app video / image processing.</td> </tr>
+     * <tr> <td>{@code PRIV}</td><td id="rb">{@code s1440p}</td>  <td colspan="2" id="rb"></td> <td>In-app viewfinder analysis.</td> </tr>
+     * <tr> <td>{@code JPEG}</td><td id="rb">{@code s1440p}</td>  <td colspan="2" id="rb"></td> <td>No viewfinder still image capture.</td> </tr>
+     * <tr> <td>{@code YUV / PRIV}</td><td id="rb">{@code s720p}</td> <td>{@code JPEG}</td><td id="rb">{@code s1440p}</td> <td> Standard still imaging.</td> </tr>
+     * <tr> <td>{@code YUV / PRIV}</td><td id="rb">{@code s720p}</td> <td>{@code YUV / PRIV }</td><td id="rb">{@code s1440p}</td> <td>In-app video / processing with preview.</td> </tr>
      * </table><br>
      * </p>
      *
-     * <p> For guaranteed concurrent stream configurations, MAXIMUM refers to the camera device's
-     * resolution for that format from {@link StreamConfigurationMap#getOutputSizes} or
+     * <p> For guaranteed concurrent stream configurations:</p>
+     * <p> s720p refers to the camera device's resolution for that format from {@link StreamConfigurationMap#getOutputSizes} or
      * 720p(1280X720) whichever is lower. </p>
+     * <p> s1440p refers to the camera device's resolution for that format from {@link StreamConfigurationMap#getOutputSizes} or
+     * 1440p(1920X1440) whichever is lower. </p>
      * <p>MONOCHROME-capability ({@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES}
      * includes {@link CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_MONOCHROME MONOCHROME}) devices
      * supporting {@link android.graphics.ImageFormat#Y8 Y8} support substituting {@code YUV}
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index 17c83f3..743ce7b 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -140,6 +140,11 @@
      * <p>The set of combinations doesn't contain physical cameras that can only be used as
      * part of a logical multi-camera device.</p>
      *
+     * <p> If a new camera id becomes available through
+     * {@link AvailabilityCallback#onCameraUnavailable(String)}, clients can call
+     * this method to check if new combinations of camera ids which can stream concurrently are
+     * available.
+     *
      * @return The set of combinations of currently connected camera devices, that may have
      *         sessions configured concurrently. The set of combinations will be empty if no such
      *         combinations are supported by the camera subsystem.
diff --git a/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java b/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java
index 41e1443..f0fab6a 100644
--- a/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java
+++ b/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java
@@ -267,7 +267,7 @@
                 mStreamsInformation.hashCode());
     }
 
-    private static enum SizeThreshold { VGA, PREVIEW, RECORD, MAXIMUM, s720p }
+    private static enum SizeThreshold { VGA, PREVIEW, RECORD, MAXIMUM, s720p, s1440p }
     private static enum ReprocessType { NONE, PRIVATE, YUV }
     private static final class StreamTemplate {
         public int mFormat;
@@ -651,23 +651,38 @@
 
     private static StreamCombinationTemplate sConcurrentStreamCombinations[] = {
         new StreamCombinationTemplate(new StreamTemplate [] {
-                new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.s720p) },
+                new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.s1440p) },
                 "In-app video / image processing"),
         new StreamCombinationTemplate(new StreamTemplate [] {
-                new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.s720p) },
+                new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.s1440p) },
                 "preview / preview to GPU"),
         new StreamCombinationTemplate(new StreamTemplate [] {
+                new StreamTemplate(ImageFormat.JPEG, SizeThreshold.s1440p) },
+                "No view-finder still image capture"),
+        new StreamCombinationTemplate(new StreamTemplate [] {
                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.s720p),
-                new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.s720p)},
+                new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.s1440p)},
+                "Two-input in app video / image processing"),
+        new StreamCombinationTemplate(new StreamTemplate [] {
+                new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.s720p),
+                new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.s1440p)},
+                "High resolution video recording with preview"),
+        new StreamCombinationTemplate(new StreamTemplate [] {
+                new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.s720p),
+                new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.s1440p)},
+                "In-app video / image processing with preview"),
+        new StreamCombinationTemplate(new StreamTemplate [] {
+                new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.s720p),
+                new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.s1440p)},
                 "In-app video / image processing with preview"),
         new StreamCombinationTemplate(new StreamTemplate [] {
                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.s720p),
-                new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.s720p)},
-                "In-app video / image processing with preview"),
+                new StreamTemplate(ImageFormat.JPEG, SizeThreshold.s1440p)},
+                "Standard stil image capture"),
         new StreamCombinationTemplate(new StreamTemplate [] {
-                new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.s720p),
-                new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.s720p)},
-                "Standard Recording"),
+                new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.s720p),
+                new StreamTemplate(ImageFormat.JPEG, SizeThreshold.s1440p)},
+                "Standard still image capture"),
     };
 
     /**
@@ -720,6 +735,7 @@
                          + " cannot have mandatory concurrent streams");
             }
             Size size720p = new Size(1280, 720);
+            Size size1440p = new Size(1920, 1440);
 
             ArrayList<MandatoryStreamCombination> availableConcurrentStreamCombinations =
                     new ArrayList<MandatoryStreamCombination>();
@@ -732,8 +748,16 @@
                 for (StreamTemplate template : combTemplate.mStreamTemplates) {
                     MandatoryStreamInformation streamInfo;
                     List<Size> sizes = new ArrayList<Size>();
+                    Size formatSize = null;
+                    switch (template.mSizeThreshold) {
+                        case s1440p:
+                            formatSize = size1440p;
+                            break;
+                        default:
+                            formatSize = size720p;
+                    }
                     Size sizeChosen =
-                            getMinSize(size720p,
+                            getMinSize(formatSize,
                                     getMaxSize(mStreamConfigMap.getOutputSizes(template.mFormat)));
                     sizes.add(sizeChosen);
                     try {
diff --git a/core/java/android/hardware/display/DeviceProductInfo.java b/core/java/android/hardware/display/DeviceProductInfo.java
index 6ad7fae..ce26cb0 100644
--- a/core/java/android/hardware/display/DeviceProductInfo.java
+++ b/core/java/android/hardware/display/DeviceProductInfo.java
@@ -28,21 +28,21 @@
  * @hide
  */
 public final class DeviceProductInfo implements Parcelable {
-    final private String mName;
-    final private String mManufacturerPnpId;
-    final private String mProductId;
-    final private Integer mModelYear;
-    final private ManufactureDate mManufactureDate;
+    private final String mName;
+    private final String mManufacturerPnpId;
+    private final String mProductId;
+    private final Integer mModelYear;
+    private final ManufactureDate mManufactureDate;
 
     public DeviceProductInfo(
             String name,
             String manufacturerPnpId,
-            String productCode,
+            String productId,
             Integer modelYear,
             ManufactureDate manufactureDate) {
         this.mName = name;
         this.mManufacturerPnpId = manufacturerPnpId;
-        this.mProductId = productCode;
+        this.mProductId = productId;
         this.mModelYear = modelYear;
         this.mManufactureDate = manufactureDate;
     }
@@ -158,8 +158,8 @@
      * @hide
      */
     public static class ManufactureDate implements Parcelable {
-        final private Integer mWeek;
-        final private Integer mYear;
+        private final Integer mWeek;
+        private final Integer mYear;
 
         public ManufactureDate(Integer week, Integer year) {
             mWeek = week;
diff --git a/core/java/android/hardware/face/FaceManager.java b/core/java/android/hardware/face/FaceManager.java
index 3a0660d..9b9889e 100644
--- a/core/java/android/hardware/face/FaceManager.java
+++ b/core/java/android/hardware/face/FaceManager.java
@@ -97,8 +97,10 @@
         }
 
         @Override // binder call
-        public void onAuthenticationSucceeded(long deviceId, Face face, int userId) {
-            mHandler.obtainMessage(MSG_AUTHENTICATION_SUCCEEDED, userId, 0, face).sendToTarget();
+        public void onAuthenticationSucceeded(long deviceId, Face face, int userId,
+                boolean isStrongBiometric) {
+            mHandler.obtainMessage(MSG_AUTHENTICATION_SUCCEEDED, userId, isStrongBiometric ? 1 : 0,
+                    face).sendToTarget();
         }
 
         @Override // binder call
@@ -814,6 +816,7 @@
         private Face mFace;
         private CryptoObject mCryptoObject;
         private int mUserId;
+        private boolean mIsStrongBiometric;
 
         /**
          * Authentication result
@@ -822,10 +825,12 @@
          * @param face   the recognized face data, if allowed.
          * @hide
          */
-        public AuthenticationResult(CryptoObject crypto, Face face, int userId) {
+        public AuthenticationResult(CryptoObject crypto, Face face, int userId,
+                boolean isStrongBiometric) {
             mCryptoObject = crypto;
             mFace = face;
             mUserId = userId;
+            mIsStrongBiometric = isStrongBiometric;
         }
 
         /**
@@ -857,6 +862,16 @@
         public int getUserId() {
             return mUserId;
         }
+
+        /**
+         * Check whether the strength of the face modality associated with this operation is strong
+         * (i.e. not weak or convenience).
+         *
+         * @hide
+         */
+        public boolean isStrongBiometric() {
+            return mIsStrongBiometric;
+        }
     }
 
     /**
@@ -1056,7 +1071,8 @@
                             msg.arg2 /* vendorCode */);
                     break;
                 case MSG_AUTHENTICATION_SUCCEEDED:
-                    sendAuthenticatedSucceeded((Face) msg.obj, msg.arg1 /* userId */);
+                    sendAuthenticatedSucceeded((Face) msg.obj, msg.arg1 /* userId */,
+                            msg.arg2 == 1 /* isStrongBiometric */);
                     break;
                 case MSG_AUTHENTICATION_FAILED:
                     sendAuthenticatedFailed();
@@ -1133,10 +1149,10 @@
         }
     }
 
-    private void sendAuthenticatedSucceeded(Face face, int userId) {
+    private void sendAuthenticatedSucceeded(Face face, int userId, boolean isStrongBiometric) {
         if (mAuthenticationCallback != null) {
             final AuthenticationResult result =
-                    new AuthenticationResult(mCryptoObject, face, userId);
+                    new AuthenticationResult(mCryptoObject, face, userId, isStrongBiometric);
             mAuthenticationCallback.onAuthenticationSucceeded(result);
         }
     }
diff --git a/core/java/android/hardware/face/IFaceService.aidl b/core/java/android/hardware/face/IFaceService.aidl
index 8ba2473..6318274 100644
--- a/core/java/android/hardware/face/IFaceService.aidl
+++ b/core/java/android/hardware/face/IFaceService.aidl
@@ -110,4 +110,7 @@
     void getFeature(int userId, int feature, IFaceServiceReceiver receiver, String opPackageName);
 
     void userActivity();
+
+    // Initialize the OEM configured biometric strength
+    void initConfiguredStrength(int strength);
 }
diff --git a/core/java/android/hardware/face/IFaceServiceReceiver.aidl b/core/java/android/hardware/face/IFaceServiceReceiver.aidl
index 10f9c43..7582308 100644
--- a/core/java/android/hardware/face/IFaceServiceReceiver.aidl
+++ b/core/java/android/hardware/face/IFaceServiceReceiver.aidl
@@ -24,7 +24,8 @@
 oneway interface IFaceServiceReceiver {
     void onEnrollResult(long deviceId, int faceId, int remaining);
     void onAcquired(long deviceId, int acquiredInfo, int vendorCode);
-    void onAuthenticationSucceeded(long deviceId, in Face face, int userId);
+    void onAuthenticationSucceeded(long deviceId, in Face face, int userId,
+            boolean isStrongBiometric);
     void onAuthenticationFailed(long deviceId);
     void onError(long deviceId, int error, int vendorCode);
     void onRemoved(long deviceId, int faceId, int remaining);
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index f301a5c..dc8ea5e 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -176,6 +176,7 @@
         private Fingerprint mFingerprint;
         private CryptoObject mCryptoObject;
         private int mUserId;
+        private boolean mIsStrongBiometric;
 
         /**
          * Authentication result
@@ -184,10 +185,12 @@
          * @param fingerprint the recognized fingerprint data, if allowed.
          * @hide
          */
-        public AuthenticationResult(CryptoObject crypto, Fingerprint fingerprint, int userId) {
+        public AuthenticationResult(CryptoObject crypto, Fingerprint fingerprint, int userId,
+                boolean isStrongBiometric) {
             mCryptoObject = crypto;
             mFingerprint = fingerprint;
             mUserId = userId;
+            mIsStrongBiometric = isStrongBiometric;
         }
 
         /**
@@ -211,6 +214,15 @@
          * @hide
          */
         public int getUserId() { return mUserId; }
+
+        /**
+         * Check whether the strength of the fingerprint modality associated with this operation is
+         * strong (i.e. not weak or convenience).
+         * @hide
+         */
+        public boolean isStrongBiometric() {
+            return mIsStrongBiometric;
+        }
     };
 
     /**
@@ -833,7 +845,8 @@
                             msg.arg2 /* vendorCode */);
                     break;
                 case MSG_AUTHENTICATION_SUCCEEDED:
-                    sendAuthenticatedSucceeded((Fingerprint) msg.obj, msg.arg1 /* userId */);
+                    sendAuthenticatedSucceeded((Fingerprint) msg.obj, msg.arg1 /* userId */,
+                            msg.arg2 == 1 /* isStrongBiometric */);
                     break;
                 case MSG_AUTHENTICATION_FAILED:
                     sendAuthenticatedFailed();
@@ -890,10 +903,10 @@
         }
     }
 
-    private void sendAuthenticatedSucceeded(Fingerprint fp, int userId) {
+    private void sendAuthenticatedSucceeded(Fingerprint fp, int userId, boolean isStrongBiometric) {
         if (mAuthenticationCallback != null) {
             final AuthenticationResult result =
-                    new AuthenticationResult(mCryptoObject, fp, userId);
+                    new AuthenticationResult(mCryptoObject, fp, userId, isStrongBiometric);
             mAuthenticationCallback.onAuthenticationSucceeded(result);
         }
     }
@@ -1078,8 +1091,10 @@
         }
 
         @Override // binder call
-        public void onAuthenticationSucceeded(long deviceId, Fingerprint fp, int userId) {
-            mHandler.obtainMessage(MSG_AUTHENTICATION_SUCCEEDED, userId, 0, fp).sendToTarget();
+        public void onAuthenticationSucceeded(long deviceId, Fingerprint fp, int userId,
+                boolean isStrongBiometric) {
+            mHandler.obtainMessage(MSG_AUTHENTICATION_SUCCEEDED, userId, isStrongBiometric ? 1 : 0,
+                    fp).sendToTarget();
         }
 
         @Override // binder call
diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
index f2ffd08d..0285448 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
@@ -113,4 +113,7 @@
 
     // Removes a callback set by addClientActiveCallback
     void removeClientActiveCallback(IFingerprintClientActiveCallback callback);
+
+    // Initialize the OEM configured biometric strength
+    void initConfiguredStrength(int strength);
 }
diff --git a/core/java/android/hardware/fingerprint/IFingerprintServiceReceiver.aidl b/core/java/android/hardware/fingerprint/IFingerprintServiceReceiver.aidl
index cf1c94e..4412cee 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintServiceReceiver.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintServiceReceiver.aidl
@@ -24,7 +24,8 @@
 oneway interface IFingerprintServiceReceiver {
     void onEnrollResult(long deviceId, int fingerId, int groupId, int remaining);
     void onAcquired(long deviceId, int acquiredInfo, int vendorCode);
-    void onAuthenticationSucceeded(long deviceId, in Fingerprint fp, int userId);
+    void onAuthenticationSucceeded(long deviceId, in Fingerprint fp, int userId,
+            boolean isStrongBiometric);
     void onAuthenticationFailed(long deviceId);
     void onError(long deviceId, int error, int vendorCode);
     void onRemoved(long deviceId, int fingerId, int groupId, int remaining);
diff --git a/core/java/android/hardware/iris/IIrisService.aidl b/core/java/android/hardware/iris/IIrisService.aidl
index 8cf3c13..5ef0a0c 100644
--- a/core/java/android/hardware/iris/IIrisService.aidl
+++ b/core/java/android/hardware/iris/IIrisService.aidl
@@ -21,4 +21,6 @@
  * @hide
  */
 interface IIrisService {
-}
\ No newline at end of file
+    // Initialize the OEM configured biometric strength
+    void initConfiguredStrength(int strength);
+}
diff --git a/core/java/android/hardware/usb/UsbManager.java b/core/java/android/hardware/usb/UsbManager.java
index 086db10..d16f070 100644
--- a/core/java/android/hardware/usb/UsbManager.java
+++ b/core/java/android/hardware/usb/UsbManager.java
@@ -18,6 +18,7 @@
 package android.hardware.usb;
 
 import android.Manifest;
+import android.annotation.LongDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresFeature;
@@ -337,12 +338,14 @@
      * Code for the mtp usb function. Passed as a mask into {@link #setCurrentFunctions(long)}
      * {@hide}
      */
+    @SystemApi
     public static final long FUNCTION_MTP = GadgetFunction.MTP;
 
     /**
      * Code for the ptp usb function. Passed as a mask into {@link #setCurrentFunctions(long)}
      * {@hide}
      */
+    @SystemApi
     public static final long FUNCTION_PTP = GadgetFunction.PTP;
 
     /**
@@ -356,24 +359,28 @@
      * Code for the midi usb function. Passed as a mask into {@link #setCurrentFunctions(long)}
      * {@hide}
      */
+    @SystemApi
     public static final long FUNCTION_MIDI = GadgetFunction.MIDI;
 
     /**
      * Code for the accessory usb function.
      * {@hide}
      */
+    @SystemApi
     public static final long FUNCTION_ACCESSORY = GadgetFunction.ACCESSORY;
 
     /**
      * Code for the audio source usb function.
      * {@hide}
      */
+    @SystemApi
     public static final long FUNCTION_AUDIO_SOURCE = GadgetFunction.AUDIO_SOURCE;
 
     /**
      * Code for the adb usb function.
      * {@hide}
      */
+    @SystemApi
     public static final long FUNCTION_ADB = GadgetFunction.ADB;
 
     /**
@@ -399,6 +406,20 @@
         FUNCTION_NAME_TO_CODE.put(UsbManager.USB_FUNCTION_NCM, FUNCTION_NCM);
     }
 
+    /** @hide */
+    @LongDef(flag = true, prefix = { "FUNCTION_" }, value = {
+            FUNCTION_NONE,
+            FUNCTION_MTP,
+            FUNCTION_PTP,
+            FUNCTION_RNDIS,
+            FUNCTION_MIDI,
+            FUNCTION_ACCESSORY,
+            FUNCTION_AUDIO_SOURCE,
+            FUNCTION_ADB,
+            FUNCTION_NCM,
+    })
+    public @interface UsbFunctionMode {}
+
     private final Context mContext;
     private final IUsbManager mService;
 
@@ -721,7 +742,7 @@
      */
     @SystemApi
     @RequiresPermission(Manifest.permission.MANAGE_USB)
-    public void setCurrentFunctions(long functions) {
+    public void setCurrentFunctions(@UsbFunctionMode long functions) {
         try {
             mService.setCurrentFunctions(functions);
         } catch (RemoteException e) {
diff --git a/core/java/android/inputmethodservice/IInputMethodWrapper.java b/core/java/android/inputmethodservice/IInputMethodWrapper.java
index 2a441de..f0b1eaa 100644
--- a/core/java/android/inputmethodservice/IInputMethodWrapper.java
+++ b/core/java/android/inputmethodservice/IInputMethodWrapper.java
@@ -19,7 +19,6 @@
 import android.annotation.BinderThread;
 import android.annotation.MainThread;
 import android.compat.annotation.UnsupportedAppUsage;
-import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.os.Binder;
@@ -29,7 +28,6 @@
 import android.os.ResultReceiver;
 import android.util.Log;
 import android.view.InputChannel;
-import android.view.autofill.AutofillId;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputBinding;
 import android.view.inputmethod.InputConnection;
@@ -46,6 +44,7 @@
 import com.android.internal.view.IInputMethod;
 import com.android.internal.view.IInputMethodSession;
 import com.android.internal.view.IInputSessionCallback;
+import com.android.internal.view.InlineSuggestionsRequestInfo;
 import com.android.internal.view.InputConnectionWrapper;
 
 import java.io.FileDescriptor;
@@ -233,8 +232,9 @@
                 return;
             case DO_CREATE_INLINE_SUGGESTIONS_REQUEST:
                 args = (SomeArgs) msg.obj;
-                inputMethod.onCreateInlineSuggestionsRequest((ComponentName) args.arg1,
-                        (AutofillId) args.arg2, (IInlineSuggestionsRequestCallback) args.arg3);
+                inputMethod.onCreateInlineSuggestionsRequest(
+                        (InlineSuggestionsRequestInfo) args.arg1,
+                        (IInlineSuggestionsRequestCallback) args.arg2);
                 return;
 
         }
@@ -279,11 +279,10 @@
 
     @BinderThread
     @Override
-    public void onCreateInlineSuggestionsRequest(ComponentName componentName, AutofillId autofillId,
+    public void onCreateInlineSuggestionsRequest(InlineSuggestionsRequestInfo requestInfo,
             IInlineSuggestionsRequestCallback cb) {
         mCaller.executeOrSendMessage(
-                mCaller.obtainMessageOOO(DO_CREATE_INLINE_SUGGESTIONS_REQUEST, componentName,
-                        autofillId, cb));
+                mCaller.obtainMessageOO(DO_CREATE_INLINE_SUGGESTIONS_REQUEST, requestInfo, cb));
     }
 
     @BinderThread
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index b1aa67e..20a4ab3 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -34,7 +34,6 @@
 import android.app.ActivityManager;
 import android.app.Dialog;
 import android.compat.annotation.UnsupportedAppUsage;
-import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.content.res.Configuration;
@@ -74,7 +73,6 @@
 import android.view.WindowInsets;
 import android.view.WindowManager;
 import android.view.animation.AnimationUtils;
-import android.view.autofill.AutofillId;
 import android.view.inputmethod.CompletionInfo;
 import android.view.inputmethod.CursorAnchorInfo;
 import android.view.inputmethod.EditorInfo;
@@ -99,6 +97,7 @@
 import com.android.internal.inputmethod.InputMethodPrivilegedOperations;
 import com.android.internal.inputmethod.InputMethodPrivilegedOperationsRegistry;
 import com.android.internal.view.IInlineSuggestionsRequestCallback;
+import com.android.internal.view.InlineSuggestionsRequestInfo;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -526,12 +525,13 @@
          */
         @MainThread
         @Override
-        public void onCreateInlineSuggestionsRequest(ComponentName componentName,
-                AutofillId autofillId, IInlineSuggestionsRequestCallback cb) {
+        public void onCreateInlineSuggestionsRequest(
+                @NonNull InlineSuggestionsRequestInfo requestInfo,
+                @NonNull IInlineSuggestionsRequestCallback cb) {
             if (DEBUG) {
                 Log.d(TAG, "InputMethodService received onCreateInlineSuggestionsRequest()");
             }
-            handleOnCreateInlineSuggestionsRequest(componentName, cb);
+            handleOnCreateInlineSuggestionsRequest(requestInfo, cb);
         }
 
         /**
@@ -742,11 +742,14 @@
 
     // TODO(b/137800469): Add detailed docs explaining the inline suggestions process.
     /**
-     * Returns an {@link InlineSuggestionsRequest} to be sent to Autofill.
+     * This method should be implemented by subclass which supports displaying autofill inline
+     * suggestion.
      *
-     * <p>Should be implemented by subclasses.</p>
+     * @param uiExtras the extras that contain the UI renderer related information
+     * @return an {@link InlineSuggestionsRequest} to be sent to Autofill.
      */
-    public @Nullable InlineSuggestionsRequest onCreateInlineSuggestionsRequest() {
+    @Nullable
+    public InlineSuggestionsRequest onCreateInlineSuggestionsRequest(@NonNull Bundle uiExtras) {
         return null;
     }
 
@@ -764,7 +767,8 @@
     }
 
     @MainThread
-    private void handleOnCreateInlineSuggestionsRequest(@NonNull ComponentName componentName,
+    private void handleOnCreateInlineSuggestionsRequest(
+            @NonNull InlineSuggestionsRequestInfo requestInfo,
             @NonNull IInlineSuggestionsRequestCallback callback) {
         if (!mInputStarted) {
             try {
@@ -779,8 +783,9 @@
         if (mInlineSuggestionSession != null) {
             mInlineSuggestionSession.invalidateSession();
         }
-        mInlineSuggestionSession = new InlineSuggestionSession(componentName, callback,
-                this::getEditorInfoPackageName, this::onCreateInlineSuggestionsRequest,
+        mInlineSuggestionSession = new InlineSuggestionSession(requestInfo.getComponentName(),
+                callback, this::getEditorInfoPackageName,
+                () -> onCreateInlineSuggestionsRequest(requestInfo.getUiExtras()),
                 this::getHostInputToken, this::onInlineSuggestionsResponse);
     }
 
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index ea26ede..62eff45 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -1279,7 +1279,8 @@
     @UnsupportedAppUsage
     public NetworkCapabilities[] getDefaultNetworkCapabilitiesForUser(int userId) {
         try {
-            return mService.getDefaultNetworkCapabilitiesForUser(userId);
+            return mService.getDefaultNetworkCapabilitiesForUser(
+                    userId, mContext.getOpPackageName());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -1361,7 +1362,7 @@
     @Nullable
     public NetworkCapabilities getNetworkCapabilities(@Nullable Network network) {
         try {
-            return mService.getNetworkCapabilities(network);
+            return mService.getNetworkCapabilities(network, mContext.getOpPackageName());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -4039,10 +4040,9 @@
             @NonNull PendingIntent operation) {
         printStackTrace();
         checkPendingIntentNotNull(operation);
-        final String callingPackageName = mContext.getOpPackageName();
         try {
             mService.pendingRequestForNetwork(
-                    request.networkCapabilities, operation, callingPackageName);
+                    request.networkCapabilities, operation, mContext.getOpPackageName());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         } catch (ServiceSpecificException e) {
@@ -4154,10 +4154,9 @@
             @NonNull PendingIntent operation) {
         printStackTrace();
         checkPendingIntentNotNull(operation);
-        final String callingPackageName = mContext.getOpPackageName();
         try {
             mService.pendingListenForNetwork(
-                    request.networkCapabilities, operation, callingPackageName);
+                    request.networkCapabilities, operation, mContext.getOpPackageName());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         } catch (ServiceSpecificException e) {
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index 1c7628f..d84d05d 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -60,7 +60,8 @@
     NetworkInfo[] getAllNetworkInfo();
     Network getNetworkForType(int networkType);
     Network[] getAllNetworks();
-    NetworkCapabilities[] getDefaultNetworkCapabilitiesForUser(int userId);
+    NetworkCapabilities[] getDefaultNetworkCapabilitiesForUser(
+            int userId, String callingPackageName);
 
     boolean isNetworkSupported(int networkType);
 
@@ -69,7 +70,7 @@
     LinkProperties getLinkPropertiesForType(int networkType);
     LinkProperties getLinkProperties(in Network network);
 
-    NetworkCapabilities getNetworkCapabilities(in Network network);
+    NetworkCapabilities getNetworkCapabilities(in Network network, String callingPackageName);
 
     @UnsupportedAppUsage
     NetworkState[] getAllNetworkState();
diff --git a/core/java/android/net/Ikev2VpnProfile.java b/core/java/android/net/Ikev2VpnProfile.java
index 42b4da1..f19a341 100644
--- a/core/java/android/net/Ikev2VpnProfile.java
+++ b/core/java/android/net/Ikev2VpnProfile.java
@@ -25,7 +25,10 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.os.Process;
 import android.security.Credentials;
+import android.security.KeyStore;
+import android.security.keystore.AndroidKeyStoreProvider;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.net.VpnProfile;
@@ -59,6 +62,11 @@
  *     Exchange, Version 2 (IKEv2)</a>
  */
 public final class Ikev2VpnProfile extends PlatformVpnProfile {
+    /** Prefix for when a Private Key is an alias to look for in KeyStore @hide */
+    public static final String PREFIX_KEYSTORE_ALIAS = "KEYSTORE_ALIAS:";
+    /** Prefix for when a Private Key is stored directly in the profile @hide */
+    public static final String PREFIX_INLINE = "INLINE:";
+
     private static final String MISSING_PARAM_MSG_TMPL = "Required parameter was not provided: %s";
     private static final String EMPTY_CERT = "";
 
@@ -339,7 +347,8 @@
                 break;
             case TYPE_IKEV2_IPSEC_RSA:
                 profile.ipsecUserCert = certificateToPemString(mUserCert);
-                profile.ipsecSecret = encodeForIpsecSecret(mRsaPrivateKey.getEncoded());
+                profile.ipsecSecret =
+                        PREFIX_INLINE + encodeForIpsecSecret(mRsaPrivateKey.getEncoded());
                 profile.ipsecCaCert =
                         mServerRootCaCert == null ? "" : certificateToPemString(mServerRootCaCert);
                 break;
@@ -360,6 +369,22 @@
     @NonNull
     public static Ikev2VpnProfile fromVpnProfile(@NonNull VpnProfile profile)
             throws IOException, GeneralSecurityException {
+        return fromVpnProfile(profile, null);
+    }
+
+    /**
+     * Builds the Ikev2VpnProfile from the given profile.
+     *
+     * @param profile the source VpnProfile to build from
+     * @param keyStore the Android Keystore instance to use to retrieve the private key, or null if
+     *     the private key is PEM-encoded into the profile.
+     * @return The IKEv2/IPsec VPN profile
+     * @hide
+     */
+    @NonNull
+    public static Ikev2VpnProfile fromVpnProfile(
+            @NonNull VpnProfile profile, @Nullable KeyStore keyStore)
+            throws IOException, GeneralSecurityException {
         final Builder builder = new Builder(profile.server, profile.ipsecIdentifier);
         builder.setProxy(profile.proxy);
         builder.setAllowedAlgorithms(profile.getAllowedAlgorithms());
@@ -378,8 +403,21 @@
                 builder.setAuthPsk(decodeFromIpsecSecret(profile.ipsecSecret));
                 break;
             case TYPE_IKEV2_IPSEC_RSA:
+                final PrivateKey key;
+                if (profile.ipsecSecret.startsWith(PREFIX_KEYSTORE_ALIAS)) {
+                    Objects.requireNonNull(keyStore, "Missing Keystore for aliased PrivateKey");
+
+                    final String alias =
+                            profile.ipsecSecret.substring(PREFIX_KEYSTORE_ALIAS.length());
+                    key = AndroidKeyStoreProvider.loadAndroidKeyStorePrivateKeyFromKeystore(
+                            keyStore, alias, Process.myUid());
+                } else if (profile.ipsecSecret.startsWith(PREFIX_INLINE)) {
+                    key = getPrivateKey(profile.ipsecSecret.substring(PREFIX_INLINE.length()));
+                } else {
+                    throw new IllegalArgumentException("Invalid RSA private key prefix");
+                }
+
                 final X509Certificate userCert = certificateFromPemString(profile.ipsecUserCert);
-                final PrivateKey key = getPrivateKey(profile.ipsecSecret);
                 final X509Certificate serverRootCa = certificateFromPemString(profile.ipsecCaCert);
                 builder.setAuthDigitalSignature(userCert, key, serverRootCa);
                 break;
@@ -391,6 +429,39 @@
     }
 
     /**
+     * Validates that the VpnProfile is acceptable for the purposes of an Ikev2VpnProfile.
+     *
+     * @hide
+     */
+    public static boolean isValidVpnProfile(@NonNull VpnProfile profile) {
+        if (profile.server.isEmpty() || profile.ipsecIdentifier.isEmpty()) {
+            return false;
+        }
+
+        switch (profile.type) {
+            case TYPE_IKEV2_IPSEC_USER_PASS:
+                if (profile.username.isEmpty() || profile.password.isEmpty()) {
+                    return false;
+                }
+                break;
+            case TYPE_IKEV2_IPSEC_PSK:
+                if (profile.ipsecSecret.isEmpty()) {
+                    return false;
+                }
+                break;
+            case TYPE_IKEV2_IPSEC_RSA:
+                if (profile.ipsecSecret.isEmpty() || profile.ipsecUserCert.isEmpty()) {
+                    return false;
+                }
+                break;
+            default:
+                return false;
+        }
+
+        return true;
+    }
+
+    /**
      * Converts a X509 Certificate to a PEM-formatted string.
      *
      * <p>Must be public due to runtime-package restrictions.
@@ -432,7 +503,6 @@
 
     /** @hide */
     @NonNull
-    @VisibleForTesting(visibility = Visibility.PRIVATE)
     public static String encodeForIpsecSecret(@NonNull byte[] secret) {
         checkNotNull(secret, MISSING_PARAM_MSG_TMPL, "secret");
 
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index f8b51dd..83f9980 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -830,6 +830,23 @@
      * <p>This field keeps track of the UID of the app that created this network and is in charge of
      * its lifecycle. This could be the UID of apps such as the Wifi network suggestor, the running
      * VPN, or Carrier Service app managing a cellular data connection.
+     *
+     * <p>For NetworkCapability instances being sent from ConnectivityService, this value MUST be
+     * reset to Process.INVALID_UID unless all the following conditions are met:
+     *
+     * <ol>
+     *   <li>The destination app is the network owner
+     *   <li>The destination app has the ACCESS_FINE_LOCATION permission granted
+     *   <li>The user's location toggle is on
+     * </ol>
+     *
+     * This is because the owner UID is location-sensitive. The apps that request a network could
+     * know where the device is if they can tell for sure the system has connected to the network
+     * they requested.
+     *
+     * <p>This is populated by the network agents and for the NetworkCapabilities instance sent by
+     * an app to the System Server, the value MUST be reset to Process.INVALID_UID by the system
+     * server.
      */
     private int mOwnerUid = Process.INVALID_UID;
 
@@ -842,7 +859,16 @@
     }
 
     /**
-     * Retrieves the UID of the owner app.
+     * Retrieves the UID of the app that owns this network.
+     *
+     * <p>For user privacy reasons, this field will only be populated if:
+     *
+     * <ol>
+     *   <li>The calling app is the network owner
+     *   <li>The calling app has the ACCESS_FINE_LOCATION permission granted
+     *   <li>The user's location toggle is on
+     * </ol>
+     *
      */
     public int getOwnerUid() {
         return mOwnerUid;
@@ -880,8 +906,9 @@
      * @param administratorUids the UIDs to be set as administrators of this Network.
      * @hide
      */
+    @NonNull
     @SystemApi
-    public @NonNull NetworkCapabilities setAdministratorUids(
+    public NetworkCapabilities setAdministratorUids(
             @NonNull final List<Integer> administratorUids) {
         mAdministratorUids.clear();
         mAdministratorUids.addAll(administratorUids);
diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java
index be22458..d60820e 100644
--- a/core/java/android/os/RecoverySystem.java
+++ b/core/java/android/os/RecoverySystem.java
@@ -16,6 +16,8 @@
 
 package android.os;
 
+import static android.view.Display.DEFAULT_DISPLAY;
+
 import static java.nio.charset.StandardCharsets.UTF_8;
 
 import android.annotation.NonNull;
@@ -33,6 +35,7 @@
 import android.content.IntentFilter;
 import android.content.IntentSender;
 import android.content.pm.PackageManager;
+import android.hardware.display.DisplayManager;
 import android.provider.Settings;
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
@@ -614,7 +617,8 @@
 
             // On TV, reboot quiescently if the screen is off
             if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK)) {
-                if (context.getDisplay().getState() != Display.STATE_ON) {
+                DisplayManager dm = context.getSystemService(DisplayManager.class);
+                if (dm.getDisplay(DEFAULT_DISPLAY).getState() != Display.STATE_ON) {
                     reason += ",quiescent";
                 }
             }
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index 3faaff7..e8af564 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -42,6 +42,7 @@
 import android.os.strictmode.ExplicitGcViolation;
 import android.os.strictmode.FileUriExposedViolation;
 import android.os.strictmode.ImplicitDirectBootViolation;
+import android.os.strictmode.IncorrectContextUseViolation;
 import android.os.strictmode.InstanceCountViolation;
 import android.os.strictmode.IntentReceiverLeakedViolation;
 import android.os.strictmode.LeakedClosableViolation;
@@ -250,6 +251,7 @@
             DETECT_VM_UNTAGGED_SOCKET,
             DETECT_VM_NON_SDK_API_USAGE,
             DETECT_VM_IMPLICIT_DIRECT_BOOT,
+            DETECT_VM_INCORRECT_CONTEXT_USE,
             PENALTY_GATHER,
             PENALTY_LOG,
             PENALTY_DIALOG,
@@ -289,6 +291,8 @@
     private static final int DETECT_VM_IMPLICIT_DIRECT_BOOT = 1 << 10;
     /** @hide */
     private static final int DETECT_VM_CREDENTIAL_PROTECTED_WHILE_LOCKED = 1 << 11;
+    /** @hide */
+    private static final int DETECT_VM_INCORRECT_CONTEXT_USE = 1 << 12;
 
     /** @hide */
     private static final int DETECT_VM_ALL = 0x0000ffff;
@@ -871,6 +875,9 @@
                 if (targetSdk >= Build.VERSION_CODES.Q) {
                     detectCredentialProtectedWhileLocked();
                 }
+                if (targetSdk >= Build.VERSION_CODES.R) {
+                    detectIncorrectContextUse();
+                }
 
                 // TODO: Decide whether to detect non SDK API usage beyond a certain API level.
                 // TODO: enable detectImplicitDirectBoot() once system is less noisy
@@ -1028,6 +1035,32 @@
             }
 
             /**
+             * Detect attempts to invoke a method on a {@link Context} that is not suited for such
+             * operation.
+             * <p>An example of this is trying to obtain an instance of visual service (e.g.
+             * {@link android.view.WindowManager}) from a non-visual {@link Context}. This is not
+             * allowed, since a non-visual {@link Context} is not adjusted to any visual area, and
+             * therefore can report incorrect metrics or resources.
+             * @see Context#getDisplay()
+             * @see Context#getSystemService(String)
+             * @hide
+             */
+            @TestApi
+            public @NonNull Builder detectIncorrectContextUse() {
+                return enable(DETECT_VM_INCORRECT_CONTEXT_USE);
+            }
+
+            /**
+             * Disable detection of incorrect context use.
+             * TODO(b/149790106): Fix usages and remove.
+             * @hide
+             */
+            @TestApi
+            public @NonNull Builder permitIncorrectContextUse() {
+                return disable(DETECT_VM_INCORRECT_CONTEXT_USE);
+            }
+
+            /**
              * Crashes the whole process on violation. This penalty runs at the end of all enabled
              * penalties so you'll still get your logging or other violations before the process
              * dies.
@@ -2057,6 +2090,11 @@
     }
 
     /** @hide */
+    public static boolean vmIncorrectContextUseEnabled() {
+        return (sVmPolicy.mask & DETECT_VM_INCORRECT_CONTEXT_USE) != 0;
+    }
+
+    /** @hide */
     public static void onSqliteObjectLeaked(String message, Throwable originStack) {
         onVmPolicyViolation(new SqliteObjectLeakedViolation(message, originStack));
     }
@@ -2130,6 +2168,11 @@
         onVmPolicyViolation(new ImplicitDirectBootViolation());
     }
 
+    /** @hide */
+    public static void onIncorrectContextUsed(String message, Throwable originStack) {
+        onVmPolicyViolation(new IncorrectContextUseViolation(message, originStack));
+    }
+
     /** Assume locked until we hear otherwise */
     private static volatile boolean sUserKeyUnlocked = false;
 
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 84fd580..0f2060a 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -63,6 +63,7 @@
 import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Set;
 
 /**
  * Manages users and user details on a multi-user system. There are two major categories of
@@ -2717,10 +2718,11 @@
             Manifest.permission.CREATE_USERS})
     @UserHandleAware
     public @Nullable UserHandle createProfile(@NonNull String name, @NonNull String userType,
-            @Nullable String[] disallowedPackages) throws UserOperationException {
+            @NonNull Set<String> disallowedPackages) throws UserOperationException {
         try {
             return mService.createProfileForUserWithThrow(name, userType, 0,
-                    mUserId, disallowedPackages).getUserHandle();
+                    mUserId, disallowedPackages.toArray(
+                            new String[disallowedPackages.size()])).getUserHandle();
         } catch (ServiceSpecificException e) {
             return returnNullOrThrowUserOperationException(e,
                     mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.R);
@@ -3354,19 +3356,46 @@
     }
 
     /**
-     * Returns a list of ids for profiles associated with the context user including the user
-     * itself.
+     * Returns a list of ids for enabled profiles associated with the context user including the
+     * user itself.
      *
-     * @param enabledOnly whether to return only {@link UserInfo#isEnabled() enabled} profiles
      * @return A non-empty list of UserHandles associated with the calling user.
-     *
      * @hide
      */
     @SystemApi
     @RequiresPermission(anyOf = {Manifest.permission.MANAGE_USERS,
             Manifest.permission.CREATE_USERS}, conditional = true)
     @UserHandleAware
-    public @NonNull List<UserHandle> getUserProfiles(boolean enabledOnly) {
+    public @NonNull List<UserHandle> getEnabledProfiles() {
+        return getProfiles(true);
+    }
+
+    /**
+     * Returns a list of ids for all profiles associated with the context user including the user
+     * itself.
+     *
+     * @return A non-empty list of UserHandles associated with the calling user.
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(anyOf = {Manifest.permission.MANAGE_USERS,
+            Manifest.permission.CREATE_USERS}, conditional = true)
+    @UserHandleAware
+    public @NonNull List<UserHandle> getAllProfiles() {
+        return getProfiles(false);
+    }
+
+    /**
+     * Returns a list of ids for profiles associated with the context user including the user
+     * itself.
+     *
+     * @param enabledOnly whether to return only {@link UserInfo#isEnabled() enabled} profiles
+     * @return A non-empty list of UserHandles associated with the calling user.
+     */
+    @RequiresPermission(anyOf = {Manifest.permission.MANAGE_USERS,
+            Manifest.permission.CREATE_USERS}, conditional = true)
+    @UserHandleAware
+    private @NonNull List<UserHandle> getProfiles(boolean enabledOnly) {
         final int[] userIds = getProfileIds(mUserId, enabledOnly);
         final List<UserHandle> result = new ArrayList<>(userIds.length);
         for (int userId : userIds) {
diff --git a/core/java/android/os/incremental/IncrementalStorage.java b/core/java/android/os/incremental/IncrementalStorage.java
index f4e1f96..dea495b 100644
--- a/core/java/android/os/incremental/IncrementalStorage.java
+++ b/core/java/android/os/incremental/IncrementalStorage.java
@@ -434,6 +434,11 @@
             signature = V4Signature.readFrom(input);
         }
 
+        if (!signature.isVersionSupported()) {
+            throw new IOException("v4 signature version " + signature.version
+                    + " is not supported");
+        }
+
         final byte[] rootHash = signature.verityRootHash;
         final byte[] additionalData = signature.v3Digest;
         final byte[] pkcs7Signature = signature.pkcs7SignatureBlock;
diff --git a/core/java/android/os/incremental/V4Signature.java b/core/java/android/os/incremental/V4Signature.java
index 6516917..17adfc8 100644
--- a/core/java/android/os/incremental/V4Signature.java
+++ b/core/java/android/os/incremental/V4Signature.java
@@ -31,7 +31,9 @@
  */
 public class V4Signature {
     public static final String EXT = ".idsig";
+    public static final int SUPPORTED_VERSION = 1;
 
+    public final int version;
     public final byte[] verityRootHash;
     public final byte[] v3Digest;
     public final byte[] pkcs7SignatureBlock;
@@ -71,20 +73,27 @@
         }
     }
 
+    boolean isVersionSupported() {
+        return this.version == SUPPORTED_VERSION;
+    }
+
     static V4Signature readFrom(DataInputStream stream) throws IOException {
+        final int version = stream.readInt();
         byte[] verityRootHash = readBytes(stream);
         byte[] v3Digest = readBytes(stream);
         byte[] pkcs7SignatureBlock = readBytes(stream);
-        return new V4Signature(verityRootHash, v3Digest, pkcs7SignatureBlock);
+        return new V4Signature(version, verityRootHash, v3Digest, pkcs7SignatureBlock);
     }
 
-    V4Signature(byte[] verityRootHash, byte[] v3Digest, byte[] pkcs7SignatureBlock) {
+    V4Signature(int version, byte[] verityRootHash, byte[] v3Digest, byte[] pkcs7SignatureBlock) {
+        this.version = version;
         this.verityRootHash = verityRootHash;
         this.v3Digest = v3Digest;
         this.pkcs7SignatureBlock = pkcs7SignatureBlock;
     }
 
     void writeTo(DataOutputStream stream) throws IOException {
+        stream.writeInt(this.version);
         writeBytes(stream, this.verityRootHash);
         writeBytes(stream, this.v3Digest);
         writeBytes(stream, this.pkcs7SignatureBlock);
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 8d04df0..1454aac 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -29,6 +29,7 @@
 import static android.app.AppOpsManager.OP_WRITE_MEDIA_VIDEO;
 import static android.content.ContentResolver.DEPRECATE_DATA_PREFIX;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.os.UserHandle.PER_USER_RANGE;
 
 import android.annotation.BytesLong;
 import android.annotation.CallbackExecutor;
@@ -2324,17 +2325,34 @@
     private static final String XATTR_CACHE_TOMBSTONE = "user.cache_tombstone";
 
 
-   // Matches AID_MEDIA_RW in android_filesystem_config.h
-    private static final int QUOTA_PROJECT_ID_MEDIA_NONE = 1023;
+    // Project IDs below must match android_projectid_config.h
+    /**
+     * Default project ID for files on external storage
+     *
+     * {@hide}
+     */
+    public static final int PROJECT_ID_EXT_DEFAULT = 1000;
 
-    // Matches AID_MEDIA_IMAGE in android_filesystem_config.h
-    private static final int QUOTA_PROJECT_ID_MEDIA_IMAGE = 1057;
+    /**
+     * project ID for audio files on external storage
+     *
+     * {@hide}
+     */
+    public static final int PROJECT_ID_EXT_MEDIA_AUDIO = 1001;
 
-    // Matches AID_MEDIA_AUDIO in android_filesystem_config.h
-    private static final int QUOTA_PROJECT_ID_MEDIA_AUDIO = 1055;
+    /**
+     * project ID for video files on external storage
+     *
+     * {@hide}
+     */
+    public static final int PROJECT_ID_EXT_MEDIA_VIDEO = 1002;
 
-    // Matches AID_MEDIA_VIDEO in android_filesystem_config.h
-    private static final int QUOTA_PROJECT_ID_MEDIA_VIDEO = 1056;
+    /**
+     * project ID for image files on external storage
+     *
+     * {@hide}
+     */
+    public static final int PROJECT_ID_EXT_MEDIA_IMAGE = 1003;
 
     /**
      * Constant for use with
@@ -2388,6 +2406,11 @@
 
     private static native boolean setQuotaProjectId(String path, long projectId);
 
+    private static long getProjectIdForUser(int userId, int projectId) {
+        // Much like UserHandle.getUid(), store the user ID in the upper bits
+        return userId * PER_USER_RANGE + projectId;
+    }
+
     /**
      * Let StorageManager know that the quota type for a file on external storage should
      * be updated. Android tracks quotas for various media types. Consequently, this should be
@@ -2417,18 +2440,27 @@
             @QuotaType int quotaType) throws IOException {
         long projectId;
         final String filePath = path.getCanonicalPath();
+        final StorageVolume volume = getStorageVolume(path);
+        if (volume == null) {
+            throw new IllegalStateException("Failed to update quota type for " + filePath);
+        }
+
+        final int userId = volume.getOwner().getIdentifier();
+        if (userId < 0) {
+            throw new IllegalStateException("Failed to update quota type for " + filePath);
+        }
         switch (quotaType) {
             case QUOTA_TYPE_MEDIA_NONE:
-                projectId = QUOTA_PROJECT_ID_MEDIA_NONE;
+                projectId = getProjectIdForUser(userId, PROJECT_ID_EXT_DEFAULT);
                 break;
             case QUOTA_TYPE_MEDIA_AUDIO:
-                projectId = QUOTA_PROJECT_ID_MEDIA_AUDIO;
+                projectId = getProjectIdForUser(userId, PROJECT_ID_EXT_MEDIA_AUDIO);
                 break;
             case QUOTA_TYPE_MEDIA_VIDEO:
-                projectId = QUOTA_PROJECT_ID_MEDIA_VIDEO;
+                projectId = getProjectIdForUser(userId, PROJECT_ID_EXT_MEDIA_VIDEO);
                 break;
             case QUOTA_TYPE_MEDIA_IMAGE:
-                projectId = QUOTA_PROJECT_ID_MEDIA_IMAGE;
+                projectId = getProjectIdForUser(userId, PROJECT_ID_EXT_MEDIA_IMAGE);
                 break;
             default:
                 throw new IllegalArgumentException("Invalid quota type: " + quotaType);
diff --git a/core/java/android/os/strictmode/IncorrectContextUseViolation.java b/core/java/android/os/strictmode/IncorrectContextUseViolation.java
new file mode 100644
index 0000000..647db17
--- /dev/null
+++ b/core/java/android/os/strictmode/IncorrectContextUseViolation.java
@@ -0,0 +1,35 @@
+/*
+ * 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.os.strictmode;
+
+import android.content.Context;
+
+/**
+ * Incorrect usage of {@link Context}, such as obtaining a visual service from non-visual
+ * {@link Context} instance.
+ * @see Context#getSystemService(String)
+ * @see Context#getDisplayNoVerify()
+ * @hide
+ */
+public final class IncorrectContextUseViolation extends Violation {
+
+    /** @hide */
+    public IncorrectContextUseViolation(String message, Throwable originStack) {
+        super(message);
+        initCause(originStack);
+    }
+}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 9511152..b898271 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -9275,11 +9275,17 @@
         public static final String CUSTOM_BUGREPORT_HANDLER_USER = "custom_bugreport_handler_user";
 
         /**
-         * Whether ADB is enabled.
+         * Whether ADB over USB is enabled.
          */
         public static final String ADB_ENABLED = "adb_enabled";
 
         /**
+         * Whether ADB over Wifi is enabled.
+         * @hide
+         */
+        public static final String ADB_WIFI_ENABLED = "adb_wifi_enabled";
+
+        /**
          * Whether Views are allowed to save their attribute data.
          * @hide
          */
@@ -11509,6 +11515,7 @@
          * exempted_sync_duration           (long)
          * system_interaction_duration      (long)
          * initial_foreground_service_start_duration (long)
+         * cross_profile_apps_share_standby_buckets  (boolean)
          * </pre>
          *
          * <p>
@@ -14325,7 +14332,6 @@
          *
          * @hide
          */
-        @SystemApi
         @RequiresPermission(Manifest.permission.MONITOR_DEVICE_CONFIG_ACCESS)
         public static void registerMonitorCallback(@NonNull ContentResolver resolver,
                 @NonNull RemoteCallback callback) {
diff --git a/core/java/android/service/autofill/InlineSuggestionRenderService.java b/core/java/android/service/autofill/InlineSuggestionRenderService.java
index 4aafb63..29069e7 100644
--- a/core/java/android/service/autofill/InlineSuggestionRenderService.java
+++ b/core/java/android/service/autofill/InlineSuggestionRenderService.java
@@ -25,6 +25,7 @@
 import android.app.slice.Slice;
 import android.content.Intent;
 import android.graphics.PixelFormat;
+import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
@@ -118,6 +119,14 @@
     }
 
     /**
+     *  Returns the metadata about the renderer. Returns {@code null} if no metadata is provided.
+     */
+    @Nullable
+    public Bundle onGetInlineSuggestionsRendererInfo() {
+        return null;
+    }
+
+    /**
      * Renders the slice into a view.
      */
     @Nullable
diff --git a/core/java/android/service/controls/ControlsProviderService.java b/core/java/android/service/controls/ControlsProviderService.java
index cb20db9..b23d0cd 100644
--- a/core/java/android/service/controls/ControlsProviderService.java
+++ b/core/java/android/service/controls/ControlsProviderService.java
@@ -15,11 +15,14 @@
  */
 package android.service.controls;
 
+import android.Manifest;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
 import android.app.Service;
+import android.content.ComponentName;
+import android.content.Context;
 import android.content.Intent;
 import android.os.Bundle;
 import android.os.Handler;
@@ -51,6 +54,20 @@
     @SdkConstant(SdkConstantType.SERVICE_ACTION)
     public static final String SERVICE_CONTROLS =
             "android.service.controls.ControlsProviderService";
+
+    /**
+     * @hide
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_ADD_CONTROL =
+            "android.service.controls.action.ADD_CONTROL";
+
+    /**
+     * @hide
+     */
+    public static final String EXTRA_CONTROL =
+            "android.service.controls.extra.CONTROL";
+
     /**
      * @hide
      */
@@ -325,6 +342,33 @@
         }
     }
 
+    /**
+     * Request SystemUI to prompt the user to add a control to favorites.
+     *
+     * @param context A context
+     * @param componentName Component name of the {@link ControlsProviderService}
+     * @param control A stateless control to show to the user
+     */
+    public static void requestAddControl(@NonNull Context context,
+            @NonNull ComponentName componentName,
+            @NonNull Control control) {
+        Preconditions.checkNotNull(context);
+        Preconditions.checkNotNull(componentName);
+        Preconditions.checkNotNull(control);
+        final ComponentName sysuiComponent = ComponentName.unflattenFromString(
+                context.getResources().getString(
+                        com.android.internal.R.string.config_systemUIServiceComponent));
+        Intent intent = new Intent(ACTION_ADD_CONTROL);
+        intent.putExtra(Intent.EXTRA_COMPONENT_NAME, componentName);
+        intent.setPackage(sysuiComponent.getPackageName());
+        if (isStatelessControl(control)) {
+            intent.putExtra(EXTRA_CONTROL, control);
+        } else {
+            intent.putExtra(EXTRA_CONTROL, new Control.StatelessBuilder(control).build());
+        }
+        context.sendBroadcast(intent, Manifest.permission.BIND_CONTROLS);
+    }
+
     private static class SubscriptionAdapter extends IControlsSubscription.Stub {
         final Subscription mSubscription;
 
diff --git a/core/java/android/util/EventLog.java b/core/java/android/util/EventLog.java
index c9dc05b..ead4e46 100644
--- a/core/java/android/util/EventLog.java
+++ b/core/java/android/util/EventLog.java
@@ -16,6 +16,8 @@
 
 package android.util;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.compat.annotation.UnsupportedAppUsage;
 
@@ -62,7 +64,7 @@
         private Exception mLastWtf;
 
         // Layout of event log entry received from Android logger.
-        //  see system/core/include/log/log.h
+        //  see system/core/liblog/include/log/log_read.h
         private static final int LENGTH_OFFSET = 0;
         private static final int HEADER_SIZE_OFFSET = 2;
         private static final int PROCESS_OFFSET = 4;
@@ -73,7 +75,7 @@
 
         // Layout for event log v1 format, v2 and v3 use HEADER_SIZE_OFFSET
         private static final int V1_PAYLOAD_START = 20;
-        private static final int DATA_OFFSET = 4;
+        private static final int TAG_LENGTH = 4;
 
         // Value types
         private static final byte INT_TYPE    = 0;
@@ -121,26 +123,26 @@
 
         /** @return the type tag code of the entry */
         public int getTag() {
-            int offset = mBuffer.getShort(HEADER_SIZE_OFFSET);
-            if (offset == 0) {
-                offset = V1_PAYLOAD_START;
-            }
-            return mBuffer.getInt(offset);
+            return mBuffer.getInt(getHeaderSize());
         }
 
+        private int getHeaderSize() {
+            int length = mBuffer.getShort(HEADER_SIZE_OFFSET);
+            if (length != 0) {
+                return length;
+            }
+            return V1_PAYLOAD_START;
+        }
         /** @return one of Integer, Long, Float, String, null, or Object[] of same. */
         public synchronized Object getData() {
             try {
-                int offset = mBuffer.getShort(HEADER_SIZE_OFFSET);
-                if (offset == 0) {
-                    offset = V1_PAYLOAD_START;
-                }
+                int offset = getHeaderSize();
                 mBuffer.limit(offset + mBuffer.getShort(LENGTH_OFFSET));
-                if ((offset + DATA_OFFSET) >= mBuffer.limit()) {
+                if ((offset + TAG_LENGTH) >= mBuffer.limit()) {
                     // no payload
                     return null;
                 }
-                mBuffer.position(offset + DATA_OFFSET); // Just after the tag.
+                mBuffer.position(offset + TAG_LENGTH); // Just after the tag.
                 return decodeObject();
             } catch (IllegalArgumentException e) {
                 Log.wtf(TAG, "Illegal entry payload: tag=" + getTag(), e);
@@ -153,6 +155,28 @@
             }
         }
 
+        /**
+         * Construct a new EventLog object from the current object, copying all log metadata
+         * but replacing the actual payload with the content provided.
+         * @hide
+         */
+        public Event withNewData(@Nullable Object object) {
+            byte[] payload = encodeObject(object);
+            if (payload.length > 65535 - TAG_LENGTH) {
+                throw new IllegalArgumentException("Payload too long");
+            }
+            int headerLength = getHeaderSize();
+            byte[] newBytes = new byte[headerLength + TAG_LENGTH + payload.length];
+            // Copy header (including the 4 bytes of tag integer at the beginning of payload)
+            System.arraycopy(mBuffer.array(), 0, newBytes, 0, headerLength + TAG_LENGTH);
+            // Fill in encoded objects
+            System.arraycopy(payload, 0, newBytes, headerLength + TAG_LENGTH, payload.length);
+            Event result = new Event(newBytes);
+            // Patch payload length in header
+            result.mBuffer.putShort(LENGTH_OFFSET, (short) (payload.length + TAG_LENGTH));
+            return result;
+        }
+
         /** @return the loggable item at the current position in mBuffer. */
         private Object decodeObject() {
             byte type = mBuffer.get();
@@ -190,6 +214,66 @@
             }
         }
 
+        private static @NonNull byte[] encodeObject(@Nullable Object object) {
+            if (object == null) {
+                return new byte[0];
+            }
+            if (object instanceof Integer) {
+                return ByteBuffer.allocate(1 + 4)
+                        .order(ByteOrder.nativeOrder())
+                        .put(INT_TYPE)
+                        .putInt((Integer) object)
+                        .array();
+            } else if (object instanceof Long) {
+                return ByteBuffer.allocate(1 + 8)
+                        .order(ByteOrder.nativeOrder())
+                        .put(LONG_TYPE)
+                        .putLong((Long) object)
+                        .array();
+            } else if (object instanceof Float) {
+                return ByteBuffer.allocate(1 + 4)
+                        .order(ByteOrder.nativeOrder())
+                        .put(FLOAT_TYPE)
+                        .putFloat((Float) object)
+                        .array();
+            } else if (object instanceof String) {
+                String string = (String) object;
+                byte[] bytes;
+                try {
+                    bytes = string.getBytes("UTF-8");
+                } catch (UnsupportedEncodingException e) {
+                    bytes = new byte[0];
+                }
+                return ByteBuffer.allocate(1 + 4 + bytes.length)
+                         .order(ByteOrder.nativeOrder())
+                         .put(STRING_TYPE)
+                         .putInt(bytes.length)
+                         .put(bytes)
+                         .array();
+            } else if (object instanceof Object[]) {
+                Object[] objects = (Object[]) object;
+                if (objects.length > 255) {
+                    throw new IllegalArgumentException("Object array too long");
+                }
+                byte[][] bytes = new byte[objects.length][];
+                int totalLength = 0;
+                for (int i = 0; i < objects.length; i++) {
+                    bytes[i] = encodeObject(objects[i]);
+                    totalLength += bytes[i].length;
+                }
+                ByteBuffer buffer = ByteBuffer.allocate(1 + 1 + totalLength)
+                        .order(ByteOrder.nativeOrder())
+                        .put(LIST_TYPE)
+                        .put((byte) objects.length);
+                for (int i = 0; i < objects.length; i++) {
+                    buffer.put(bytes[i]);
+                }
+                return buffer.array();
+            } else {
+                throw new IllegalArgumentException("Unknown object type " + object);
+            }
+        }
+
         /** @hide */
         public static Event fromBytes(byte[] data) {
             return new Event(data);
diff --git a/core/java/android/util/LongSparseArray.java b/core/java/android/util/LongSparseArray.java
index 73e17a6..55542d8 100644
--- a/core/java/android/util/LongSparseArray.java
+++ b/core/java/android/util/LongSparseArray.java
@@ -16,15 +16,18 @@
 
 package android.util;
 
+import android.annotation.NonNull;
 import android.os.Parcel;
 
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.GrowingArrayUtils;
 import com.android.internal.util.Preconditions;
+import com.android.internal.util.function.LongObjPredicate;
 
 import libcore.util.EmptyArray;
 
 import java.util.Arrays;
+import java.util.Objects;
 
 /**
  * SparseArray mapping longs to Objects.  Unlike a normal array of Objects,
@@ -145,6 +148,18 @@
         delete(key);
     }
 
+    /** @hide */
+    @SuppressWarnings("unchecked")
+    public void removeIf(@NonNull LongObjPredicate<? super E> filter) {
+        Objects.requireNonNull(filter);
+        for (int i = 0; i < mSize; ++i) {
+            if (mValues[i] != DELETED && filter.test(mKeys[i], (E) mValues[i])) {
+                mValues[i] = DELETED;
+                mGarbage = true;
+            }
+        }
+    }
+
     /**
      * Removes the mapping at the specified index.
      *
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index deff79d5..73707ca 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -1586,6 +1586,19 @@
         info.addChild(wrapper.getLeashToken());
     }
 
+    @Override
+    public int getImportantForAccessibility() {
+        final int mode = super.getImportantForAccessibility();
+        // If developers explicitly set the important mode for it, don't change the mode.
+        // Only change the mode to important when this SurfaceView isn't explicitly set and has
+        // an embedded hierarchy.
+        if (mRemoteAccessibilityEmbeddedConnection == null
+                || mode != IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
+            return mode;
+        }
+        return IMPORTANT_FOR_ACCESSIBILITY_YES;
+    }
+
     private void initEmbeddedHierarchyForAccessibility(SurfaceControlViewHost.SurfacePackage p) {
         final IAccessibilityEmbeddedConnection connection = p.getAccessibilityEmbeddedConnection();
         final RemoteAccessibilityEmbeddedConnection wrapper =
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 4c7307e..11ab572 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -13442,8 +13442,7 @@
      * @see #getImportantForAccessibility()
      */
     public boolean isImportantForAccessibility() {
-        final int mode = (mPrivateFlags2 & PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK)
-                >> PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT;
+        final int mode = getImportantForAccessibility();
         if (mode == IMPORTANT_FOR_ACCESSIBILITY_NO
                 || mode == IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS) {
             return false;
diff --git a/core/java/android/view/WindowContainerTransaction.java b/core/java/android/view/WindowContainerTransaction.java
index cf34b0b..f406be9 100644
--- a/core/java/android/view/WindowContainerTransaction.java
+++ b/core/java/android/view/WindowContainerTransaction.java
@@ -26,6 +26,7 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.ArrayMap;
+import android.view.SurfaceControl;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -77,8 +78,28 @@
     public WindowContainerTransaction scheduleFinishEnterPip(IWindowContainer container,
             Rect bounds) {
         Change chg = getOrCreateChange(container.asBinder());
-        chg.mSchedulePipCallback = true;
         chg.mPinnedBounds = new Rect(bounds);
+        chg.mChangeMask |= Change.CHANGE_PIP_CALLBACK;
+
+        return this;
+    }
+
+    /**
+     * Send a SurfaceControl transaction to the server, which the server will apply in sync with
+     * the next bounds change. As this uses deferred transaction and not BLAST it is only
+     * able to sync with a single window, and the first visible window in this hierarchy of type
+     * BASE_APPLICATION to resize will be used. If there are bound changes included in this
+     * WindowContainer transaction (from setBounds or scheduleFinishEnterPip), the SurfaceControl
+     * transaction will be synced with those bounds. If there are no changes, then
+     * the SurfaceControl transaction will be synced with the next bounds change. This means
+     * that you can call this, apply the WindowContainer transaction, and then later call
+     * dismissPip() to achieve synchronization.
+     */
+    public WindowContainerTransaction setBoundsChangeTransaction(IWindowContainer container,
+            SurfaceControl.Transaction t) {
+        Change chg = getOrCreateChange(container.asBinder());
+        chg.mBoundsChangeTransaction = t;
+        chg.mChangeMask |= Change.CHANGE_BOUNDS_TRANSACTION;
         return this;
     }
 
@@ -174,6 +195,8 @@
      */
     public static class Change implements Parcelable {
         public static final int CHANGE_FOCUSABLE = 1;
+        public static final int CHANGE_BOUNDS_TRANSACTION = 1 << 1;
+        public static final int CHANGE_PIP_CALLBACK = 1 << 2;
 
         private final Configuration mConfiguration = new Configuration();
         private boolean mFocusable = true;
@@ -181,8 +204,8 @@
         private @ActivityInfo.Config int mConfigSetMask = 0;
         private @WindowConfiguration.WindowConfig int mWindowSetMask = 0;
 
-        private boolean mSchedulePipCallback = false;
         private Rect mPinnedBounds = null;
+        private SurfaceControl.Transaction mBoundsChangeTransaction = null;
 
         public Change() {}
 
@@ -192,11 +215,14 @@
             mChangeMask = in.readInt();
             mConfigSetMask = in.readInt();
             mWindowSetMask = in.readInt();
-            mSchedulePipCallback = (in.readInt() != 0);
-            if (mSchedulePipCallback ) {
+            if ((mChangeMask & Change.CHANGE_PIP_CALLBACK) != 0) {
                 mPinnedBounds = new Rect();
                 mPinnedBounds.readFromParcel(in);
             }
+            if ((mChangeMask & Change.CHANGE_BOUNDS_TRANSACTION) != 0) {
+                mBoundsChangeTransaction =
+                    SurfaceControl.Transaction.CREATOR.createFromParcel(in);
+            }
         }
 
         public Configuration getConfiguration() {
@@ -233,6 +259,10 @@
             return mPinnedBounds;
         }
 
+        public SurfaceControl.Transaction getBoundsChangeTransaction() {
+            return mBoundsChangeTransaction;
+        }
+
         @Override
         public String toString() {
             final boolean changesBounds =
@@ -264,10 +294,12 @@
             dest.writeInt(mConfigSetMask);
             dest.writeInt(mWindowSetMask);
 
-            dest.writeInt(mSchedulePipCallback ? 1 : 0);
-            if (mSchedulePipCallback ) {
+            if (mPinnedBounds != null) {
                 mPinnedBounds.writeToParcel(dest, flags);
             }
+            if (mBoundsChangeTransaction != null) {
+                mBoundsChangeTransaction.writeToParcel(dest, flags);
+            }
         }
 
         @Override
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index 56683dd..d40f505 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -101,7 +101,7 @@
     @Override
     public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
         applyDefaultToken(params);
-        mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
+        mGlobal.addView(view, params, mContext.getDisplayNoVerify(), mParentWindow);
         mIsViewAdded = true;
         mLastView = view;
         mLastParams = (WindowManager.LayoutParams) params;
@@ -158,7 +158,7 @@
 
     @Override
     public Display getDefaultDisplay() {
-        return mContext.getDisplay();
+        return mContext.getDisplayNoVerify();
     }
 
     @Override
@@ -240,7 +240,7 @@
     private Rect getMaximumBounds() {
         // TODO(b/128338354): Current maximum bound is display size, but it should be displayArea
         //  bound after displayArea feature is finished.
-        final Display display = mContext.getDisplay();
+        final Display display = mContext.getDisplayNoVerify();
         final Point displaySize = new Point();
         display.getRealSize(displaySize);
         return new Rect(0, 0, displaySize.x, displaySize.y);
diff --git a/core/java/android/view/accessibility/OWNERS b/core/java/android/view/accessibility/OWNERS
index 265674a..c6f42f7 100644
--- a/core/java/android/view/accessibility/OWNERS
+++ b/core/java/android/view/accessibility/OWNERS
@@ -1,3 +1,4 @@
 svetoslavganov@google.com
 pweaver@google.com
 rhedjao@google.com
+qasid@google.com
diff --git a/core/java/android/view/inline/InlinePresentationSpec.java b/core/java/android/view/inline/InlinePresentationSpec.java
index 8bda339..3cc04b8 100644
--- a/core/java/android/view/inline/InlinePresentationSpec.java
+++ b/core/java/android/view/inline/InlinePresentationSpec.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.os.Bundle;
 import android.os.Parcelable;
 import android.util.Size;
 
@@ -40,15 +41,13 @@
     private final Size mMaxSize;
 
     /**
-     * The fully qualified resource name of the UI style resource identifier, defaults to {@code
-     * null}.
-     *
-     * <p> The value can be obtained by calling {@code Resources#getResourceName(int)}.
+     * The extras encoding the UI style information. Defaults to {@code null} in which case the
+     * default system UI style will be used.
      */
     @Nullable
-    private final String mStyle;
+    private final Bundle mStyle;
 
-    private static String defaultStyle() {
+    private static Bundle defaultStyle() {
         return null;
     }
 
@@ -76,7 +75,7 @@
     /* package-private */ InlinePresentationSpec(
             @NonNull Size minSize,
             @NonNull Size maxSize,
-            @Nullable String style) {
+            @Nullable Bundle style) {
         this.mMinSize = minSize;
         com.android.internal.util.AnnotationValidations.validate(
                 NonNull.class, null, mMinSize);
@@ -105,13 +104,11 @@
     }
 
     /**
-     * The fully qualified resource name of the UI style resource identifier, defaults to {@code
-     * null}.
-     *
-     * <p> The value can be obtained by calling {@code Resources#getResourceName(int)}.
+     * The extras encoding the UI style information. Defaults to null in which case the default
+     * system UI style will be used.
      */
     @DataClass.Generated.Member
-    public @Nullable String getStyle() {
+    public @Nullable Bundle getStyle() {
         return mStyle;
     }
 
@@ -170,7 +167,7 @@
         dest.writeByte(flg);
         dest.writeSize(mMinSize);
         dest.writeSize(mMaxSize);
-        if (mStyle != null) dest.writeString(mStyle);
+        if (mStyle != null) dest.writeBundle(mStyle);
     }
 
     @Override
@@ -187,7 +184,7 @@
         byte flg = in.readByte();
         Size minSize = (Size) in.readSize();
         Size maxSize = (Size) in.readSize();
-        String style = (flg & 0x4) == 0 ? null : in.readString();
+        Bundle style = (flg & 0x4) == 0 ? null : in.readBundle();
 
         this.mMinSize = minSize;
         com.android.internal.util.AnnotationValidations.validate(
@@ -223,7 +220,7 @@
 
         private @NonNull Size mMinSize;
         private @NonNull Size mMaxSize;
-        private @Nullable String mStyle;
+        private @Nullable Bundle mStyle;
 
         private long mBuilderFieldsSet = 0L;
 
@@ -247,13 +244,11 @@
         }
 
         /**
-         * The fully qualified resource name of the UI style resource identifier, defaults to {@code
-         * null}.
-         *
-         * <p> The value can be obtained by calling {@code Resources#getResourceName(int)}.
+         * The extras encoding the UI style information. Defaults to null in which case the default
+         * system UI style will be used.
          */
         @DataClass.Generated.Member
-        public @NonNull Builder setStyle(@Nullable String value) {
+        public @NonNull Builder setStyle(@Nullable Bundle value) {
             checkNotUsed();
             mBuilderFieldsSet |= 0x4;
             mStyle = value;
@@ -284,10 +279,10 @@
     }
 
     @DataClass.Generated(
-            time = 1581736227796L,
+            time = 1582078731418L,
             codegenVersion = "1.0.14",
             sourceFile = "frameworks/base/core/java/android/view/inline/InlinePresentationSpec.java",
-            inputSignatures = "private final @android.annotation.NonNull android.util.Size mMinSize\nprivate final @android.annotation.NonNull android.util.Size mMaxSize\nprivate final @android.annotation.Nullable java.lang.String mStyle\nprivate static  java.lang.String defaultStyle()\nclass InlinePresentationSpec extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true, genBuilder=true)\nclass BaseBuilder extends java.lang.Object implements []")
+            inputSignatures = "private final @android.annotation.NonNull android.util.Size mMinSize\nprivate final @android.annotation.NonNull android.util.Size mMaxSize\nprivate final @android.annotation.Nullable android.os.Bundle mStyle\nprivate static  android.os.Bundle defaultStyle()\nclass InlinePresentationSpec extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true, genBuilder=true)\nclass BaseBuilder extends java.lang.Object implements []")
     @Deprecated
     private void __metadata() {}
 
diff --git a/core/java/android/view/inputmethod/InputMethod.java b/core/java/android/view/inputmethod/InputMethod.java
index 91e15c1..71c9e33 100644
--- a/core/java/android/view/inputmethod/InputMethod.java
+++ b/core/java/android/view/inputmethod/InputMethod.java
@@ -21,17 +21,16 @@
 import android.annotation.Nullable;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
-import android.content.ComponentName;
 import android.inputmethodservice.InputMethodService;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.ResultReceiver;
 import android.util.Log;
 import android.view.View;
-import android.view.autofill.AutofillId;
 
 import com.android.internal.inputmethod.IInputMethodPrivilegedOperations;
 import com.android.internal.view.IInlineSuggestionsRequestCallback;
+import com.android.internal.view.InlineSuggestionsRequestInfo;
 
 /**
  * The InputMethod interface represents an input method which can generate key
@@ -114,14 +113,13 @@
     /**
      * Called to notify the IME that Autofill Frameworks requested an inline suggestions request.
      *
-     * @param componentName {@link ComponentName} of current app/activity.
-     * @param autofillId {@link AutofillId} of currently focused field.
+     * @param requestInfo information needed to create an {@link InlineSuggestionsRequest}.
      * @param cb {@link IInlineSuggestionsRequestCallback} used to pass back the request object.
      *
      * @hide
      */
-    default void onCreateInlineSuggestionsRequest(ComponentName componentName,
-            AutofillId autofillId, IInlineSuggestionsRequestCallback cb) {
+    default void onCreateInlineSuggestionsRequest(InlineSuggestionsRequestInfo requestInfo,
+            IInlineSuggestionsRequestCallback cb) {
         try {
             cb.onInlineSuggestionsUnsupported();
         } catch (RemoteException e) {
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index dbab81b1..39d5f5c 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -93,12 +93,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
-import java.util.concurrent.CancellationException;
 import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.Future;
 import java.util.concurrent.ThreadFactory;
 import java.util.concurrent.TimeUnit;
 
@@ -415,16 +410,6 @@
     int mCursorCandEnd;
 
     /**
-     * Initial startInput with {@link StartInputReason.WINDOW_FOCUS_GAIN} is executed
-     * in a background thread. Later, if there is an actual startInput it will wait on
-     * main thread till the background thread completes.
-     */
-    private Future<?> mWindowFocusGainFuture;
-
-    private ExecutorService mStartInputWorker = Executors.newSingleThreadExecutor(
-            new ImeThreadFactory("StartInputWorker"));
-
-    /**
      * The instance that has previously been sent to the input method.
      */
     private CursorAnchorInfo mCursorAnchorInfo = null;
@@ -612,41 +597,36 @@
             final boolean forceNewFocus1 = forceNewFocus;
             final int startInputFlags = getStartInputFlags(focusedView, 0);
 
-            if (mWindowFocusGainFuture != null) {
-                mWindowFocusGainFuture.cancel(false /* mayInterruptIfRunning */);
+            final ImeFocusController controller = getFocusController();
+            if (controller == null) {
+                return;
             }
-            mWindowFocusGainFuture = mStartInputWorker.submit(() -> {
-                final ImeFocusController controller = getFocusController();
-                if (controller == null) {
+            if (controller.checkFocus(forceNewFocus1, false)) {
+                // We need to restart input on the current focus view.  This
+                // should be done in conjunction with telling the system service
+                // about the window gaining focus, to help make the transition
+                // smooth.
+                if (startInput(StartInputReason.WINDOW_FOCUS_GAIN,
+                        focusedView, startInputFlags, softInputMode, windowFlags)) {
                     return;
                 }
-                if (controller.checkFocus(forceNewFocus1, false)) {
-                    // We need to restart input on the current focus view.  This
-                    // should be done in conjunction with telling the system service
-                    // about the window gaining focus, to help make the transition
-                    // smooth.
-                    if (startInput(StartInputReason.WINDOW_FOCUS_GAIN,
-                            focusedView, startInputFlags, softInputMode, windowFlags)) {
-                        return;
-                    }
-                }
+            }
 
-                synchronized (mH) {
-                    // For some reason we didn't do a startInput + windowFocusGain, so
-                    // we'll just do a window focus gain and call it a day.
-                    try {
-                        if (DEBUG) Log.v(TAG, "Reporting focus gain, without startInput");
-                        mService.startInputOrWindowGainedFocus(
-                                StartInputReason.WINDOW_FOCUS_GAIN_REPORT_ONLY, mClient,
-                                focusedView.getWindowToken(), startInputFlags, softInputMode,
-                                windowFlags,
-                                null, null, 0 /* missingMethodFlags */,
-                                mCurRootView.mContext.getApplicationInfo().targetSdkVersion);
-                    } catch (RemoteException e) {
-                        throw e.rethrowFromSystemServer();
-                    }
+            synchronized (mH) {
+                // For some reason we didn't do a startInput + windowFocusGain, so
+                // we'll just do a window focus gain and call it a day.
+                try {
+                    if (DEBUG) Log.v(TAG, "Reporting focus gain, without startInput");
+                    mService.startInputOrWindowGainedFocus(
+                            StartInputReason.WINDOW_FOCUS_GAIN_REPORT_ONLY, mClient,
+                            focusedView.getWindowToken(), startInputFlags, softInputMode,
+                            windowFlags,
+                            null, null, 0 /* missingMethodFlags */,
+                            mCurRootView.mContext.getApplicationInfo().targetSdkVersion);
+                } catch (RemoteException e) {
+                    throw e.rethrowFromSystemServer();
                 }
-            });
+            }
         }
 
         /**
@@ -664,10 +644,6 @@
          */
         @Override
         public void setCurrentRootView(ViewRootImpl rootView) {
-            if (mWindowFocusGainFuture != null) {
-                mWindowFocusGainFuture.cancel(false /* mayInterruptIfRunning */);
-                mWindowFocusGainFuture = null;
-            }
             synchronized (mH) {
                 if (mCurRootView != null) {
                     // Reset the last served view and restart window focus state of the root view.
@@ -845,19 +821,16 @@
                             } catch (RemoteException e) {
                             }
                         }
-                    }
-                    // Check focus again in case that "onWindowFocus" is called before
-                    // handling this message.
-                    final View servedView;
-                    synchronized (mH) {
-                        servedView = getServedViewLocked();
-                    }
-                    if (servedView != null && canStartInput(servedView)) {
-                        if (mCurRootView != null && mCurRootView.getImeFocusController()
-                                .checkFocus(mRestartOnNextWindowFocus, false)) {
-                            final int reason = active ? StartInputReason.ACTIVATED_BY_IMMS
-                                    : StartInputReason.DEACTIVATED_BY_IMMS;
-                            mDelegate.startInput(reason, null, 0, 0, 0);
+                        // Check focus again in case that "onWindowFocus" is called before
+                        // handling this message.
+                        final View servedView = getServedViewLocked();
+                        if (servedView != null && canStartInput(servedView)) {
+                            if (mCurRootView != null && mCurRootView.getImeFocusController()
+                                    .checkFocus(mRestartOnNextWindowFocus, false)) {
+                                final int reason = active ? StartInputReason.ACTIVATED_BY_IMMS
+                                        : StartInputReason.DEACTIVATED_BY_IMMS;
+                                mDelegate.startInput(reason, null, 0, 0, 0);
+                            }
                         }
                     }
                     return;
@@ -1035,6 +1008,13 @@
         }
 
         @Override
+        public void scheduleStartInputIfNecessary(boolean fullscreen) {
+            // TODO(b/149859205): See if we can optimize this by having a fused dedicated operation.
+            mH.obtainMessage(MSG_SET_ACTIVE, 0 /* active */, fullscreen ? 1 : 0).sendToTarget();
+            mH.obtainMessage(MSG_SET_ACTIVE, 1 /* active */, fullscreen ? 1 : 0).sendToTarget();
+        }
+
+        @Override
         public void reportFullscreenMode(boolean fullscreen) {
             mH.obtainMessage(MSG_REPORT_FULLSCREEN_MODE, fullscreen ? 1 : 0, 0)
                     .sendToTarget();
@@ -1430,10 +1410,6 @@
      */
     void clearBindingLocked() {
         if (DEBUG) Log.v(TAG, "Clearing binding!");
-        if (mWindowFocusGainFuture != null) {
-            mWindowFocusGainFuture.cancel(false /* mayInterruptIfRunning */);
-            mWindowFocusGainFuture = null;
-        }
         clearConnectionLocked();
         setInputChannelLocked(null);
         mBindSequence = -1;
@@ -1826,18 +1802,6 @@
     boolean startInputInner(@StartInputReason int startInputReason,
             @Nullable IBinder windowGainingFocus, @StartInputFlags int startInputFlags,
             @SoftInputModeFlags int softInputMode, int windowFlags) {
-        if (startInputReason != StartInputReason.WINDOW_FOCUS_GAIN
-                && mWindowFocusGainFuture != null) {
-            try {
-                mWindowFocusGainFuture.get();
-            } catch (ExecutionException | InterruptedException e) {
-                // do nothing
-            } catch (CancellationException e) {
-                // window no longer has focus.
-                return true;
-            }
-        }
-
         final View view;
         synchronized (mH) {
             view = getServedViewLocked();
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 9de1222..13c1f67 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -83,6 +83,7 @@
 import android.util.DisplayMetrics;
 import android.util.Log;
 import android.util.SparseArray;
+import android.util.TypedValue;
 import android.view.ActionMode;
 import android.view.ActionMode.Callback;
 import android.view.ContextMenu;
@@ -151,9 +152,6 @@
     private static final String TAG = "Editor";
     private static final boolean DEBUG_UNDO = false;
 
-    // Specifies whether to allow starting a cursor drag by dragging anywhere over the text.
-    @VisibleForTesting
-    public static boolean FLAG_ENABLE_CURSOR_DRAG = true;
     // Specifies whether to use the magnifier when pressing the insertion or selection handles.
     private static final boolean FLAG_USE_MAGNIFIER = true;
 
@@ -387,13 +385,25 @@
 
     private final SuggestionHelper mSuggestionHelper = new SuggestionHelper();
 
-    // Specifies whether the cursor control feature set is enabled.
-    // This can only be true if the text view is editable.
-    private boolean mCursorControlEnabled;
+    private boolean mFlagCursorDragFromAnywhereEnabled;
+    private boolean mFlagInsertionHandleGesturesEnabled;
 
     // Specifies whether the new magnifier (with fish-eye effect) is enabled.
     private final boolean mNewMagnifierEnabled;
 
+    // Line height range in DP for the new magnifier.
+    static private final int MIN_LINE_HEIGHT_FOR_MAGNIFIER = 20;
+    static private final int MAX_LINE_HEIGHT_FOR_MAGNIFIER = 32;
+    // Line height range in pixels for the new magnifier.
+    //  - If the line height is bigger than the max, magnifier should be dismissed.
+    //  - If the line height is smaller than the min, magnifier should apply a bigger zoom factor
+    //    to make sure the text can be seen clearly.
+    private int mMinLineHeightForMagnifier;
+    private int mMaxLineHeightForMagnifier;
+    // The zoom factor initially configured.
+    // The actual zoom value may changes based on this initial zoom value.
+    private float mInitialZoom = 1f;
+
     Editor(TextView textView) {
         mTextView = textView;
         // Synchronize the filter list, which places the undo input filter at the end.
@@ -402,26 +412,43 @@
         mHapticTextHandleEnabled = mTextView.getContext().getResources().getBoolean(
                 com.android.internal.R.bool.config_enableHapticTextHandle);
 
-        mCursorControlEnabled = AppGlobals.getIntCoreSetting(
-                WidgetFlags.KEY_ENABLE_CURSOR_CONTROL , 0) != 0;
+        mFlagCursorDragFromAnywhereEnabled = AppGlobals.getIntCoreSetting(
+                WidgetFlags.KEY_ENABLE_CURSOR_DRAG_FROM_ANYWHERE,
+                WidgetFlags.ENABLE_CURSOR_DRAG_FROM_ANYWHERE_DEFAULT ? 1 : 0) != 0;
+        mFlagInsertionHandleGesturesEnabled = AppGlobals.getIntCoreSetting(
+                WidgetFlags.KEY_ENABLE_INSERTION_HANDLE_GESTURES,
+                WidgetFlags.ENABLE_INSERTION_HANDLE_GESTURES_DEFAULT ? 1 : 0) != 0;
         mNewMagnifierEnabled = AppGlobals.getIntCoreSetting(
-                WidgetFlags.KEY_ENABLE_NEW_MAGNIFIER, 0) != 0;
+                WidgetFlags.KEY_ENABLE_NEW_MAGNIFIER,
+                WidgetFlags.ENABLE_NEW_MAGNIFIER_DEFAULT ? 1 : 0) != 0;
         if (TextView.DEBUG_CURSOR) {
-            logCursor("Editor", "Cursor control is %s.",
-                    mCursorControlEnabled ? "enabled" : "disabled");
+            logCursor("Editor", "Cursor drag from anywhere is %s.",
+                    mFlagCursorDragFromAnywhereEnabled ? "enabled" : "disabled");
+            logCursor("Editor", "Insertion handle gestures is %s.",
+                    mFlagInsertionHandleGesturesEnabled ? "enabled" : "disabled");
             logCursor("Editor", "New magnifier is %s.",
                     mNewMagnifierEnabled ? "enabled" : "disabled");
         }
     }
 
     @VisibleForTesting
-    public void setCursorControlEnabled(boolean enabled) {
-        mCursorControlEnabled = enabled;
+    public boolean getFlagCursorDragFromAnywhereEnabled() {
+        return mFlagCursorDragFromAnywhereEnabled;
     }
 
     @VisibleForTesting
-    public boolean getCursorControlEnabled() {
-        return mCursorControlEnabled;
+    public void setFlagCursorDragFromAnywhereEnabled(boolean enabled) {
+        mFlagCursorDragFromAnywhereEnabled = enabled;
+    }
+
+    @VisibleForTesting
+    public boolean getFlagInsertionHandleGesturesEnabled() {
+        return mFlagInsertionHandleGesturesEnabled;
+    }
+
+    @VisibleForTesting
+    public void setFlagInsertionHandleGesturesEnabled(boolean enabled) {
+        mFlagInsertionHandleGesturesEnabled = enabled;
     }
 
     // Lazy creates the magnifier animator.
@@ -440,12 +467,12 @@
     private Magnifier.Builder createBuilderWithInlineMagnifierDefaults() {
         final Magnifier.Builder params = new Magnifier.Builder(mTextView);
 
-        // TODO: supports changing the height/width dynamically because the text height can be
-        // dynamically changed.
         float zoom = AppGlobals.getFloatCoreSetting(
-                WidgetFlags.KEY_MAGNIFIER_ZOOM_FACTOR, 1.5f);
+                WidgetFlags.KEY_MAGNIFIER_ZOOM_FACTOR,
+                WidgetFlags.MAGNIFIER_ZOOM_FACTOR_DEFAULT);
         float aspectRatio = AppGlobals.getFloatCoreSetting(
-                WidgetFlags.KEY_MAGNIFIER_ASPECT_RATIO, 5.5f);
+                WidgetFlags.KEY_MAGNIFIER_ASPECT_RATIO,
+                WidgetFlags.MAGNIFIER_ASPECT_RATIO_DEFAULT);
         // Avoid invalid/unsupported values.
         if (zoom < 1.2f || zoom > 1.8f) {
             zoom = 1.5f;
@@ -454,13 +481,20 @@
             aspectRatio = 5.5f;
         }
 
+        mInitialZoom = zoom;
+        mMinLineHeightForMagnifier = (int) TypedValue.applyDimension(
+                TypedValue.COMPLEX_UNIT_DIP, MIN_LINE_HEIGHT_FOR_MAGNIFIER,
+                mTextView.getContext().getResources().getDisplayMetrics());
+        mMaxLineHeightForMagnifier = (int) TypedValue.applyDimension(
+                TypedValue.COMPLEX_UNIT_DIP, MAX_LINE_HEIGHT_FOR_MAGNIFIER,
+                mTextView.getContext().getResources().getDisplayMetrics());
+
         final Layout layout = mTextView.getLayout();
         final int line = layout.getLineForOffset(mTextView.getSelectionStart());
         final int sourceHeight =
             layout.getLineBottomWithoutSpacing(line) - layout.getLineTop(line);
-        // Slightly increase the height to avoid tooLargeTextForMagnifier() returns true.
-        int height = (int)(sourceHeight * zoom) + 2;
-        int width = (int)(aspectRatio * height);
+        final int height = (int)(sourceHeight * zoom);
+        final int width = (int)(aspectRatio * Math.max(sourceHeight, mMinLineHeightForMagnifier));
 
         params.setFishEyeStyle()
                 .setSize(width, height)
@@ -4902,6 +4936,12 @@
         }
 
         private boolean tooLargeTextForMagnifier() {
+            if (mNewMagnifierEnabled) {
+                Layout layout = mTextView.getLayout();
+                final int line = layout.getLineForOffset(getCurrentCursorOffset());
+                return layout.getLineBottomWithoutSpacing(line) - layout.getLineTop(line)
+                        >= mMaxLineHeightForMagnifier;
+            }
             final float magnifierContentHeight = Math.round(
                     mMagnifierAnimator.mMagnifier.getHeight()
                             / mMagnifierAnimator.mMagnifier.getZoom());
@@ -5111,9 +5151,16 @@
                     int lineRight = (int) layout.getLineRight(line);
                     lineRight += mTextView.getTotalPaddingLeft() - mTextView.getScrollX();
                     mMagnifierAnimator.mMagnifier.setSourceHorizontalBounds(lineLeft, lineRight);
+                    final int lineHeight =
+                            layout.getLineBottomWithoutSpacing(line) - layout.getLineTop(line);
+                    float zoom = mInitialZoom;
+                    if (lineHeight < mMinLineHeightForMagnifier) {
+                        zoom = zoom * mMinLineHeightForMagnifier / lineHeight;
+                    }
+                    mMagnifierAnimator.mMagnifier.updateSourceFactors(lineHeight, zoom);
                     mMagnifierAnimator.mMagnifier.show(showPosInView.x, showPosInView.y);
                 } else {
-                  mMagnifierAnimator.show(showPosInView.x, showPosInView.y);
+                    mMagnifierAnimator.show(showPosInView.x, showPosInView.y);
                 }
                 updateHandlesVisibility();
             } else {
@@ -5259,11 +5306,13 @@
 
             int deltaHeight = 0;
             int opacity = 255;
-            if (mCursorControlEnabled) {
+            if (mFlagInsertionHandleGesturesEnabled) {
                 deltaHeight = AppGlobals.getIntCoreSetting(
-                        WidgetFlags.KEY_INSERTION_HANDLE_DELTA_HEIGHT, 25);
+                        WidgetFlags.KEY_INSERTION_HANDLE_DELTA_HEIGHT,
+                        WidgetFlags.INSERTION_HANDLE_DELTA_HEIGHT_DEFAULT);
                 opacity = AppGlobals.getIntCoreSetting(
-                        WidgetFlags.KEY_INSERTION_HANDLE_OPACITY, 50);
+                        WidgetFlags.KEY_INSERTION_HANDLE_OPACITY,
+                        WidgetFlags.INSERTION_HANDLE_OPACITY_DEFAULT);
                 // Avoid invalid/unsupported values.
                 if (deltaHeight < -25 || deltaHeight > 50) {
                     deltaHeight = 25;
@@ -5329,7 +5378,7 @@
 
         @Override
         protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-            if (mCursorControlEnabled) {
+            if (mFlagInsertionHandleGesturesEnabled) {
                 final int height = Math.max(
                         getPreferredHeight() + mDeltaHeight, mDrawable.getIntrinsicHeight());
                 setMeasuredDimension(getPreferredWidth(), height);
@@ -5340,7 +5389,7 @@
 
         @Override
         public boolean onTouchEvent(MotionEvent ev) {
-            if (mCursorControlEnabled && FLAG_ENABLE_CURSOR_DRAG) {
+            if (mFlagInsertionHandleGesturesEnabled && mFlagCursorDragFromAnywhereEnabled) {
                 // Should only enable touch through when cursor drag is enabled.
                 // Otherwise the insertion handle view cannot be moved.
                 return touchThrough(ev);
@@ -6031,7 +6080,7 @@
                     }
                     if (mIsDraggingCursor) {
                         performCursorDrag(event);
-                    } else if (FLAG_ENABLE_CURSOR_DRAG
+                    } else if (mFlagCursorDragFromAnywhereEnabled
                                 && mTextView.getLayout() != null
                                 && mTextView.isFocused()
                                 && mTouchState.isMovedEnoughForDrag()
diff --git a/core/java/android/widget/Magnifier.java b/core/java/android/widget/Magnifier.java
index 47ea1cb..a299b01 100644
--- a/core/java/android/widget/Magnifier.java
+++ b/core/java/android/widget/Magnifier.java
@@ -89,7 +89,7 @@
     // The width of the window containing the magnifier.
     private final int mWindowWidth;
     // The height of the window containing the magnifier.
-    private final int mWindowHeight;
+    private int mWindowHeight;
     // The zoom applied to the view region copied to the magnifier view.
     private float mZoom;
     // The width of the content that will be copied to the magnifier.
@@ -485,6 +485,21 @@
     }
 
     /**
+     * Updates the factors of source which may impact the magnifier's size.
+     * This can be called while the magnifier is showing and moving.
+     * @param sourceHeight the new source height.
+     * @param zoom the new zoom factor.
+     */
+    void updateSourceFactors(final int sourceHeight, final float zoom) {
+        mZoom = zoom;
+        mSourceHeight = sourceHeight;
+        mWindowHeight = (int) (sourceHeight * zoom);
+        if (mWindow != null) {
+            mWindow.updateContentFactors(mWindowHeight, zoom);
+        }
+    }
+
+    /**
      * Returns the zoom to be applied to the magnified view region copied to the magnifier.
      * If the zoom is x and the magnifier window size is (width, height), the original size
      * of the content being magnified will be (width / x, height / x).
@@ -904,7 +919,7 @@
         private final Display mDisplay;
         // The size of the content of the magnifier.
         private final int mContentWidth;
-        private final int mContentHeight;
+        private int mContentHeight;
         // The insets of the content inside the allocated surface.
         private final int mOffsetX;
         private final int mOffsetY;
@@ -947,7 +962,7 @@
         // The current content of the magnifier. It is mBitmap + mOverlay, only used for testing.
         private Bitmap mCurrentContent;
 
-        private final float mZoom;
+        private float mZoom;
         // The width of the ramp region in pixels on the left & right sides of the fish-eye effect.
         private final int mRamp;
         // Whether is in the new magnifier style.
@@ -1009,11 +1024,11 @@
 
             final RecordingCanvas canvas = mRenderer.getRootNode().beginRecording(width, height);
             try {
-                canvas.insertReorderBarrier();
+                canvas.enableZ();
                 canvas.drawRenderNode(mBitmapRenderNode);
-                canvas.insertInorderBarrier();
+                canvas.disableZ();
                 canvas.drawRenderNode(mOverlayRenderNode);
-                canvas.insertInorderBarrier();
+                canvas.disableZ();
             } finally {
                 mRenderer.getRootNode().endRecording();
             }
@@ -1034,15 +1049,66 @@
             }
         }
 
+        /**
+         * Updates the factors of content which may resize the window.
+         * @param contentHeight the new height of content.
+         * @param zoom the new zoom factor.
+         */
+        private void updateContentFactors(final int contentHeight, final float zoom) {
+            if (mContentHeight == contentHeight && mZoom == zoom) {
+              return;
+            }
+            if (mContentHeight < contentHeight) {
+                // Grows the surface height as necessary.
+                new SurfaceControl.Transaction().setBufferSize(
+                        mSurfaceControl, mContentWidth, contentHeight).apply();
+                mSurface.copyFrom(mSurfaceControl);
+                mRenderer.setSurface(mSurface);
+
+                final Outline outline = new Outline();
+                outline.setRoundRect(0, 0, mContentWidth, contentHeight, 0);
+                outline.setAlpha(1.0f);
+
+                mBitmapRenderNode.setLeftTopRightBottom(mOffsetX, mOffsetY,
+                        mOffsetX + mContentWidth, mOffsetY + contentHeight);
+                mBitmapRenderNode.setOutline(outline);
+
+                mOverlayRenderNode.setLeftTopRightBottom(mOffsetX, mOffsetY,
+                        mOffsetX + mContentWidth, mOffsetY + contentHeight);
+                mOverlayRenderNode.setOutline(outline);
+
+                final RecordingCanvas canvas =
+                        mRenderer.getRootNode().beginRecording(mContentWidth, contentHeight);
+                try {
+                    canvas.enableZ();
+                    canvas.drawRenderNode(mBitmapRenderNode);
+                    canvas.disableZ();
+                    canvas.drawRenderNode(mOverlayRenderNode);
+                    canvas.disableZ();
+                } finally {
+                    mRenderer.getRootNode().endRecording();
+                }
+            }
+            mContentHeight = contentHeight;
+            mZoom = zoom;
+            fillMeshMatrix();
+        }
+
         private void createMeshMatrixForFishEyeEffect() {
             mMeshWidth = 1;
             mMeshHeight = 6;
+            mMeshLeft = new float[2 * (mMeshWidth + 1) * (mMeshHeight + 1)];
+            mMeshRight = new float[2 * (mMeshWidth + 1) * (mMeshHeight + 1)];
+            fillMeshMatrix();
+        }
+
+        private void fillMeshMatrix() {
+            mMeshWidth = 1;
+            mMeshHeight = 6;
             final float w = mContentWidth;
             final float h = mContentHeight;
             final float h0 = h / mZoom;
             final float dh = h - h0;
-            mMeshLeft = new float[2 * (mMeshWidth + 1) * (mMeshHeight + 1)];
-            mMeshRight = new float[2 * (mMeshWidth + 1) * (mMeshHeight + 1)];
             for (int i = 0; i < 2 * (mMeshWidth + 1) * (mMeshHeight + 1); i += 2) {
                 // Calculates X value.
                 final int colIndex = i % (2 * (mMeshWidth + 1)) / 2;
@@ -1197,6 +1263,7 @@
             if (mBitmap != null) {
                 mBitmap.recycle();
             }
+            mOverlay.setCallback(null);
         }
 
         private void doDraw() {
diff --git a/core/java/android/widget/WidgetFlags.java b/core/java/android/widget/WidgetFlags.java
index 1a8e7a7..bce5497 100644
--- a/core/java/android/widget/WidgetFlags.java
+++ b/core/java/android/widget/WidgetFlags.java
@@ -17,27 +17,49 @@
 package android.widget;
 
 /**
- * Keeps the flags related to the Widget namespace in {@link DeviceConfig}.
+ * Flags in the {@link android.provider.DeviceConfig#NAMESPACE_WIDGET "widget" namespace}.
  *
  * @hide
  */
 public final class WidgetFlags {
 
     /**
-     * Whether the cursor control feature set is enabled.
-     * TODO: Makes this flag key visible to webview/chrome.
+     * Whether starting a cursor drag from anywhere in the text should be enabled.
      */
-    public static final String ENABLE_CURSOR_CONTROL =
-            "CursorControlFeature__enable_cursor_control";
+    public static final String ENABLE_CURSOR_DRAG_FROM_ANYWHERE =
+            "CursorControlFeature__enable_cursor_drag_from_anywhere";
 
     /**
-     * The key name used in app core settings for enable cursor control.
+     * The key used in app core settings for the flag {@link #ENABLE_CURSOR_DRAG_FROM_ANYWHERE}.
      */
-    public static final String KEY_ENABLE_CURSOR_CONTROL = "widget__enable_cursor_control";
+    public static final String KEY_ENABLE_CURSOR_DRAG_FROM_ANYWHERE =
+            "widget__enable_cursor_drag_from_anywhere";
+
+    /**
+     * Default value for the flag {@link #ENABLE_CURSOR_DRAG_FROM_ANYWHERE}.
+     */
+    public static final boolean ENABLE_CURSOR_DRAG_FROM_ANYWHERE_DEFAULT = true;
+
+    /**
+     * Whether additional gestures should be enabled for the insertion cursor handle (e.g.
+     * long-press or double-tap on the handle to trigger selection).
+     */
+    public static final String ENABLE_INSERTION_HANDLE_GESTURES =
+            "CursorControlFeature__enable_insertion_handle_gestures";
+
+    /**
+     * The key used in app core settings for the flag {@link #ENABLE_INSERTION_HANDLE_GESTURES}.
+     */
+    public static final String KEY_ENABLE_INSERTION_HANDLE_GESTURES =
+            "widget__enable_insertion_handle_gestures";
+
+    /**
+     * Default value for the flag {@link #ENABLE_INSERTION_HANDLE_GESTURES}.
+     */
+    public static final boolean ENABLE_INSERTION_HANDLE_GESTURES_DEFAULT = false;
 
     /**
      * The flag of delta height applies to the insertion handle when cursor control flag is enabled.
-     * The default value is 25.
      */
     public static final String INSERTION_HANDLE_DELTA_HEIGHT =
             "CursorControlFeature__insertion_handle_delta_height";
@@ -49,8 +71,13 @@
             "widget__insertion_handle_delta_height";
 
     /**
+     * Default value for the flag {@link #INSERTION_HANDLE_DELTA_HEIGHT}.
+     */
+    public static final int INSERTION_HANDLE_DELTA_HEIGHT_DEFAULT = 25;
+
+    /**
      * The flag of opacity applies to the insertion handle when cursor control flag is enabled.
-     * The opacity value is in the range of {0..100}. The default value is 50.
+     * The opacity value is in the range of {0..100}.
      */
     public static final String INSERTION_HANDLE_OPACITY =
             "CursorControlFeature__insertion_handle_opacity";
@@ -62,6 +89,11 @@
             "widget__insertion_handle_opacity";
 
     /**
+     * Default value for the flag {@link #INSERTION_HANDLE_OPACITY}.
+     */
+    public static final int INSERTION_HANDLE_OPACITY_DEFAULT = 50;
+
+    /**
      * The flag of enabling the new magnifier.
      */
     public static final String ENABLE_NEW_MAGNIFIER = "CursorControlFeature__enable_new_magnifier";
@@ -72,8 +104,12 @@
     public static final String KEY_ENABLE_NEW_MAGNIFIER = "widget__enable_new_magnifier";
 
     /**
+     * Default value for the flag {@link #ENABLE_NEW_MAGNIFIER}.
+     */
+    public static final boolean ENABLE_NEW_MAGNIFIER_DEFAULT = false;
+
+    /**
      * The flag of zoom factor applies to the new magnifier.
-     * The default value is 1.5f.
      */
     public static final String MAGNIFIER_ZOOM_FACTOR =
             "CursorControlFeature__magnifier_zoom_factor";
@@ -84,8 +120,12 @@
     public static final String KEY_MAGNIFIER_ZOOM_FACTOR = "widget__magnifier_zoom_factor";
 
     /**
+     * Default value for the flag {@link #MAGNIFIER_ZOOM_FACTOR}.
+     */
+    public static final float MAGNIFIER_ZOOM_FACTOR_DEFAULT = 1.5f;
+
+    /**
      * The flag of aspect ratio (width/height) applies to the new magnifier.
-     * The default value is 5.5f.
      */
     public static final String MAGNIFIER_ASPECT_RATIO =
             "CursorControlFeature__magnifier_aspect_ratio";
@@ -95,6 +135,11 @@
      */
     public static final String KEY_MAGNIFIER_ASPECT_RATIO = "widget__magnifier_aspect_ratio";
 
+    /**
+     * Default value for the flag {@link #MAGNIFIER_ASPECT_RATIO}.
+     */
+    public static final float MAGNIFIER_ASPECT_RATIO_DEFAULT = 5.5f;
+
     private WidgetFlags() {
     }
 }
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index a201a33..250b1ea 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -1805,6 +1805,10 @@
             if (!TextUtils.isEmpty(dataString)) {
                 return new IntentFilter(intent.getAction(), dataString);
             }
+            if (intent.getType() == null) {
+                Log.e(TAG, "Failed to get target intent filter: intent data and type are null");
+                return null;
+            }
             IntentFilter intentFilter = new IntentFilter(intent.getAction(), intent.getType());
             List<Uri> contentUris = new ArrayList<>();
             if (Intent.ACTION_SEND.equals(intent.getAction())) {
@@ -1825,7 +1829,7 @@
             }
             return intentFilter;
         } catch (Exception e) {
-            Log.e(TAG, "failed to get target intent filter", e);
+            Log.e(TAG, "Failed to get target intent filter", e);
             return null;
         }
     }
diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl
index 2f1a15f..dc6942c 100644
--- a/core/java/com/android/internal/app/IBatteryStats.aidl
+++ b/core/java/com/android/internal/app/IBatteryStats.aidl
@@ -133,7 +133,7 @@
     void noteNetworkStatsEnabled();
     void noteDeviceIdleMode(int mode, String activeReason, int activeUid);
     void setBatteryState(int status, int health, int plugType, int level, int temp, int volt,
-            int chargeUAh, int chargeFullUAh);
+            int chargeUAh, int chargeFullUAh, long chargeTimeToFullSeconds);
     @UnsupportedAppUsage
     long getAwakeTimeBattery();
     long getAwakeTimePlugged();
diff --git a/core/java/com/android/internal/app/ResolverViewPager.java b/core/java/com/android/internal/app/ResolverViewPager.java
index 84fed9c..8239018 100644
--- a/core/java/com/android/internal/app/ResolverViewPager.java
+++ b/core/java/com/android/internal/app/ResolverViewPager.java
@@ -24,10 +24,10 @@
 import com.android.internal.widget.ViewPager;
 
 /**
- * A {@link ViewPager} which wraps around its first child's height and has swiping disabled.
+ * A {@link ViewPager} which wraps around its first child's height.
  * <p>Normally {@link ViewPager} instances expand their height to cover all remaining space in
  * the layout.
- * <p>This class is used for the intent resolver and share sheet's tabbed view.
+ * <p>This class is used for the intent resolver's tabbed view.
  */
 public class ResolverViewPager extends ViewPager {
 
@@ -70,14 +70,4 @@
         heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
     }
-
-    @Override
-    public boolean onTouchEvent(MotionEvent ev) {
-        return false;
-    }
-
-    @Override
-    public boolean onInterceptTouchEvent(MotionEvent ev) {
-        return false;
-    }
 }
diff --git a/core/java/com/android/internal/content/NativeLibraryHelper.java b/core/java/com/android/internal/content/NativeLibraryHelper.java
index 0ccc45e..04bf915 100644
--- a/core/java/com/android/internal/content/NativeLibraryHelper.java
+++ b/core/java/com/android/internal/content/NativeLibraryHelper.java
@@ -31,7 +31,6 @@
 import android.content.pm.PackageParser;
 import android.content.pm.PackageParser.PackageLite;
 import android.content.pm.PackageParser.PackageParserException;
-import android.content.pm.parsing.AndroidPackage;
 import android.os.Build;
 import android.os.IBinder;
 import android.os.SELinux;
@@ -95,20 +94,12 @@
             }
         }
 
-        public static Handle create(AndroidPackage pkg) throws IOException {
-            return create(
-                    pkg.makeListAllCodePaths(),
-                    (pkg.getFlags() & ApplicationInfo.FLAG_MULTIARCH) != 0,
-                    (pkg.getFlags() & ApplicationInfo.FLAG_EXTRACT_NATIVE_LIBS) != 0,
-                    (pkg.getFlags() & ApplicationInfo.FLAG_DEBUGGABLE) != 0);
-        }
-
         public static Handle create(PackageLite lite) throws IOException {
             return create(lite.getAllCodePaths(), lite.multiArch, lite.extractNativeLibs,
                     lite.debuggable);
         }
 
-        private static Handle create(List<String> codePaths, boolean multiArch,
+        public static Handle create(List<String> codePaths, boolean multiArch,
                 boolean extractNativeLibs, boolean debuggable) throws IOException {
             final int size = codePaths.size();
             final String[] apkPaths = new String[size];
diff --git a/core/java/com/android/internal/content/om/OverlayConfig.java b/core/java/com/android/internal/content/om/OverlayConfig.java
index f699eb8..72f16e4 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");
 
@@ -186,13 +186,6 @@
      */
     @NonNull
     public static OverlayConfig getZygoteInstance() {
-        if (Process.myUid() != Process.ROOT_UID) {
-            // Scan the overlays in the zygote process to generate configuration settings for
-            // overlays on the system image. Do not cache this instance so OverlayConfig will not
-            // be present in applications by default.
-            throw new IllegalStateException("Can only be invoked in the root process");
-        }
-
         Trace.traceBegin(Trace.TRACE_TAG_RRO, "OverlayConfig#getZygoteInstance");
         try {
             return new OverlayConfig(null /* rootDirectory */, OverlayScanner::new,
@@ -208,20 +201,19 @@
      * {@link #getSystemInstance()} will return the initialized instance.
      */
     @NonNull
-    public static OverlayConfig initializeSystemInstance(AndroidPackageProvider packageProvider) {
-        if (Process.myUid() != Process.SYSTEM_UID) {
-            throw new IllegalStateException("Can only be invoked in the system process");
-        }
-
+    public static OverlayConfig initializeSystemInstance(PackageProvider packageProvider) {
         Trace.traceBegin(Trace.TRACE_TAG_RRO, "OverlayConfig#initializeSystemInstance");
-        sInstance = new OverlayConfig(null, null, packageProvider);
-        Trace.traceEnd(Trace.TRACE_TAG_RRO);
+        try {
+            sInstance = new OverlayConfig(null, null, packageProvider);
+        } finally {
+            Trace.traceEnd(Trace.TRACE_TAG_RRO);
+        }
         return sInstance;
     }
 
     /**
      * Retrieves the singleton instance initialized by
-     * {@link #initializeSystemInstance(AndroidPackageProvider)}.
+     * {@link #initializeSystemInstance(PackageProvider)}.
      */
     @NonNull
     public static OverlayConfig getSystemInstance() {
@@ -291,10 +283,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())));
@@ -373,10 +365,6 @@
      */
     @NonNull
     public String[] createImmutableFrameworkIdmapsInZygote() {
-        if (Process.myUid() != Process.ROOT_UID) {
-            throw new IllegalStateException("This method can only be called from the root process");
-        }
-
         final String targetPath = "/system/framework/framework-res.apk";
         final ArrayList<String> idmapPaths = new ArrayList<>();
         final ArrayList<IdmapInvocation> idmapInvocations =
diff --git a/core/java/com/android/internal/content/om/TEST_MAPPING b/core/java/com/android/internal/content/om/TEST_MAPPING
new file mode 100644
index 0000000..4cb595b
--- /dev/null
+++ b/core/java/com/android/internal/content/om/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+  "presubmit": [
+    {
+      "name": "FrameworksCoreTests",
+      "options": [
+        {
+          "include-filter": "com.android.internal.content."
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/core/java/com/android/internal/net/VpnProfile.java b/core/java/com/android/internal/net/VpnProfile.java
index bbae027..23b1ab5 100644
--- a/core/java/com/android/internal/net/VpnProfile.java
+++ b/core/java/com/android/internal/net/VpnProfile.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.compat.annotation.UnsupportedAppUsage;
+import android.net.Ikev2VpnProfile;
 import android.net.ProxyInfo;
 import android.os.Build;
 import android.os.Parcel;
@@ -332,15 +333,38 @@
         return builder.toString().getBytes(StandardCharsets.UTF_8);
     }
 
+    /** Checks if this profile specifies a LegacyVpn type. */
+    public static boolean isLegacyType(int type) {
+        switch (type) {
+            case VpnProfile.TYPE_IKEV2_IPSEC_USER_PASS: // fall through
+            case VpnProfile.TYPE_IKEV2_IPSEC_RSA: // fall through
+            case VpnProfile.TYPE_IKEV2_IPSEC_PSK:
+                return false;
+            default:
+                return true;
+        }
+    }
+
+    private boolean isValidLockdownLegacyVpnProfile() {
+        return isLegacyType(type) && isServerAddressNumeric() && hasDns()
+                && areDnsAddressesNumeric();
+    }
+
+    private boolean isValidLockdownPlatformVpnProfile() {
+        return Ikev2VpnProfile.isValidVpnProfile(this);
+    }
+
     /**
-     * Tests if profile is valid for lockdown, which requires IPv4 address for both server and DNS.
-     * Server hostnames would require using DNS before connection.
+     * Tests if profile is valid for lockdown.
+     *
+     * <p>For LegacyVpn profiles, this requires an IPv4 address for both the server and DNS.
+     *
+     * <p>For PlatformVpn profiles, this requires a server, an identifier and the relevant fields to
+     * be non-null.
      */
     public boolean isValidLockdownProfile() {
         return isTypeValidForLockdown()
-                && isServerAddressNumeric()
-                && hasDns()
-                && areDnsAddressesNumeric();
+                && (isValidLockdownLegacyVpnProfile() || isValidLockdownPlatformVpnProfile());
     }
 
     /** Returns {@code true} if the VPN type is valid for lockdown. */
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 18066dc..27c7cb6 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -1000,6 +1000,8 @@
     private int mMinLearnedBatteryCapacity = -1;
     private int mMaxLearnedBatteryCapacity = -1;
 
+    private long mBatteryTimeToFullSeconds = -1;
+
     private long[] mCpuFreqs;
 
     @VisibleForTesting
@@ -12226,7 +12228,7 @@
     @GuardedBy("this")
     public void setBatteryStateLocked(final int status, final int health, final int plugType,
             final int level, /* not final */ int temp, final int volt, final int chargeUAh,
-            final int chargeFullUAh) {
+            final int chargeFullUAh, final long chargeTimeToFullSeconds) {
         // Temperature is encoded without the signed bit, so clamp any negative temperatures to 0.
         temp = Math.max(0, temp);
 
@@ -12429,6 +12431,8 @@
             mMinLearnedBatteryCapacity = Math.min(mMinLearnedBatteryCapacity, chargeFullUAh);
         }
         mMaxLearnedBatteryCapacity = Math.max(mMaxLearnedBatteryCapacity, chargeFullUAh);
+
+        mBatteryTimeToFullSeconds = chargeTimeToFullSeconds;
     }
 
     public static boolean isOnBattery(int plugType, int status) {
@@ -12578,19 +12582,10 @@
             // Not yet working.
             return -1;
         }
-        /* Broken
-        int curLevel = mCurrentBatteryLevel;
-        int plugLevel = mDischargePlugLevel;
-        if (plugLevel < 0 || curLevel < (plugLevel+1)) {
-            return -1;
+        if (mBatteryTimeToFullSeconds >= 0) {
+            return mBatteryTimeToFullSeconds * (1000 * 1000); // s to us
         }
-        long duration = computeBatteryRealtime(curTime, STATS_SINCE_UNPLUGGED);
-        if (duration < 1000*1000) {
-            return -1;
-        }
-        long usPerLevel = duration/(curLevel-plugLevel);
-        return usPerLevel * (100-curLevel);
-        */
+        // Else use algorithmic approach
         if (mChargeStepTracker.mNumStepDurations < 1) {
             return -1;
         }
@@ -12598,7 +12593,7 @@
         if (msPerLevel <= 0) {
             return -1;
         }
-        return (msPerLevel * (100-mCurrentBatteryLevel)) * 1000;
+        return (msPerLevel * (100 - mCurrentBatteryLevel)) * 1000;
     }
 
     /*@hide */
diff --git a/core/java/com/android/internal/os/PowerProfile.java b/core/java/com/android/internal/os/PowerProfile.java
index 3db8f4e..add2304 100644
--- a/core/java/com/android/internal/os/PowerProfile.java
+++ b/core/java/com/android/internal/os/PowerProfile.java
@@ -393,6 +393,9 @@
     }
 
     public int getNumCoresInCpuCluster(int cluster) {
+        if (cluster < 0 || cluster >= mCpuClusters.length) {
+            return 0; // index out of bound
+        }
         return mCpuClusters[cluster].numCpus;
     }
 
diff --git a/core/java/com/android/internal/os/TEST_MAPPING b/core/java/com/android/internal/os/TEST_MAPPING
new file mode 100644
index 0000000..f44b9fb
--- /dev/null
+++ b/core/java/com/android/internal/os/TEST_MAPPING
@@ -0,0 +1,30 @@
+{
+  "presubmit": [
+    {
+      "name": "FrameworksCoreTests",
+      "options": [
+        {
+          "include-filter": "com.android.internal.os.KernelCpuUidFreqTimeReaderTest"
+        },
+        {
+          "include-filter": "com.android.internal.os.KernelCpuUidActiveTimeReaderTest"
+        },
+        {
+          "include-filter": "com.android.internal.os.KernelCpuUidClusterTimeReaderTest"
+        },
+        {
+          "include-filter": "com.android.internal.os.KernelSingleUidTimeReaderTest"
+        },
+        {
+          "include-filter": "com.android.internal.os.KernelCpuUidBpfMapReaderTest"
+        }
+
+      ],
+      "file_patterns": [
+        "KernelCpuUidTimeReader\\.java",
+        "KernelCpuUidBpfMapReader\\.java",
+        "KernelSingleUidTimeReader\\.java"
+      ]
+    }
+  ]
+}
diff --git a/core/java/com/android/internal/util/CollectionUtils.java b/core/java/com/android/internal/util/CollectionUtils.java
index 4dac542..9b2bcfb 100644
--- a/core/java/com/android/internal/util/CollectionUtils.java
+++ b/core/java/com/android/internal/util/CollectionUtils.java
@@ -186,6 +186,17 @@
     }
 
     /**
+     * Returns the given map, or an immutable empty map if the provided map is null
+     *
+     * This can be used to guarantee null-safety without paying the price of extra allocations
+     *
+     * @see Collections#emptyMap
+     */
+    public static @NonNull <K, V> Map<K, V> emptyIfNull(@Nullable Map<K, V> cur) {
+        return cur == null ? Collections.emptyMap() : cur;
+    }
+
+    /**
      * Returns the size of the given collection, or 0 if null
      */
     public static int size(@Nullable Collection<?> cur) {
@@ -297,6 +308,33 @@
     }
 
     /**
+     * Similar to {@link List#add(int, Object)}, but with support for list values of {@code null}
+     * and {@link Collections#emptyList}
+     */
+    public static @NonNull <T> List<T> add(@Nullable List<T> cur, int index, T val) {
+        if (cur == null || cur == Collections.emptyList()) {
+            cur = new ArrayList<>();
+        }
+        cur.add(index, val);
+        return cur;
+    }
+
+    /**
+     * Similar to {@link Set#addAll(Collection)}}, but with support for list values of {@code null}
+     * and {@link Collections#emptySet}
+     */
+    public static @NonNull <T> Set<T> addAll(@Nullable Set<T> cur, @Nullable Collection<T> val) {
+        if (isEmpty(val)) {
+            return cur != null ? cur : Collections.emptySet();
+        }
+        if (cur == null || cur == Collections.emptySet()) {
+            cur = new ArraySet<>();
+        }
+        cur.addAll(val);
+        return cur;
+    }
+
+    /**
      * @see #add(List, Object)
      */
     public static @NonNull <T> Set<T> add(@Nullable Set<T> cur, T val) {
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/java/com/android/internal/util/function/LongObjPredicate.java b/core/java/com/android/internal/util/function/LongObjPredicate.java
new file mode 100644
index 0000000..9e46307
--- /dev/null
+++ b/core/java/com/android/internal/util/function/LongObjPredicate.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 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.internal.util.function;
+
+/**
+ * Represents a predicate (boolean-valued function) of a {@code long}-valued argument
+ * and an object-valued argument.
+ *
+ * @param <T> the type of the object-valued argument to the predicate
+ */
+@FunctionalInterface
+public interface LongObjPredicate<T> {
+    /**
+     * Evaluates this predicate on the given arguments.
+     *
+     * @param value the first input argument
+     * @param t the second input argument
+     * @return {@code true} if the input arguments match the predicate,
+     *         otherwise {@code false}
+     */
+    boolean test(long value, T t);
+}
diff --git a/core/java/com/android/internal/view/FloatingActionMode.java b/core/java/com/android/internal/view/FloatingActionMode.java
index 69b1609..633d684 100644
--- a/core/java/com/android/internal/view/FloatingActionMode.java
+++ b/core/java/com/android/internal/view/FloatingActionMode.java
@@ -210,7 +210,7 @@
     }
 
     private boolean isContentRectWithinBounds() {
-        mContext.getDisplay().getRealSize(mDisplaySize);
+        mContext.getDisplayNoVerify().getRealSize(mDisplaySize);
         mScreenRect.set(0, 0, mDisplaySize.x, mDisplaySize.y);
 
         return intersectsClosed(mContentRectOnScreen, mScreenRect)
diff --git a/core/java/com/android/internal/view/IInputMethod.aidl b/core/java/com/android/internal/view/IInputMethod.aidl
index 475a321..fd4b5ab 100644
--- a/core/java/com/android/internal/view/IInputMethod.aidl
+++ b/core/java/com/android/internal/view/IInputMethod.aidl
@@ -16,10 +16,8 @@
 
 package com.android.internal.view;
 
-import android.content.ComponentName;
 import android.os.IBinder;
 import android.os.ResultReceiver;
-import android.view.autofill.AutofillId;
 import android.view.InputChannel;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputBinding;
@@ -29,6 +27,7 @@
 import com.android.internal.view.IInputContext;
 import com.android.internal.view.IInputMethodSession;
 import com.android.internal.view.IInputSessionCallback;
+import com.android.internal.view.InlineSuggestionsRequestInfo;
 
 /**
  * Top-level interface to an input method component (implemented in a
@@ -38,7 +37,7 @@
 oneway interface IInputMethod {
     void initializeInternal(IBinder token, int displayId, IInputMethodPrivilegedOperations privOps);
 
-    void onCreateInlineSuggestionsRequest(in ComponentName componentName, in AutofillId autofillId,
+    void onCreateInlineSuggestionsRequest(in InlineSuggestionsRequestInfo requestInfo,
             in IInlineSuggestionsRequestCallback cb);
 
     void bindInput(in InputBinding binding);
diff --git a/core/java/com/android/internal/view/IInputMethodClient.aidl b/core/java/com/android/internal/view/IInputMethodClient.aidl
index 41f902e..4509032 100644
--- a/core/java/com/android/internal/view/IInputMethodClient.aidl
+++ b/core/java/com/android/internal/view/IInputMethodClient.aidl
@@ -28,6 +28,7 @@
     void onBindMethod(in InputBindResult res);
     void onUnbindMethod(int sequence, int unbindReason);
     void setActive(boolean active, boolean fullscreen);
+    void scheduleStartInputIfNecessary(boolean fullscreen);
     void reportFullscreenMode(boolean fullscreen);
     void reportPreRendered(in EditorInfo info);
     void applyImeVisibility(boolean setVisible);
diff --git a/core/java/com/android/internal/view/InlineSuggestionsRequestInfo.aidl b/core/java/com/android/internal/view/InlineSuggestionsRequestInfo.aidl
new file mode 100644
index 0000000..8125c0d
--- /dev/null
+++ b/core/java/com/android/internal/view/InlineSuggestionsRequestInfo.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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.internal.view;
+
+parcelable InlineSuggestionsRequestInfo;
diff --git a/core/java/com/android/internal/view/InlineSuggestionsRequestInfo.java b/core/java/com/android/internal/view/InlineSuggestionsRequestInfo.java
new file mode 100644
index 0000000..6148490
--- /dev/null
+++ b/core/java/com/android/internal/view/InlineSuggestionsRequestInfo.java
@@ -0,0 +1,229 @@
+/*
+ * 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.internal.view;
+
+import android.annotation.NonNull;
+import android.content.ComponentName;
+import android.os.Bundle;
+import android.os.Parcelable;
+import android.view.autofill.AutofillId;
+import android.view.inputmethod.InlineSuggestionsRequest;
+
+import com.android.internal.util.DataClass;
+
+/**
+ * Wraps the information needed to create an {@link InlineSuggestionsRequest}.
+ *
+ * @hide
+ */
+@DataClass(
+        genToString = true,
+        genHiddenConstDefs = true,
+        genEqualsHashCode = true)
+public final class InlineSuggestionsRequestInfo implements Parcelable {
+    /**
+     * The {@link ComponentName} of current app/activity
+     */
+    private final @NonNull ComponentName mComponentName;
+
+    /**
+     * The {@link AutofillId} of currently focused field.
+     */
+    private final @NonNull AutofillId mAutofillId;
+
+    /**
+     * The extras that contain the UI renderer related information
+     */
+    private final @NonNull Bundle mUiExtras;
+
+
+
+    // Code below generated by codegen v1.0.14.
+    //
+    // DO NOT MODIFY!
+    // CHECKSTYLE:OFF Generated code
+    //
+    // To regenerate run:
+    // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/com/android/internal/view/InlineSuggestionsRequestInfo.java
+    //
+    // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+    //   Settings > Editor > Code Style > Formatter Control
+    //@formatter:off
+
+
+    /**
+     * Creates a new InlineSuggestionsRequestInfo.
+     *
+     * @param componentName
+     *   The {@link ComponentName} of current app/activity
+     * @param autofillId
+     *   The {@link AutofillId} of currently focused field.
+     * @param uiExtras
+     *   The extras that contain the ui renderer related information
+     */
+    @DataClass.Generated.Member
+    public InlineSuggestionsRequestInfo(
+            @NonNull ComponentName componentName,
+            @NonNull AutofillId autofillId,
+            @NonNull Bundle uiExtras) {
+        this.mComponentName = componentName;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mComponentName);
+        this.mAutofillId = autofillId;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mAutofillId);
+        this.mUiExtras = uiExtras;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mUiExtras);
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    /**
+     * The {@link ComponentName} of current app/activity
+     */
+    @DataClass.Generated.Member
+    public @NonNull ComponentName getComponentName() {
+        return mComponentName;
+    }
+
+    /**
+     * The {@link AutofillId} of currently focused field.
+     */
+    @DataClass.Generated.Member
+    public @NonNull AutofillId getAutofillId() {
+        return mAutofillId;
+    }
+
+    /**
+     * The extras that contain the ui renderer related information
+     */
+    @DataClass.Generated.Member
+    public @NonNull Bundle getUiExtras() {
+        return mUiExtras;
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public String toString() {
+        // You can override field toString logic by defining methods like:
+        // String fieldNameToString() { ... }
+
+        return "InlineSuggestionsRequestInfo { " +
+                "componentName = " + mComponentName + ", " +
+                "autofillId = " + mAutofillId + ", " +
+                "uiExtras = " + mUiExtras +
+        " }";
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public boolean equals(@android.annotation.Nullable Object o) {
+        // You can override field equality logic by defining either of the methods like:
+        // boolean fieldNameEquals(InlineSuggestionsRequestInfo other) { ... }
+        // boolean fieldNameEquals(FieldType otherValue) { ... }
+
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        @SuppressWarnings("unchecked")
+        InlineSuggestionsRequestInfo that = (InlineSuggestionsRequestInfo) o;
+        //noinspection PointlessBooleanExpression
+        return true
+                && java.util.Objects.equals(mComponentName, that.mComponentName)
+                && java.util.Objects.equals(mAutofillId, that.mAutofillId)
+                && java.util.Objects.equals(mUiExtras, that.mUiExtras);
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public int hashCode() {
+        // You can override field hashCode logic by defining methods like:
+        // int fieldNameHashCode() { ... }
+
+        int _hash = 1;
+        _hash = 31 * _hash + java.util.Objects.hashCode(mComponentName);
+        _hash = 31 * _hash + java.util.Objects.hashCode(mAutofillId);
+        _hash = 31 * _hash + java.util.Objects.hashCode(mUiExtras);
+        return _hash;
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public void writeToParcel(@NonNull android.os.Parcel dest, int flags) {
+        // You can override field parcelling by defining methods like:
+        // void parcelFieldName(Parcel dest, int flags) { ... }
+
+        dest.writeTypedObject(mComponentName, flags);
+        dest.writeTypedObject(mAutofillId, flags);
+        dest.writeBundle(mUiExtras);
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public int describeContents() { return 0; }
+
+    /** @hide */
+    @SuppressWarnings({"unchecked", "RedundantCast"})
+    @DataClass.Generated.Member
+    /* package-private */ InlineSuggestionsRequestInfo(@NonNull android.os.Parcel in) {
+        // You can override field unparcelling by defining methods like:
+        // static FieldType unparcelFieldName(Parcel in) { ... }
+
+        ComponentName componentName = (ComponentName) in.readTypedObject(ComponentName.CREATOR);
+        AutofillId autofillId = (AutofillId) in.readTypedObject(AutofillId.CREATOR);
+        Bundle uiExtras = in.readBundle();
+
+        this.mComponentName = componentName;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mComponentName);
+        this.mAutofillId = autofillId;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mAutofillId);
+        this.mUiExtras = uiExtras;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mUiExtras);
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    @DataClass.Generated.Member
+    public static final @NonNull Parcelable.Creator<InlineSuggestionsRequestInfo> CREATOR
+            = new Parcelable.Creator<InlineSuggestionsRequestInfo>() {
+        @Override
+        public InlineSuggestionsRequestInfo[] newArray(int size) {
+            return new InlineSuggestionsRequestInfo[size];
+        }
+
+        @Override
+        public InlineSuggestionsRequestInfo createFromParcel(@NonNull android.os.Parcel in) {
+            return new InlineSuggestionsRequestInfo(in);
+        }
+    };
+
+    @DataClass.Generated(
+            time = 1582076613213L,
+            codegenVersion = "1.0.14",
+            sourceFile = "frameworks/base/core/java/com/android/internal/view/InlineSuggestionsRequestInfo.java",
+            inputSignatures = "private final @android.annotation.NonNull android.content.ComponentName mComponentName\nprivate final @android.annotation.NonNull android.view.autofill.AutofillId mAutofillId\nprivate final @android.annotation.NonNull android.os.Bundle mUiExtras\nclass InlineSuggestionsRequestInfo extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genHiddenConstDefs=true, genEqualsHashCode=true)")
+    @Deprecated
+    private void __metadata() {}
+
+
+    //@formatter:on
+    // End of generated code
+
+}
diff --git a/core/java/com/android/internal/view/InputBindResult.java b/core/java/com/android/internal/view/InputBindResult.java
index a5964b5..f29e95c 100644
--- a/core/java/com/android/internal/view/InputBindResult.java
+++ b/core/java/com/android/internal/view/InputBindResult.java
@@ -89,57 +89,64 @@
          */
         int SUCCESS_WAITING_IME_BINDING = 2;
         /**
+         * Indicates that {@link com.android.server.inputmethod.InputMethodManagerService} has a
+         * pending operation to switch to a different user.
+         *
+         * <p>Note that in this state even what would be the next current IME is not determined.</p>
+         */
+        int SUCCESS_WAITING_USER_SWITCHING = 3;
+        /**
          * Indicates that this is not intended for starting input but just for reporting window
          * focus change from the application process.
          *
          * <p>All other fields do not have meaningful value.</p>
          */
-        int SUCCESS_REPORT_WINDOW_FOCUS_ONLY = 3;
+        int SUCCESS_REPORT_WINDOW_FOCUS_ONLY = 4;
         /**
          * Indicates somehow
          * {@link
          * com.android.server.inputmethod.InputMethodManagerService#startInputOrWindowGainedFocus}
          * is trying to return null {@link InputBindResult}, which must never happen.
          */
-        int ERROR_NULL = 4;
+        int ERROR_NULL = 5;
         /**
          * Indicates that {@link com.android.server.inputmethod.InputMethodManagerService}
          * recognizes no IME.
          */
-        int ERROR_NO_IME = 5;
+        int ERROR_NO_IME = 6;
         /**
          * Indicates that {@link android.view.inputmethod.EditorInfo#packageName} does not match
          * the caller UID.
          *
          * @see android.view.inputmethod.EditorInfo#packageName
          */
-        int ERROR_INVALID_PACKAGE_NAME = 6;
+        int ERROR_INVALID_PACKAGE_NAME = 7;
         /**
          * Indicates that the system is still in an early stage of the boot process and any 3rd
          * party application is not allowed to run.
          *
          * @see com.android.server.SystemService#PHASE_THIRD_PARTY_APPS_CAN_START
          */
-        int ERROR_SYSTEM_NOT_READY = 7;
+        int ERROR_SYSTEM_NOT_READY = 8;
         /**
          * Indicates that {@link com.android.server.inputmethod.InputMethodManagerService} tried to
          * connect to an {@link android.inputmethodservice.InputMethodService} but failed.
          *
          * @see android.content.Context#bindServiceAsUser(Intent, ServiceConnection, int, UserHandle)
          */
-        int ERROR_IME_NOT_CONNECTED = 8;
+        int ERROR_IME_NOT_CONNECTED = 9;
         /**
          * Indicates that the caller is not the foreground user, does not have
          * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} permission, or the user
          * specified in {@link android.view.inputmethod.EditorInfo#targetInputMethodUser} is not
          * running.
          */
-        int ERROR_INVALID_USER = 9;
+        int ERROR_INVALID_USER = 10;
         /**
          * Indicates that the caller should have specified non-null
          * {@link android.view.inputmethod.EditorInfo}.
          */
-        int ERROR_NULL_EDITOR_INFO = 10;
+        int ERROR_NULL_EDITOR_INFO = 11;
         /**
          * Indicates that the target window the client specified cannot be the IME target right now.
          *
@@ -149,24 +156,24 @@
          *
          * @see com.android.server.wm.WindowManagerInternal#isInputMethodClientFocus(int, int, int)
          */
-        int ERROR_NOT_IME_TARGET_WINDOW = 11;
+        int ERROR_NOT_IME_TARGET_WINDOW = 12;
         /**
          * Indicates that focused view in the current window is not an editor.
          */
-        int ERROR_NO_EDITOR = 12;
+        int ERROR_NO_EDITOR = 13;
         /**
          * Indicates that there is a mismatch in display ID between IME client and focused Window.
          */
-        int ERROR_DISPLAY_ID_MISMATCH = 13;
+        int ERROR_DISPLAY_ID_MISMATCH = 14;
         /**
          * Indicates that current IME client is no longer allowed to access to the associated
          * display.
          */
-        int ERROR_INVALID_DISPLAY_ID = 14;
+        int ERROR_INVALID_DISPLAY_ID = 15;
         /**
          * Indicates that the client is not recognized by the system.
          */
-        int ERROR_INVALID_CLIENT = 15;
+        int ERROR_INVALID_CLIENT = 16;
     }
 
     @ResultCode
@@ -299,6 +306,8 @@
                 return "SUCCESS_WAITING_IME_SESSION";
             case ResultCode.SUCCESS_WAITING_IME_BINDING:
                 return "SUCCESS_WAITING_IME_BINDING";
+            case ResultCode.SUCCESS_WAITING_USER_SWITCHING:
+                return "SUCCESS_WAITING_USER_SWITCHING";
             case ResultCode.SUCCESS_REPORT_WINDOW_FOCUS_ONLY:
                 return "SUCCESS_REPORT_WINDOW_FOCUS_ONLY";
             case ResultCode.ERROR_NULL:
@@ -386,4 +395,11 @@
      * Predefined error object for {@link ResultCode#ERROR_INVALID_CLIENT}.
      */
     public static final InputBindResult INVALID_CLIENT = error(ResultCode.ERROR_INVALID_CLIENT);
+
+    /**
+     * Predefined <strong>success</strong> object for
+     * {@link ResultCode#SUCCESS_WAITING_USER_SWITCHING}.
+     */
+    public static final InputBindResult USER_SWITCHING =
+            error(ResultCode.SUCCESS_WAITING_USER_SWITCHING);
 }
diff --git a/core/java/com/android/internal/view/RotationPolicy.java b/core/java/com/android/internal/view/RotationPolicy.java
index 13425e5..cfb2bf9 100644
--- a/core/java/com/android/internal/view/RotationPolicy.java
+++ b/core/java/com/android/internal/view/RotationPolicy.java
@@ -77,10 +77,7 @@
             final Point size = new Point();
             final IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
             try {
-                final Display display = context.getDisplay();
-                final int displayId = display != null
-                        ? display.getDisplayId()
-                        : Display.DEFAULT_DISPLAY;
+                final int displayId = context.getDisplayId();
                 wm.getInitialDisplaySize(displayId, size);
                 return size.x < size.y ?
                         Configuration.ORIENTATION_PORTRAIT : Configuration.ORIENTATION_LANDSCAPE;
diff --git a/core/java/com/android/internal/widget/ILockSettings.aidl b/core/java/com/android/internal/widget/ILockSettings.aidl
index e24e982..e35fda1 100644
--- a/core/java/com/android/internal/widget/ILockSettings.aidl
+++ b/core/java/com/android/internal/widget/ILockSettings.aidl
@@ -57,6 +57,8 @@
     void registerStrongAuthTracker(in IStrongAuthTracker tracker);
     void unregisterStrongAuthTracker(in IStrongAuthTracker tracker);
     void requireStrongAuth(int strongAuthReason, int userId);
+    void reportSuccessfulBiometricUnlock(boolean isStrongBiometric, int userId);
+    void scheduleNonStrongBiometricIdleTimeout(int userId);
     void systemReady();
     void userPresent(int userId);
     int getStrongAuthForUser(int userId);
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 864429c..d9b2902 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -49,6 +49,7 @@
 import android.provider.Settings;
 import android.text.TextUtils;
 import android.util.Log;
+import android.util.SparseBooleanArray;
 import android.util.SparseIntArray;
 import android.util.SparseLongArray;
 
@@ -1382,6 +1383,22 @@
         }
     }
 
+    public void reportSuccessfulBiometricUnlock(boolean isStrongBiometric, int userId) {
+        try {
+            getLockSettings().reportSuccessfulBiometricUnlock(isStrongBiometric, userId);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Could not report successful biometric unlock", e);
+        }
+    }
+
+    public void scheduleNonStrongBiometricIdleTimeout(int userId) {
+        try {
+            getLockSettings().scheduleNonStrongBiometricIdleTimeout(userId);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Could not schedule non-strong biometric idle timeout", e);
+        }
+    }
+
     /**
      * @see StrongAuthTracker#getStrongAuthForUser
      */
@@ -1557,7 +1574,8 @@
                         SOME_AUTH_REQUIRED_AFTER_USER_REQUEST,
                         STRONG_AUTH_REQUIRED_AFTER_LOCKOUT,
                         STRONG_AUTH_REQUIRED_AFTER_TIMEOUT,
-                        STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN})
+                        STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN,
+                        STRONG_AUTH_REQUIRED_AFTER_NON_STRONG_BIOMETRICS_TIMEOUT})
         @Retention(RetentionPolicy.SOURCE)
         public @interface StrongAuthFlags {}
 
@@ -1604,6 +1622,12 @@
         public static final int STRONG_AUTH_REQUIRED_FOR_UNATTENDED_UPDATE = 0x40;
 
         /**
+         * Strong authentication is required because it hasn't been used for a time after a
+         * non-strong biometric (i.e. weak or convenience biometric) is used to unlock device.
+         */
+        public static final int STRONG_AUTH_REQUIRED_AFTER_NON_STRONG_BIOMETRICS_TIMEOUT = 0x80;
+
+        /**
          * Strong auth flags that do not prevent biometric methods from being accepted as auth.
          * If any other flags are set, biometric authentication is disabled.
          */
@@ -1614,6 +1638,10 @@
         private final H mHandler;
         private final int mDefaultStrongAuthFlags;
 
+        private final SparseBooleanArray mIsNonStrongBiometricAllowedForUser =
+                new SparseBooleanArray();
+        private final boolean mDefaultIsNonStrongBiometricAllowed = true;
+
         public StrongAuthTracker(Context context) {
             this(context, Looper.myLooper());
         }
@@ -1657,8 +1685,21 @@
          * @return true if unlocking with a biometric method alone is allowed for {@code userId}
          * by the current strong authentication requirements.
          */
-        public boolean isBiometricAllowedForUser(int userId) {
-            return (getStrongAuthForUser(userId) & ~ALLOWING_BIOMETRIC) == 0;
+        public boolean isBiometricAllowedForUser(boolean isStrongBiometric, int userId) {
+            boolean allowed = ((getStrongAuthForUser(userId) & ~ALLOWING_BIOMETRIC) == 0);
+            if (!isStrongBiometric) {
+                allowed &= isNonStrongBiometricAllowedAfterIdleTimeout(userId);
+            }
+            return allowed;
+        }
+
+        /**
+         * @return true if unlocking with a non-strong (i.e. weak or convenience) biometric method
+         * alone is allowed for {@code userId}, otherwise returns false.
+         */
+        public boolean isNonStrongBiometricAllowedAfterIdleTimeout(int userId) {
+            return mIsNonStrongBiometricAllowedForUser.get(userId,
+                    mDefaultIsNonStrongBiometricAllowed);
         }
 
         /**
@@ -1667,6 +1708,12 @@
         public void onStrongAuthRequiredChanged(int userId) {
         }
 
+        /**
+         * Called when whether non-strong biometric is allowed for {@code userId} changed.
+         */
+        public void onIsNonStrongBiometricAllowedChanged(int userId) {
+        }
+
         protected void handleStrongAuthRequiredChanged(@StrongAuthFlags int strongAuthFlags,
                 int userId) {
             int oldValue = getStrongAuthForUser(userId);
@@ -1680,6 +1727,18 @@
             }
         }
 
+        protected void handleIsNonStrongBiometricAllowedChanged(boolean allowed,
+                int userId) {
+            boolean oldValue = isNonStrongBiometricAllowedAfterIdleTimeout(userId);
+            if (allowed != oldValue) {
+                if (allowed == mDefaultIsNonStrongBiometricAllowed) {
+                    mIsNonStrongBiometricAllowedForUser.delete(userId);
+                } else {
+                    mIsNonStrongBiometricAllowedForUser.put(userId, allowed);
+                }
+                onIsNonStrongBiometricAllowedChanged(userId);
+            }
+        }
 
         protected final IStrongAuthTracker.Stub mStub = new IStrongAuthTracker.Stub() {
             @Override
@@ -1688,10 +1747,17 @@
                 mHandler.obtainMessage(H.MSG_ON_STRONG_AUTH_REQUIRED_CHANGED,
                         strongAuthFlags, userId).sendToTarget();
             }
+
+            @Override
+            public void onIsNonStrongBiometricAllowedChanged(boolean allowed, int userId) {
+                mHandler.obtainMessage(H.MSG_ON_IS_NON_STRONG_BIOMETRIC_ALLOWED_CHANGED,
+                        allowed ? 1 : 0, userId).sendToTarget();
+            }
         };
 
         private class H extends Handler {
             static final int MSG_ON_STRONG_AUTH_REQUIRED_CHANGED = 1;
+            static final int MSG_ON_IS_NON_STRONG_BIOMETRIC_ALLOWED_CHANGED = 2;
 
             public H(Looper looper) {
                 super(looper);
@@ -1703,6 +1769,10 @@
                     case MSG_ON_STRONG_AUTH_REQUIRED_CHANGED:
                         handleStrongAuthRequiredChanged(msg.arg1, msg.arg2);
                         break;
+                    case MSG_ON_IS_NON_STRONG_BIOMETRIC_ALLOWED_CHANGED:
+                        handleIsNonStrongBiometricAllowedChanged(msg.arg1 == 1 /* allowed */,
+                                msg.arg2);
+                        break;
                 }
             }
         }
diff --git a/core/jni/android_os_storage_StorageManager.cpp b/core/jni/android_os_storage_StorageManager.cpp
index aee6733..fd3e66b 100644
--- a/core/jni/android_os_storage_StorageManager.cpp
+++ b/core/jni/android_os_storage_StorageManager.cpp
@@ -15,6 +15,7 @@
  */
 
 #define LOG_TAG "StorageManager"
+#include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/unique_fd.h>
 #include <fcntl.h>
@@ -25,11 +26,30 @@
 
 namespace android {
 
+static const char* kProcFilesystems = "/proc/filesystems";
+
+// Checks whether the passed in filesystem is listed in /proc/filesystems
+static bool IsFilesystemSupported(const std::string& fsType) {
+    std::string supported;
+    if (!android::base::ReadFileToString(kProcFilesystems, &supported)) {
+        PLOG(ERROR) << "Failed to read supported filesystems";
+        return false;
+    }
+    return supported.find(fsType + "\n") != std::string::npos;
+}
+
 jboolean android_os_storage_StorageManager_setQuotaProjectId(JNIEnv* env, jobject self,
                                                              jstring path, jlong projectId) {
     struct fsxattr fsx;
     ScopedUtfChars utf_chars_path(env, path);
 
+    static bool sdcardFsSupported = IsFilesystemSupported("sdcardfs");
+    if (sdcardFsSupported) {
+        // sdcardfs doesn't support project ID quota tracking and takes care of quota
+        // in a different way.
+        return JNI_TRUE;
+    }
+
     if (projectId > UINT32_MAX) {
         LOG(ERROR) << "Invalid project id: " << projectId;
         return JNI_FALSE;
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index 27c5a73..93449ff 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -186,6 +186,7 @@
         proxy->setSwapBehavior(SwapBehavior::kSwap_discardBuffer);
     }
     proxy->setSurface(window, enableTimeout);
+    ANativeWindow_release(window);
 }
 
 static jboolean android_view_ThreadedRenderer_pause(JNIEnv* env, jobject clazz,
diff --git a/core/jni/core_jni_helpers.h b/core/jni/core_jni_helpers.h
index f03f427..8bb4d50 100644
--- a/core/jni/core_jni_helpers.h
+++ b/core/jni/core_jni_helpers.h
@@ -47,28 +47,32 @@
 static inline jfieldID GetFieldIDOrDie(JNIEnv* env, jclass clazz, const char* field_name,
                                        const char* field_signature) {
     jfieldID res = env->GetFieldID(clazz, field_name, field_signature);
-    LOG_ALWAYS_FATAL_IF(res == NULL, "Unable to find static field %s", field_name);
+    LOG_ALWAYS_FATAL_IF(res == NULL, "Unable to find static field %s with signature %s", field_name,
+                        field_signature);
     return res;
 }
 
 static inline jmethodID GetMethodIDOrDie(JNIEnv* env, jclass clazz, const char* method_name,
                                          const char* method_signature) {
     jmethodID res = env->GetMethodID(clazz, method_name, method_signature);
-    LOG_ALWAYS_FATAL_IF(res == NULL, "Unable to find method %s", method_name);
+    LOG_ALWAYS_FATAL_IF(res == NULL, "Unable to find method %s with signature %s", method_name,
+                        method_signature);
     return res;
 }
 
 static inline jfieldID GetStaticFieldIDOrDie(JNIEnv* env, jclass clazz, const char* field_name,
                                              const char* field_signature) {
     jfieldID res = env->GetStaticFieldID(clazz, field_name, field_signature);
-    LOG_ALWAYS_FATAL_IF(res == NULL, "Unable to find static field %s", field_name);
+    LOG_ALWAYS_FATAL_IF(res == NULL, "Unable to find static field %s with signature %s", field_name,
+                        field_signature);
     return res;
 }
 
 static inline jmethodID GetStaticMethodIDOrDie(JNIEnv* env, jclass clazz, const char* method_name,
                                                const char* method_signature) {
     jmethodID res = env->GetStaticMethodID(clazz, method_name, method_signature);
-    LOG_ALWAYS_FATAL_IF(res == NULL, "Unable to find static method %s", method_name);
+    LOG_ALWAYS_FATAL_IF(res == NULL, "Unable to find static method %s with signature %s",
+                        method_name, method_signature);
     return res;
 }
 
diff --git a/core/proto/android/server/peopleservice.proto b/core/proto/android/server/peopleservice.proto
index e476c52..e65a2ab 100644
--- a/core/proto/android/server/peopleservice.proto
+++ b/core/proto/android/server/peopleservice.proto
@@ -50,6 +50,9 @@
 
   // Integer representation of conversation bit flags.
   optional int32 conversation_flags = 6;
+
+  // The phone number of the contact.
+  optional string contact_phone_number = 7;
 }
 
 // On disk data of events.
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 62e57e4..814b8ac 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -399,6 +399,9 @@
     <protected-broadcast android:name="android.intent.action.AIRPLANE_MODE" />
     <protected-broadcast android:name="android.intent.action.ADVANCED_SETTINGS" />
     <protected-broadcast android:name="android.intent.action.APPLICATION_RESTRICTIONS_CHANGED" />
+    <protected-broadcast android:name="com.android.server.adb.WIRELESS_DEBUG_PAIRED_DEVICES" />
+    <protected-broadcast android:name="com.android.server.adb.WIRELESS_DEBUG_PAIRING_RESULT" />
+    <protected-broadcast android:name="com.android.server.adb.WIRELESS_DEBUG_STATUS" />
 
     <!-- Legacy -->
     <protected-broadcast android:name="android.intent.action.ACTION_IDLE_MAINTENANCE_START" />
@@ -2771,7 +2774,7 @@
     <permission android:name="android.permission.READ_DEVICE_CONFIG"
         android:protectionLevel="signature|preinstalled" />
 
-    <!-- @SystemApi @hide Allows an application to monitor config settings access.
+    <!-- @hide Allows an application to monitor {@link android.provider.Settings.Config} access.
     <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.MONITOR_DEVICE_CONFIG_ACCESS"
         android:protectionLevel="signature"/>
@@ -3081,8 +3084,7 @@
 
     <!-- Allows SystemUI to request third party controls.
          <p>Should only be requested by the System and required by
-         ControlsService declarations.
-         @hide
+         {@link android.service.controls.ControlsProviderService} declarations.
     -->
     <permission android:name="android.permission.BIND_CONTROLS"
         android:protectionLevel="signature" />
diff --git a/core/res/res/layout/chooser_grid.xml b/core/res/res/layout/chooser_grid.xml
index c0de693..5676049 100644
--- a/core/res/res/layout/chooser_grid.xml
+++ b/core/res/res/layout/chooser_grid.xml
@@ -90,7 +90,7 @@
                 android:id="@android:id/tabcontent"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content">
-                <com.android.internal.app.ResolverViewPager
+                <com.android.internal.widget.ViewPager
                     android:id="@+id/profile_pager"
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"/>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index c15b794..70d8a02 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2460,6 +2460,12 @@
          rmem_min,rmem_def,rmem_max,wmem_min,wmem_def,wmem_max -->
     <string name="config_ethernet_tcp_buffers" translatable="false">524288,1048576,3145728,524288,1048576,2097152</string>
 
+    <!-- What source to use to estimate link upstream and downstream bandwidth capacities.
+         Default is carrier_config, but it should be set to modem if the modem is returning
+         predictive (instead of instantaneous) bandwidth estimate.
+         Values are carrier_config and modem. -->
+    <string name="config_bandwidthEstimateSource">carrier_config</string>
+
     <!-- Whether WiFi display is supported by this device.
          There are many prerequisites for this feature to work correctly.
          Here are a few of them:
@@ -2582,6 +2588,18 @@
     <string name="config_customAdbPublicKeyConfirmationSecondaryUserComponent"
             >com.android.systemui/com.android.systemui.usb.UsbDebuggingSecondaryUserActivity</string>
 
+    <!-- Name of the activity or service that prompts the user to reject, accept, or whitelist
+         a wireless network for wireless debugging.
+         Can be customized for other product types -->
+    <string name="config_customAdbWifiNetworkConfirmationComponent"
+            >com.android.systemui/com.android.systemui.wifi.WifiDebuggingActivity</string>
+
+    <!-- Name of the activity that prompts the secondary user to acknowledge she/he needs to
+         switch to the primary user to enable wireless debugging.
+         Can be customized for other product types -->
+    <string name="config_customAdbWifiNetworkConfirmationSecondaryUserComponent"
+            >com.android.systemui/com.android.systemui.wifi.WifiDebuggingSecondaryUserActivity</string>
+
     <!-- Component name of the activity that shows the usb containment status. -->
     <string name="config_usbContaminantActivity" translatable="false"
             >com.android.systemui/com.android.systemui.usb.UsbContaminantActivity</string>
@@ -3532,6 +3550,8 @@
      mode -->
     <string-array translatable="false" name="config_priorityOnlyDndExemptPackages">
         <item>com.android.dialer</item>
+        <item>com.android.systemui</item>
+        <item>android</item>
     </string-array>
 
     <!-- The default value for transition animation scale found in developer settings.
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 48049b4..4f221d0 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -781,9 +781,6 @@
 
     <dimen name="chooser_action_button_icon_size">18dp</dimen>
 
-    <!-- Assistant handles -->
-    <dimen name="assist_handle_shadow_radius">2dp</dimen>
-
     <!-- For Waterfall Display -->
     <dimen name="waterfall_display_left_edge_size">0px</dimen>
     <dimen name="waterfall_display_top_edge_size">0px</dimen>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index d513e2b..1445736 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -3527,6 +3527,12 @@
     <!-- Message of notification shown when ADB is actively connected to the phone. -->
     <string name="adb_active_notification_message">Tap to turn off USB debugging</string>
     <string name="adb_active_notification_message" product="tv">Select to disable USB debugging.</string>
+    <!-- Title of notification shown when ADB Wireless is actively connected to the phone. [CHAR LIMIT=NONE] -->
+    <string name="adbwifi_active_notification_title">Wireless debugging connected</string>
+    <!-- Message of notification shown when ADB Wireless is actively connected to the phone. [CHAR LIMIT=NONE] -->
+    <string name="adbwifi_active_notification_message">Tap to turn off wireless debugging</string>
+    <!-- Message of notification shown when ADB Wireless is actively connected to the TV. [CHAR LIMIT=NONE] -->
+    <string name="adbwifi_active_notification_message" product="tv">Select to disable wireless debugging.</string>
 
     <!-- Title of notification shown when Test Harness Mode is enabled. [CHAR LIMIT=NONE] -->
     <string name="test_harness_mode_notification_title">Test Harness Mode enabled</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 85c2a2a..a3da411 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -473,6 +473,7 @@
   <java-symbol type="integer" name="config_num_physical_slots" />
   <java-symbol type="array" name="config_integrityRuleProviderPackages" />
   <java-symbol type="bool" name="config_useAssistantVolume" />
+  <java-symbol type="string" name="config_bandwidthEstimateSource" />
 
   <java-symbol type="color" name="tab_indicator_text_v4" />
 
@@ -2008,6 +2009,8 @@
   <java-symbol type="string" name="accessibility_binding_label" />
   <java-symbol type="string" name="adb_active_notification_message" />
   <java-symbol type="string" name="adb_active_notification_title" />
+  <java-symbol type="string" name="adbwifi_active_notification_message" />
+  <java-symbol type="string" name="adbwifi_active_notification_title" />
   <java-symbol type="string" name="test_harness_mode_notification_title" />
   <java-symbol type="string" name="test_harness_mode_notification_message" />
   <java-symbol type="string" name="console_running_notification_title" />
@@ -2153,6 +2156,8 @@
   <java-symbol type="integer" name="config_attentiveWarningDuration" />
   <java-symbol type="string" name="config_customAdbPublicKeyConfirmationComponent" />
   <java-symbol type="string" name="config_customAdbPublicKeyConfirmationSecondaryUserComponent" />
+  <java-symbol type="string" name="config_customAdbWifiNetworkConfirmationComponent" />
+  <java-symbol type="string" name="config_customAdbWifiNetworkConfirmationSecondaryUserComponent" />
   <java-symbol type="string" name="config_customVpnConfirmDialogComponent" />
   <java-symbol type="string" name="config_customVpnAlwaysOnDisconnectedDialogComponent" />
   <java-symbol type="string" name="config_platformVpnConfirmDialogComponent" />
@@ -3839,9 +3844,6 @@
   <!-- For App Standby -->
   <java-symbol type="string" name="as_app_forced_to_restricted_bucket" />
 
-  <!-- Assistant handles -->
-  <java-symbol type="dimen" name="assist_handle_shadow_radius" />
-
   <!-- For Waterfall Display -->
   <java-symbol type="dimen" name="waterfall_display_left_edge_size" />
   <java-symbol type="dimen" name="waterfall_display_top_edge_size" />
diff --git a/core/res/res/xml/power_profile.xml b/core/res/res/xml/power_profile.xml
index 899d630..d8ec72f 100644
--- a/core/res/res/xml/power_profile.xml
+++ b/core/res/res/xml/power_profile.xml
@@ -51,6 +51,12 @@
       <value>0.1</value> <!-- ~1mA -->
   </array>
 
+  <!-- Additional power consumption by CPU excluding cluster and core when
+       running -->
+  <array name="cpu.active">
+      <value>0.1</value>
+  </array>
+
   <!-- A list of heterogeneous CPU clusters, where the value for each cluster represents the
        number of CPU cores for that cluster.
 
diff --git a/core/tests/coretests/Android.bp b/core/tests/coretests/Android.bp
index 8e4e684..33fead6 100644
--- a/core/tests/coretests/Android.bp
+++ b/core/tests/coretests/Android.bp
@@ -83,21 +83,13 @@
         ":FrameworksCoreTests_install_bad_dex",
         ":FrameworksCoreTests_install_complete_package_info",
         ":FrameworksCoreTests_install_decl_perm",
-        ":FrameworksCoreTests_install_intent_filters",
         ":FrameworksCoreTests_install_jni_lib_open_from_apk",
         ":FrameworksCoreTests_install_loc_auto",
         ":FrameworksCoreTests_install_loc_internal",
         ":FrameworksCoreTests_install_loc_sdcard",
         ":FrameworksCoreTests_install_loc_unspecified",
-        ":FrameworksCoreTests_install_split_base",
-        ":FrameworksCoreTests_install_split_feature_a",
         ":FrameworksCoreTests_install_use_perm_good",
         ":FrameworksCoreTests_install_uses_feature",
-        ":FrameworksCoreTests_install_uses_sdk_0",
-        ":FrameworksCoreTests_install_uses_sdk_q0",
-        ":FrameworksCoreTests_install_uses_sdk_r",
-        ":FrameworksCoreTests_install_uses_sdk_r0",
-        ":FrameworksCoreTests_install_uses_sdk_r5",
         ":FrameworksCoreTests_install_verifier_bad",
         ":FrameworksCoreTests_install_verifier_good",
         ":FrameworksCoreTests_keyset_permdef_sa_unone",
diff --git a/core/tests/coretests/apks/install-split-base/Android.bp b/core/tests/coretests/apks/install-split-base/Android.bp
deleted file mode 100644
index ddf75b2..0000000
--- a/core/tests/coretests/apks/install-split-base/Android.bp
+++ /dev/null
@@ -1,6 +0,0 @@
-android_test_helper_app {
-    name: "FrameworksCoreTests_install_split_base",
-    defaults: ["FrameworksCoreTests_apks_defaults"],
-
-    srcs: ["**/*.java"],
-}
diff --git a/core/tests/coretests/apks/install_intent_filters/Android.bp b/core/tests/coretests/apks/install_intent_filters/Android.bp
deleted file mode 100644
index 6cc5eba..0000000
--- a/core/tests/coretests/apks/install_intent_filters/Android.bp
+++ /dev/null
@@ -1,7 +0,0 @@
-android_test_helper_app {
-    name: "FrameworksCoreTests_install_intent_filters",
-    defaults: ["FrameworksCoreTests_apks_defaults"],
-
-    srcs: ["**/*.java"],
-}
-
diff --git a/core/tests/coretests/apks/install_uses_sdk/Android.bp b/core/tests/coretests/apks/install_uses_sdk/Android.bp
deleted file mode 100644
index 92b09ed..0000000
--- a/core/tests/coretests/apks/install_uses_sdk/Android.bp
+++ /dev/null
@@ -1,39 +0,0 @@
-android_test_helper_app {
-    name: "FrameworksCoreTests_install_uses_sdk_r0",
-    defaults: ["FrameworksCoreTests_apks_defaults"],
-    manifest: "AndroidManifest-r0.xml",
-
-    srcs: ["**/*.java"],
-}
-
-android_test_helper_app {
-    name: "FrameworksCoreTests_install_uses_sdk_r5",
-    defaults: ["FrameworksCoreTests_apks_defaults"],
-    manifest: "AndroidManifest-r5.xml",
-
-    srcs: ["**/*.java"],
-}
-
-android_test_helper_app {
-    name: "FrameworksCoreTests_install_uses_sdk_q0",
-    defaults: ["FrameworksCoreTests_apks_defaults"],
-    manifest: "AndroidManifest-q0.xml",
-
-    srcs: ["**/*.java"],
-}
-
-android_test_helper_app {
-    name: "FrameworksCoreTests_install_uses_sdk_r",
-    defaults: ["FrameworksCoreTests_apks_defaults"],
-    manifest: "AndroidManifest-r.xml",
-
-    srcs: ["**/*.java"],
-}
-
-android_test_helper_app {
-    name: "FrameworksCoreTests_install_uses_sdk_0",
-    defaults: ["FrameworksCoreTests_apks_defaults"],
-    manifest: "AndroidManifest-0.xml",
-
-    srcs: ["**/*.java"],
-}
diff --git a/core/tests/coretests/src/android/accessibilityservice/AccessibilityShortcutInfoTest.java b/core/tests/coretests/src/android/accessibilityservice/AccessibilityShortcutInfoTest.java
index 82a7b2c..f0e70a5 100644
--- a/core/tests/coretests/src/android/accessibilityservice/AccessibilityShortcutInfoTest.java
+++ b/core/tests/coretests/src/android/accessibilityservice/AccessibilityShortcutInfoTest.java
@@ -90,6 +90,12 @@
     }
 
     @Test
+    public void testLoadAnimatedImage() {
+        assertNotNull("Can't find animated image",
+                mShortcutInfo.loadAnimatedImage(mTargetContext));
+    }
+
+    @Test
     public void testHtmlDescription() {
         final String htmlDescription = mTargetContext.getResources()
                 .getString(R.string.accessibility_shortcut_html_description);
diff --git a/core/tests/coretests/src/android/content/ContentResolverTest.java b/core/tests/coretests/src/android/content/ContentResolverTest.java
index 78c4420..1737bd0 100644
--- a/core/tests/coretests/src/android/content/ContentResolverTest.java
+++ b/core/tests/coretests/src/android/content/ContentResolverTest.java
@@ -234,4 +234,12 @@
         assertThat(type).isNull();
         assertThat(end).isLessThan(start + 5000);
     }
+
+    @Test
+    public void testCanonicalize() {
+        Uri canonical = mResolver.canonicalize(
+                Uri.parse("content://android.content.FakeProviderRemote/something"));
+        assertThat(canonical).isEqualTo(
+                Uri.parse("content://android.content.FakeProviderRemote/canonical"));
+    }
 }
diff --git a/core/tests/coretests/src/android/content/ContextTest.java b/core/tests/coretests/src/android/content/ContextTest.java
index f074233..f0997a6 100644
--- a/core/tests/coretests/src/android/content/ContextTest.java
+++ b/core/tests/coretests/src/android/content/ContextTest.java
@@ -16,11 +16,13 @@
 
 package android.content;
 
+import static android.view.Display.DEFAULT_DISPLAY;
+
 import static org.junit.Assert.assertEquals;
 
 import android.app.ActivityThread;
+import android.hardware.display.DisplayManager;
 import android.os.UserHandle;
-import android.view.WindowManager;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.SmallTest;
@@ -45,17 +47,16 @@
         final Context testContext =
                 InstrumentationRegistry.getInstrumentation().getTargetContext();
 
-        assertEquals(testContext.getDisplay().getDisplayId(), testContext.getDisplayId());
+        assertEquals(testContext.getDisplayNoVerify().getDisplayId(), testContext.getDisplayId());
     }
 
-    // TODO(b/128338354): Re-visit this test after introducing WindowContext
     @Test
     public void testDisplayIdForDefaultDisplayContext() {
         final Context testContext =
                 InstrumentationRegistry.getInstrumentation().getTargetContext();
-        final WindowManager wm = testContext.getSystemService(WindowManager.class);
+        final DisplayManager dm = testContext.getSystemService(DisplayManager.class);
         final Context defaultDisplayContext =
-                testContext.createDisplayContext(wm.getDefaultDisplay());
+                testContext.createDisplayContext(dm.getDisplay(DEFAULT_DISPLAY));
 
         assertEquals(defaultDisplayContext.getDisplay().getDisplayId(),
                 defaultDisplayContext.getDisplayId());
diff --git a/core/tests/coretests/src/android/content/FakeProviderRemote.java b/core/tests/coretests/src/android/content/FakeProviderRemote.java
index 7b9bdbc..1d7ba5d 100644
--- a/core/tests/coretests/src/android/content/FakeProviderRemote.java
+++ b/core/tests/coretests/src/android/content/FakeProviderRemote.java
@@ -54,4 +54,10 @@
     public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
         return 0;
     }
+
+    @Override
+    public Uri canonicalize(Uri uri) {
+        return new Uri.Builder().scheme(uri.getScheme()).authority(uri.getAuthority())
+                .appendPath("canonical").build();
+    }
 }
diff --git a/core/tests/coretests/src/android/content/integrity/IntegrityFormulaTest.java b/core/tests/coretests/src/android/content/integrity/IntegrityFormulaTest.java
index 62c9c98..7e4c138 100644
--- a/core/tests/coretests/src/android/content/integrity/IntegrityFormulaTest.java
+++ b/core/tests/coretests/src/android/content/integrity/IntegrityFormulaTest.java
@@ -109,8 +109,8 @@
     @Test
     public void createGreaterThanOrEqualsToFormula_versionCode() {
         int versionCode = 12;
-        IntegrityFormula formula = IntegrityFormula.Application.versionCodeGreaterThanOrEqualTo(
-                versionCode);
+        IntegrityFormula formula =
+                IntegrityFormula.Application.versionCodeGreaterThanOrEqualTo(versionCode);
 
         AtomicFormula.LongAtomicFormula stringAtomicFormula =
                 (AtomicFormula.LongAtomicFormula) formula;
@@ -124,11 +124,11 @@
     public void createIsTrueFormula_preInstalled() {
         IntegrityFormula formula = IntegrityFormula.Application.isPreInstalled();
 
-        AtomicFormula.BooleanAtomicFormula stringAtomicFormula =
+        AtomicFormula.BooleanAtomicFormula booleanAtomicFormula =
                 (AtomicFormula.BooleanAtomicFormula) formula;
 
-        assertThat(stringAtomicFormula.getKey()).isEqualTo(AtomicFormula.PRE_INSTALLED);
-        assertThat(stringAtomicFormula.getValue()).isTrue();
+        assertThat(booleanAtomicFormula.getKey()).isEqualTo(AtomicFormula.PRE_INSTALLED);
+        assertThat(booleanAtomicFormula.getValue()).isTrue();
     }
 
     @Test
@@ -136,8 +136,8 @@
         String packageName = "com.test.package";
         String certificateName = "certificate";
         IntegrityFormula formula1 = IntegrityFormula.Application.packageNameEquals(packageName);
-        IntegrityFormula formula2 = IntegrityFormula.Application.certificatesContain(
-                certificateName);
+        IntegrityFormula formula2 =
+                IntegrityFormula.Application.certificatesContain(certificateName);
 
         IntegrityFormula compoundFormula = IntegrityFormula.all(formula1, formula2);
 
@@ -149,8 +149,8 @@
         String packageName = "com.test.package";
         String certificateName = "certificate";
         IntegrityFormula formula1 = IntegrityFormula.Application.packageNameEquals(packageName);
-        IntegrityFormula formula2 = IntegrityFormula.Application.certificatesContain(
-                certificateName);
+        IntegrityFormula formula2 =
+                IntegrityFormula.Application.certificatesContain(certificateName);
 
         IntegrityFormula compoundFormula = IntegrityFormula.any(formula1, formula2);
 
@@ -166,4 +166,29 @@
 
         assertThat(compoundFormula.getTag()).isEqualTo(COMPOUND_FORMULA_TAG);
     }
+
+    @Test
+    public void createIsTrueFormula_stampNotTrusted() {
+        IntegrityFormula formula = IntegrityFormula.SourceStamp.notTrusted();
+
+        AtomicFormula.BooleanAtomicFormula booleanAtomicFormula =
+                (AtomicFormula.BooleanAtomicFormula) formula;
+
+        assertThat(booleanAtomicFormula.getKey()).isEqualTo(AtomicFormula.STAMP_TRUSTED);
+        assertThat(booleanAtomicFormula.getValue()).isFalse();
+    }
+
+    @Test
+    public void createEqualsFormula_stampCertificateHash() {
+        String stampCertificateHash = "test-cert";
+        IntegrityFormula formula =
+                IntegrityFormula.SourceStamp.stampCertificateHashEquals(stampCertificateHash);
+
+        AtomicFormula.StringAtomicFormula stringAtomicFormula =
+                (AtomicFormula.StringAtomicFormula) formula;
+
+        assertThat(stringAtomicFormula.getKey()).isEqualTo(AtomicFormula.STAMP_CERTIFICATE_HASH);
+        assertThat(stringAtomicFormula.getValue()).matches(stampCertificateHash);
+        assertThat(stringAtomicFormula.getIsHashedValue()).isTrue();
+    }
 }
diff --git a/core/tests/coretests/src/android/service/controls/ControlProviderServiceTest.java b/core/tests/coretests/src/android/service/controls/ControlProviderServiceTest.java
index 78c88d7..4c2ca7e 100644
--- a/core/tests/coretests/src/android/service/controls/ControlProviderServiceTest.java
+++ b/core/tests/coretests/src/android/service/controls/ControlProviderServiceTest.java
@@ -25,9 +25,13 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.Manifest;
 import android.app.PendingIntent;
+import android.content.ComponentName;
+import android.content.Context;
 import android.content.IIntentSender;
 import android.content.Intent;
+import android.content.res.Resources;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.IBinder;
@@ -44,6 +48,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
@@ -59,6 +64,11 @@
 @RunWith(AndroidJUnit4.class)
 public class ControlProviderServiceTest {
 
+    private static final ComponentName TEST_SYSUI_COMPONENT =
+            ComponentName.unflattenFromString("sysui/.test.cls");
+    private static final ComponentName TEST_COMPONENT =
+            ComponentName.unflattenFromString("test.pkg/.test.cls");
+
     private IBinder mToken = new Binder();
     @Mock
     private IControlsActionCallback.Stub mActionCallback;
@@ -66,6 +76,12 @@
     private IControlsSubscriber.Stub mSubscriber;
     @Mock
     private IIntentSender mIIntentSender;
+    @Mock
+    private Resources mResources;
+    @Mock
+    private Context mContext;
+    @Captor
+    private ArgumentCaptor<Intent> mIntentArgumentCaptor;
 
     private PendingIntent mPendingIntent;
     private FakeControlsProviderService mControlsProviderService;
@@ -81,6 +97,10 @@
         when(mSubscriber.asBinder()).thenCallRealMethod();
         when(mSubscriber.queryLocalInterface(any())).thenReturn(mSubscriber);
 
+        when(mResources.getString(com.android.internal.R.string.config_systemUIServiceComponent))
+                .thenReturn(TEST_SYSUI_COMPONENT.flattenToString());
+        when(mContext.getResources()).thenReturn(mResources);
+
         Bundle b = new Bundle();
         b.putBinder(ControlsProviderService.CALLBACK_TOKEN, mToken);
         Intent intent = new Intent();
@@ -223,6 +243,21 @@
                 ControlAction.RESPONSE_OK);
     }
 
+    @Test
+    public void testRequestAdd() {
+        Control control = new Control.StatelessBuilder("TEST_ID", mPendingIntent).build();
+        ControlsProviderService.requestAddControl(mContext, TEST_COMPONENT, control);
+
+        verify(mContext).sendBroadcast(mIntentArgumentCaptor.capture(),
+                eq(Manifest.permission.BIND_CONTROLS));
+        Intent intent = mIntentArgumentCaptor.getValue();
+        assertEquals(ControlsProviderService.ACTION_ADD_CONTROL, intent.getAction());
+        assertEquals(TEST_SYSUI_COMPONENT.getPackageName(), intent.getPackage());
+        assertEquals(TEST_COMPONENT, intent.getParcelableExtra(Intent.EXTRA_COMPONENT_NAME));
+        assertTrue(equals(control,
+                intent.getParcelableExtra(ControlsProviderService.EXTRA_CONTROL)));
+    }
+
     private static boolean equals(Control c1, Control c2) {
         if (c1 == c2) return true;
         if (c1 == null || c2 == null) return false;
diff --git a/core/tests/coretests/src/android/util/EventLogTest.java b/core/tests/coretests/src/android/util/EventLogTest.java
new file mode 100644
index 0000000..94e72c4
--- /dev/null
+++ b/core/tests/coretests/src/android/util/EventLogTest.java
@@ -0,0 +1,74 @@
+/*
+ * 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.util;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.util.EventLog.Event;
+
+import junit.framework.AssertionFailedError;
+
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/** Unit tests for {@link android.util.EventLog} */
+public class EventLogTest {
+
+    @Test
+    public void testWithNewData() throws Throwable {
+        Event event = createEvent(() -> {
+            EventLog.writeEvent(314,  123);
+        }, 314);
+
+        assertTrue(event.withNewData(12345678L).getData().equals(12345678L));
+        assertTrue(event.withNewData(2.718f).getData().equals(2.718f));
+        assertTrue(event.withNewData("test string").getData().equals("test string"));
+
+        Object[] objects = ((Object[]) event.withNewData(
+                new Object[] {111, 2.22f, 333L, "444"}).getData());
+        assertEquals(4, objects.length);
+        assertTrue(objects[0].equals(111));
+        assertTrue(objects[1].equals(2.22f));
+        assertTrue(objects[2].equals(333L));
+        assertTrue(objects[3].equals("444"));
+    }
+
+    /**
+     * Creates an Event object. Only the native code has the serialization and deserialization logic
+     * so need to actually emit a real log in order to generate the object.
+     */
+    private Event createEvent(Runnable generator, int expectedTag) throws Exception {
+        Long markerData = System.currentTimeMillis();
+        EventLog.writeEvent(expectedTag, markerData);
+        generator.run();
+
+        List<Event> events = new ArrayList<>();
+        // Give the message some time to show up in the log
+        Thread.sleep(20);
+        EventLog.readEvents(new int[] {expectedTag}, events);
+        for (int i = 0; i < events.size() - 1; i++) {
+            if (markerData.equals(events.get(i).getData())) {
+                return events.get(i + 1);
+            }
+        }
+        throw new AssertionFailedError("Unable to locate marker event");
+    }
+}
diff --git a/core/tests/coretests/src/android/util/LongSparseArrayTest.java b/core/tests/coretests/src/android/util/LongSparseArrayTest.java
new file mode 100644
index 0000000..bf3f0f5
--- /dev/null
+++ b/core/tests/coretests/src/android/util/LongSparseArrayTest.java
@@ -0,0 +1,54 @@
+/*
+ * 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.util;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import com.android.internal.util.function.LongObjPredicate;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests for {@link LongSparseArray}.
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class LongSparseArrayTest {
+    @Test
+    public void testRemoveIf() {
+        final LongSparseArray<Integer> sparseArray = new LongSparseArray();
+        for (int i = 0; i < 10; ++i) {
+            for (int j = 100; j < 110; ++j) {
+                sparseArray.put(i, j);
+                sparseArray.put(-i, j);
+                sparseArray.put(j, -i);
+                sparseArray.put(-j, -i);
+            }
+        }
+
+        final LongObjPredicate<Integer> predicate = (value, obj) -> (value < 0 && obj < 0);
+        sparseArray.removeIf(predicate);
+
+        for (int i = 0; i < sparseArray.size(); ++i) {
+            assertThat(predicate.test(sparseArray.keyAt(i), sparseArray.valueAt(i)))
+                    .isFalse();
+        }
+    }
+}
diff --git a/core/tests/coretests/src/android/view/CutoutSpecificationTest.java b/core/tests/coretests/src/android/view/CutoutSpecificationTest.java
index b41f90c..7872810 100644
--- a/core/tests/coretests/src/android/view/CutoutSpecificationTest.java
+++ b/core/tests/coretests/src/android/view/CutoutSpecificationTest.java
@@ -21,10 +21,27 @@
 import static org.testng.Assert.assertThrows;
 
 import android.graphics.Rect;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
+/**
+ * Tests for {@link CutoutSpecification} used by {@link DisplayCutout}.
+ *
+ * <p>Build/Install/Run:
+ *  atest FrameworksCoreTests:CutoutSpecificationTest
+ *
+ * <p>This test class is a part of Window Manager Service tests and specified in
+ * {@link com.android.server.wm.test.filters.FrameworksTestsFilter}.
+ */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+@Presubmit
 public class CutoutSpecificationTest {
     private static final String WITHOUT_BIND_CUTOUT_SPECIFICATION = "M 0,0\n"
             + "h 48\n"
@@ -344,7 +361,7 @@
                         .parse("@bottom"
                                 + "M 0,0\n"
                                 + "v -10\n"
-                                + "h 10\n"
+                                + "h -10\n"
                                 + "v 10\n"
                                 + "z\n"
                                 + "@right\n"
diff --git a/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java b/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java
index 7c78bce..7f0e0d2 100644
--- a/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java
+++ b/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java
@@ -61,7 +61,7 @@
                 .setName("testSurface")
                 .build();
         InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
-            ViewRootImpl viewRootImpl = new ViewRootImpl(mContext, mContext.getDisplay());
+            ViewRootImpl viewRootImpl = new ViewRootImpl(mContext, mContext.getDisplayNoVerify());
             try {
                 viewRootImpl.setView(new TextView(mContext), new LayoutParams(), null);
             } catch (BadTokenException e) {
diff --git a/core/tests/coretests/src/android/view/InsetsControllerTest.java b/core/tests/coretests/src/android/view/InsetsControllerTest.java
index 24fe2a0..7737b1a 100644
--- a/core/tests/coretests/src/android/view/InsetsControllerTest.java
+++ b/core/tests/coretests/src/android/view/InsetsControllerTest.java
@@ -110,7 +110,7 @@
         InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
             Context context = InstrumentationRegistry.getTargetContext();
             // cannot mock ViewRootImpl since it's final.
-            mViewRoot = new ViewRootImpl(context, context.getDisplay());
+            mViewRoot = new ViewRootImpl(context, context.getDisplayNoVerify());
             try {
                 mViewRoot.setView(new TextView(context), new LayoutParams(), null);
             } catch (BadTokenException e) {
diff --git a/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java b/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java
index 5e9e2f0..754c679 100644
--- a/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java
+++ b/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java
@@ -77,7 +77,8 @@
         instrumentation.runOnMainSync(() -> {
             final Context context = instrumentation.getTargetContext();
             // cannot mock ViewRootImpl since it's final.
-            final ViewRootImpl viewRootImpl = new ViewRootImpl(context, context.getDisplay());
+            final ViewRootImpl viewRootImpl = new ViewRootImpl(context,
+                    context.getDisplayNoVerify());
             try {
                 viewRootImpl.setView(new TextView(context), new LayoutParams(), null);
             } catch (BadTokenException e) {
diff --git a/core/tests/coretests/src/android/view/ViewRootImplTest.java b/core/tests/coretests/src/android/view/ViewRootImplTest.java
index df6ed8c..e2adbcc 100644
--- a/core/tests/coretests/src/android/view/ViewRootImplTest.java
+++ b/core/tests/coretests/src/android/view/ViewRootImplTest.java
@@ -61,7 +61,7 @@
 
         InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
             mViewRootImpl = new ViewRootImplAccessor(
-                    new ViewRootImpl(mContext, mContext.getDisplay()));
+                    new ViewRootImpl(mContext, mContext.getDisplayNoVerify()));
         });
     }
 
diff --git a/core/tests/coretests/src/android/widget/EditorCursorDragTest.java b/core/tests/coretests/src/android/widget/EditorCursorDragTest.java
index d7abfcc..0a094c61d 100644
--- a/core/tests/coretests/src/android/widget/EditorCursorDragTest.java
+++ b/core/tests/coretests/src/android/widget/EditorCursorDragTest.java
@@ -50,7 +50,6 @@
 
 import com.google.common.base.Strings;
 
-import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -69,7 +68,6 @@
     public ActivityTestRule<TextViewActivity> mActivityRule = new ActivityTestRule<>(
             TextViewActivity.class);
 
-    private boolean mOriginalFlagValue;
     private Instrumentation mInstrumentation;
     private Activity mActivity;
 
@@ -77,13 +75,6 @@
     public void before() throws Throwable {
         mInstrumentation = InstrumentationRegistry.getInstrumentation();
         mActivity = mActivityRule.getActivity();
-        mOriginalFlagValue = Editor.FLAG_ENABLE_CURSOR_DRAG;
-        Editor.FLAG_ENABLE_CURSOR_DRAG = true;
-    }
-
-    @After
-    public void after() throws Throwable {
-        Editor.FLAG_ENABLE_CURSOR_DRAG = mOriginalFlagValue;
     }
 
     @Test
diff --git a/core/tests/coretests/src/android/widget/TextViewActivityTest.java b/core/tests/coretests/src/android/widget/TextViewActivityTest.java
index 0c38e71..88a6f9e 100644
--- a/core/tests/coretests/src/android/widget/TextViewActivityTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewActivityTest.java
@@ -31,8 +31,8 @@
 import static android.widget.espresso.TextViewActions.doubleTapAndDragOnText;
 import static android.widget.espresso.TextViewActions.doubleTapHandle;
 import static android.widget.espresso.TextViewActions.dragHandle;
-import static android.widget.espresso.TextViewActions.longPressAndDragOnText;
 import static android.widget.espresso.TextViewActions.longPressAndDragHandle;
+import static android.widget.espresso.TextViewActions.longPressAndDragOnText;
 import static android.widget.espresso.TextViewActions.longPressHandle;
 import static android.widget.espresso.TextViewActions.longPressOnTextAtIndex;
 import static android.widget.espresso.TextViewAssertions.doesNotHaveStyledText;
@@ -514,29 +514,26 @@
         onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.indexOf("f")));
     }
 
+    private void enableFlagsForInsertionHandleGestures() {
+        final TextView textView = mActivity.findViewById(R.id.textview);
+        final Editor editor = textView.getEditorForTesting();
+        editor.setFlagCursorDragFromAnywhereEnabled(true);
+        editor.setFlagInsertionHandleGesturesEnabled(true);
+        // Note: We don't need to reset these flags explicitly at the end of each test, because a
+        // fresh TextView and Editor will be created for each test.
+    }
+
     @Test
     public void testInsertionHandle_touchThrough() {
-        final TextView textView = mActivity.findViewById(R.id.textview);
-        boolean cursorControlEnabled = textView.getEditorForTesting().getCursorControlEnabled();
-        boolean cursorDragEnabled = Editor.FLAG_ENABLE_CURSOR_DRAG;
-        textView.getEditorForTesting().setCursorControlEnabled(true);
-        Editor.FLAG_ENABLE_CURSOR_DRAG = true;
-
+        enableFlagsForInsertionHandleGestures();
         testInsertionHandle();
         testInsertionHandle_multiLine();
-
-        textView.getEditorForTesting().setCursorControlEnabled(cursorControlEnabled);
-        Editor.FLAG_ENABLE_CURSOR_DRAG = cursorDragEnabled;
     }
 
     @Test
     public void testInsertionHandle_longPressToSelect() {
-        // This test only makes sense when Cursor Control flag is enabled.
+        enableFlagsForInsertionHandleGestures();
         final TextView textView = mActivity.findViewById(R.id.textview);
-        boolean cursorControlEnabled = textView.getEditorForTesting().getCursorControlEnabled();
-        boolean cursorDragEnabled = Editor.FLAG_ENABLE_CURSOR_DRAG;
-        textView.getEditorForTesting().setCursorControlEnabled(true);
-        Editor.FLAG_ENABLE_CURSOR_DRAG = true;
 
         final String text = "hello the world";
         onView(withId(R.id.textview)).perform(replaceText(text));
@@ -546,20 +543,12 @@
 
         onHandleView(com.android.internal.R.id.insertion_handle).perform(longPressHandle(textView));
         onView(withId(R.id.textview)).check(hasSelection("world"));
-
-        textView.getEditorForTesting().setCursorControlEnabled(cursorControlEnabled);
-        Editor.FLAG_ENABLE_CURSOR_DRAG = cursorDragEnabled;
     }
 
     @Test
     public void testInsertionHandle_longPressAndDragToSelect() {
-        // This test only makes sense when Cursor Control flag is enabled.
+        enableFlagsForInsertionHandleGestures();
         final TextView textView = mActivity.findViewById(R.id.textview);
-        boolean cursorControlEnabled = textView.getEditorForTesting().getCursorControlEnabled();
-        boolean cursorDragEnabled = Editor.FLAG_ENABLE_CURSOR_DRAG;
-        textView.getEditorForTesting().setCursorControlEnabled(true);
-        Editor.FLAG_ENABLE_CURSOR_DRAG = true;
-
         final String text = "hello the world";
         onView(withId(R.id.textview)).perform(replaceText(text));
 
@@ -569,19 +558,12 @@
         onHandleView(com.android.internal.R.id.insertion_handle)
                 .perform(longPressAndDragHandle(textView, Handle.INSERTION, text.indexOf('t')));
         onView(withId(R.id.textview)).check(hasSelection("the world"));
-
-        textView.getEditorForTesting().setCursorControlEnabled(cursorControlEnabled);
-        Editor.FLAG_ENABLE_CURSOR_DRAG = cursorDragEnabled;
     }
 
     @Test
     public void testInsertionHandle_doubleTapToSelect() {
-        // This test only makes sense when Cursor Control flag is enabled.
+        enableFlagsForInsertionHandleGestures();
         final TextView textView = mActivity.findViewById(R.id.textview);
-        boolean cursorControlEnabled = textView.getEditorForTesting().getCursorControlEnabled();
-        boolean cursorDragEnabled = Editor.FLAG_ENABLE_CURSOR_DRAG;
-        textView.getEditorForTesting().setCursorControlEnabled(true);
-        Editor.FLAG_ENABLE_CURSOR_DRAG = true;
 
         final String text = "hello the world";
         onView(withId(R.id.textview)).perform(replaceText(text));
@@ -591,19 +573,12 @@
 
         onHandleView(com.android.internal.R.id.insertion_handle).perform(doubleTapHandle(textView));
         onView(withId(R.id.textview)).check(hasSelection("world"));
-
-        textView.getEditorForTesting().setCursorControlEnabled(cursorControlEnabled);
-        Editor.FLAG_ENABLE_CURSOR_DRAG = cursorDragEnabled;
     }
 
     @Test
     public void testInsertionHandle_doubleTapAndDragToSelect() {
-        // This test only makes sense when Cursor Control flag is enabled.
+        enableFlagsForInsertionHandleGestures();
         final TextView textView = mActivity.findViewById(R.id.textview);
-        boolean cursorControlEnabled = textView.getEditorForTesting().getCursorControlEnabled();
-        boolean cursorDragEnabled = Editor.FLAG_ENABLE_CURSOR_DRAG;
-        textView.getEditorForTesting().setCursorControlEnabled(true);
-        Editor.FLAG_ENABLE_CURSOR_DRAG = true;
 
         final String text = "hello the world";
         onView(withId(R.id.textview)).perform(replaceText(text));
@@ -614,9 +589,6 @@
         onHandleView(com.android.internal.R.id.insertion_handle)
                 .perform(doubleTapAndDragHandle(textView, Handle.INSERTION, text.indexOf('t')));
         onView(withId(R.id.textview)).check(hasSelection("the world"));
-
-        textView.getEditorForTesting().setCursorControlEnabled(cursorControlEnabled);
-        Editor.FLAG_ENABLE_CURSOR_DRAG = cursorDragEnabled;
     }
 
     @Test
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/core/tests/coretests/src/com/android/internal/policy/DecorContextTest.java b/core/tests/coretests/src/com/android/internal/policy/DecorContextTest.java
index cdcf23f..3e40466 100644
--- a/core/tests/coretests/src/com/android/internal/policy/DecorContextTest.java
+++ b/core/tests/coretests/src/com/android/internal/policy/DecorContextTest.java
@@ -53,7 +53,10 @@
 
     @Test
     public void testDecorContextWithDefaultDisplay() {
-        DecorContext context = new DecorContext(mContext.getApplicationContext(), mContext);
+        Display defaultDisplay = new Display(DisplayManagerGlobal.getInstance(), DEFAULT_DISPLAY,
+                new DisplayInfo(), DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS);
+        DecorContext context = new DecorContext(mContext.getApplicationContext(),
+                mContext.createDisplayContext(defaultDisplay));
 
         assertDecorContextDisplay(DEFAULT_DISPLAY, context);
     }
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 08b30f7..78c7b76d 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -410,6 +410,7 @@
     <privapp-permissions package="com.android.dynsystem">
         <permission name="android.permission.REBOOT"/>
         <permission name="android.permission.MANAGE_DYNAMIC_SYSTEM"/>
+        <permission name="android.permission.READ_OEM_UNLOCK_STATE"/>
     </privapp-permissions>
     <privapp-permissions package="com.android.settings">
         <permission name="android.permission.INSTALL_DYNAMIC_SYSTEM"/>
diff --git a/graphics/java/android/graphics/Outline.java b/graphics/java/android/graphics/Outline.java
index c12159c..5858e39 100644
--- a/graphics/java/android/graphics/Outline.java
+++ b/graphics/java/android/graphics/Outline.java
@@ -280,7 +280,10 @@
      * {@link android.os.Build.VERSION_CODES#Q}, it is no longer required to be
      * convex.
      *
-     * @deprecated The path is no longer required to be convex. Use {@link #setPath} instead.
+     * @deprecated As of {@link android.os.Build.VERSION_CODES#Q}, the restriction
+     * that the path must be convex is removed. However, the API is misnamed until
+     * {@link android.os.Build.VERSION_CODES#R}, when {@link #setPath} is
+     * introduced. Use {@link #setPath} instead.
      */
     @Deprecated
     public void setConvexPath(@NonNull Path convexPath) {
diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp
index 914c046..56d951c 100644
--- a/libs/hwui/hwui/Bitmap.cpp
+++ b/libs/hwui/hwui/Bitmap.cpp
@@ -150,11 +150,7 @@
     AHardwareBuffer_Desc bufferDesc;
     AHardwareBuffer_describe(hardwareBuffer, &bufferDesc);
     SkImageInfo info = uirenderer::BufferDescriptionToImageInfo(bufferDesc, colorSpace);
-
-    // If the stride is 0 we have to use the width as an approximation (eg, compressed buffer)
-    const auto bufferStride = bufferDesc.stride > 0 ? bufferDesc.stride : bufferDesc.width;
-    const size_t rowBytes = info.bytesPerPixel() * bufferStride;
-    return sk_sp<Bitmap>(new Bitmap(hardwareBuffer, info, rowBytes, palette));
+    return createFrom(hardwareBuffer, info, bufferDesc, palette);
 }
 
 sk_sp<Bitmap> Bitmap::createFrom(AHardwareBuffer* hardwareBuffer, SkColorType colorType,
@@ -164,8 +160,14 @@
     AHardwareBuffer_describe(hardwareBuffer, &bufferDesc);
     SkImageInfo info = SkImageInfo::Make(bufferDesc.width, bufferDesc.height,
                                          colorType, alphaType, colorSpace);
+    return createFrom(hardwareBuffer, info, bufferDesc, palette);
+}
 
-    const size_t rowBytes = info.bytesPerPixel() * bufferDesc.stride;
+sk_sp<Bitmap> Bitmap::createFrom(AHardwareBuffer* hardwareBuffer, const SkImageInfo& info,
+                                 const AHardwareBuffer_Desc& bufferDesc, BitmapPalette palette) {
+    // If the stride is 0 we have to use the width as an approximation (eg, compressed buffer)
+    const auto bufferStride = bufferDesc.stride > 0 ? bufferDesc.stride : bufferDesc.width;
+    const size_t rowBytes = info.bytesPerPixel() * bufferStride;
     return sk_sp<Bitmap>(new Bitmap(hardwareBuffer, info, rowBytes, palette));
 }
 #endif
diff --git a/libs/hwui/hwui/Bitmap.h b/libs/hwui/hwui/Bitmap.h
index 3bfb780..b8b5994 100644
--- a/libs/hwui/hwui/Bitmap.h
+++ b/libs/hwui/hwui/Bitmap.h
@@ -169,6 +169,12 @@
 #ifdef __ANDROID__ // Layoutlib does not support hardware acceleration
     Bitmap(AHardwareBuffer* buffer, const SkImageInfo& info, size_t rowBytes,
            BitmapPalette palette);
+
+    // Common code for the two public facing createFrom(AHardwareBuffer*, ...)
+    // methods.
+    // bufferDesc is only used to compute rowBytes.
+    static sk_sp<Bitmap> createFrom(AHardwareBuffer* hardwareBuffer, const SkImageInfo& info,
+                                    const AHardwareBuffer_Desc& bufferDesc, BitmapPalette palette);
 #endif
 
     virtual ~Bitmap();
diff --git a/libs/usb/Android.bp b/libs/usb/Android.bp
index 027a748..e752b55 100644
--- a/libs/usb/Android.bp
+++ b/libs/usb/Android.bp
@@ -19,5 +19,3 @@
     srcs: ["src/**/*.java"],
     api_packages: ["com.android.future.usb"],
 }
-
-subdirs = ["tests/*"]
diff --git a/libs/usb/tests/AccessoryChat/Android.bp b/libs/usb/tests/AccessoryChat/Android.bp
index 63a670c..19ed3d3 100644
--- a/libs/usb/tests/AccessoryChat/Android.bp
+++ b/libs/usb/tests/AccessoryChat/Android.bp
@@ -1,4 +1,3 @@
-subdirs = ["accessorychat"]
 //
 // Copyright (C) 2011 The Android Open Source Project
 //
diff --git a/location/java/android/location/LocationManagerInternal.java b/location/java/android/location/LocationManagerInternal.java
index 085602c..6006d50 100644
--- a/location/java/android/location/LocationManagerInternal.java
+++ b/location/java/android/location/LocationManagerInternal.java
@@ -27,22 +27,6 @@
 public abstract class LocationManagerInternal {
 
     /**
-     * Requests that a provider change its allowed state. A provider may or may not honor this
-     * request, and if the provider does change its state as a result, that may happen
-     * asynchronously after some delay.
-     *
-     * <p>Setting a provider's state to allowed implies that any consents or terms and conditions
-     * that may be necessary to allow the provider are agreed to. Setting a providers state to
-     * disallowed implies that any consents or terms and conditions have their agreement revoked.
-     *
-     * @param provider A location provider as listed by {@link LocationManager#getAllProviders()}
-     * @param allowed  Whether the location provider is being requested to allow or disallow
-     *                 itself
-     * @throws IllegalArgumentException if provider is null
-     */
-    public abstract void requestSetProviderAllowed(@NonNull String provider, boolean allowed);
-
-    /**
      * Returns true if the given provider is enabled for the given user.
      *
      * @param provider A location provider as listed by {@link LocationManager#getAllProviders()}
diff --git a/location/java/com/android/internal/location/ILocationProvider.aidl b/location/java/com/android/internal/location/ILocationProvider.aidl
index b7817ff..4246c6c 100644
--- a/location/java/com/android/internal/location/ILocationProvider.aidl
+++ b/location/java/com/android/internal/location/ILocationProvider.aidl
@@ -37,6 +37,4 @@
 
     @UnsupportedAppUsage
     oneway void sendExtraCommand(String command, in Bundle extras);
-
-    oneway void requestSetAllowed(boolean allowed);
 }
diff --git a/location/lib/api/current.txt b/location/lib/api/current.txt
index 49fcaab..9cc30d0 100644
--- a/location/lib/api/current.txt
+++ b/location/lib/api/current.txt
@@ -17,7 +17,6 @@
     method @Deprecated protected int onGetStatus(android.os.Bundle);
     method @Deprecated protected long onGetStatusUpdateTime();
     method protected void onInit();
-    method protected void onRequestSetAllowed(boolean);
     method protected boolean onSendExtraCommand(@Nullable String, @Nullable android.os.Bundle);
     method protected abstract void onSetRequest(com.android.location.provider.ProviderRequestUnbundled, android.os.WorkSource);
     method public void reportLocation(android.location.Location);
diff --git a/location/lib/java/com/android/location/provider/LocationProviderBase.java b/location/lib/java/com/android/location/provider/LocationProviderBase.java
index bd29d8a..d3fb58f 100644
--- a/location/lib/java/com/android/location/provider/LocationProviderBase.java
+++ b/location/lib/java/com/android/location/provider/LocationProviderBase.java
@@ -315,17 +315,6 @@
         return false;
     }
 
-    /**
-     * Invoked when the system wishes to request that the provider sets its allowed state as
-     * desired. This implies that the caller is providing/retracting consent for any terms and
-     * conditions or consents associated with the provider.
-     *
-     * <p>It is generally only necessary to override this function if the provider has some barriers
-     * or gates for enabling/disabling itself, in which case this function should handle those
-     * appropriately. A provider that is always allowed has no need to override this function.
-     */
-    protected void onRequestSetAllowed(boolean allowed) {}
-
     private final class Service extends ILocationProvider.Stub {
 
         @Override
@@ -356,10 +345,5 @@
         public void sendExtraCommand(String command, Bundle extras) {
             onSendExtraCommand(command, extras);
         }
-
-        @Override
-        public void requestSetAllowed(boolean allowed) {
-            onRequestSetAllowed(allowed);
-        }
     }
 }
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 0b825f6..383202b 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -1654,6 +1654,12 @@
      * @hide
      * Interface to be notified of changes in the preferred audio device set for a given audio
      * strategy.
+     * <p>Note that this listener will only be invoked whenever
+     * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)} or
+     * {@link #removePreferredDeviceForStrategy(AudioProductStrategy)} causes a change in
+     * preferred device. It will not be invoked directly after registration with
+     * {@link #addOnPreferredDeviceForStrategyChangedListener(Executor, OnPreferredDeviceForStrategyChangedListener)}
+     * to indicate which strategies had preferred devices at the time of registration.</p>
      * @see #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)
      * @see #removePreferredDeviceForStrategy(AudioProductStrategy)
      * @see #getPreferredDeviceForStrategy(AudioProductStrategy)
diff --git a/media/java/android/media/DrmInitData.java b/media/java/android/media/DrmInitData.java
index cc35f14..d803311 100644
--- a/media/java/android/media/DrmInitData.java
+++ b/media/java/android/media/DrmInitData.java
@@ -37,7 +37,9 @@
      *
      * @param schemeUuid The DRM scheme's UUID.
      * @return The initialization data for the scheme, or null if the scheme is not supported.
+     * @deprecated Use {@link #getSchemeInitDataCount} and {@link #getSchemeInitDataAt} instead.
      */
+    @Deprecated
     public abstract SchemeInitData get(UUID schemeUuid);
 
     /**
diff --git a/media/java/android/media/IMediaRoute2ProviderService.aidl b/media/java/android/media/IMediaRoute2ProviderService.aidl
index cd0def3..6cd2547 100644
--- a/media/java/android/media/IMediaRoute2ProviderService.aidl
+++ b/media/java/android/media/IMediaRoute2ProviderService.aidl
@@ -29,13 +29,13 @@
     // MediaRoute2ProviderService#MediaRoute2ProviderServiceStub for readability.
     void setCallback(IMediaRoute2ProviderServiceCallback callback);
     void updateDiscoveryPreference(in RouteDiscoveryPreference discoveryPreference);
-    void setRouteVolume(String routeId, int volume);
+    void setRouteVolume(String routeId, int volume, long requestId);
 
     void requestCreateSession(String packageName, String routeId, long requestId,
             in @nullable Bundle sessionHints);
-    void selectRoute(String sessionId, String routeId);
-    void deselectRoute(String sessionId, String routeId);
-    void transferToRoute(String sessionId, String routeId);
-    void setSessionVolume(String sessionId, int volume);
-    void releaseSession(String sessionId);
+    void selectRoute(String sessionId, String routeId, long requestId);
+    void deselectRoute(String sessionId, String routeId, long requestId);
+    void transferToRoute(String sessionId, String routeId, long requestId);
+    void setSessionVolume(String sessionId, int volume, long requestId);
+    void releaseSession(String sessionId, long requestId);
 }
diff --git a/media/java/android/media/IMediaRoute2ProviderServiceCallback.aidl b/media/java/android/media/IMediaRoute2ProviderServiceCallback.aidl
index e35b0c4..ab42d75 100644
--- a/media/java/android/media/IMediaRoute2ProviderServiceCallback.aidl
+++ b/media/java/android/media/IMediaRoute2ProviderServiceCallback.aidl
@@ -31,4 +31,5 @@
     void notifySessionCreationFailed(long requestId);
     void notifySessionUpdated(in RoutingSessionInfo sessionInfo);
     void notifySessionReleased(in RoutingSessionInfo sessionInfo);
+    void notifyRequestFailed(long requestId, int reason);
 }
diff --git a/media/java/android/media/IMediaRouter2Manager.aidl b/media/java/android/media/IMediaRouter2Manager.aidl
index ffad659..a2f9ee9 100644
--- a/media/java/android/media/IMediaRouter2Manager.aidl
+++ b/media/java/android/media/IMediaRouter2Manager.aidl
@@ -30,4 +30,5 @@
     void notifyRoutesAdded(in List<MediaRoute2Info> routes);
     void notifyRoutesRemoved(in List<MediaRoute2Info> routes);
     void notifyRoutesChanged(in List<MediaRoute2Info> routes);
+    void notifyRequestFailed(int requestId, int reason);
 }
diff --git a/media/java/android/media/IMediaRouterService.aidl b/media/java/android/media/IMediaRouterService.aidl
index cbec323..c7cb07d 100644
--- a/media/java/android/media/IMediaRouterService.aidl
+++ b/media/java/android/media/IMediaRouterService.aidl
@@ -71,16 +71,17 @@
     void registerManager(IMediaRouter2Manager manager, String packageName);
     void unregisterManager(IMediaRouter2Manager manager);
     void setRouteVolumeWithManager(IMediaRouter2Manager manager, in MediaRoute2Info route,
-            int volume);
+            int volume, int requestId);
 
     void requestCreateSessionWithManager(IMediaRouter2Manager manager, String packageName,
             in @nullable MediaRoute2Info route, int requestId);
     void selectRouteWithManager(IMediaRouter2Manager manager, String sessionId,
-            in MediaRoute2Info route);
+            in MediaRoute2Info route, int requestId);
     void deselectRouteWithManager(IMediaRouter2Manager manager, String sessionId,
-            in MediaRoute2Info route);
+            in MediaRoute2Info route, int requestId);
     void transferToRouteWithManager(IMediaRouter2Manager manager, String sessionId,
-            in MediaRoute2Info route);
-    void setSessionVolumeWithManager(IMediaRouter2Manager manager, String sessionId, int volume);
-    void releaseSessionWithManager(IMediaRouter2Manager manager, String sessionId);
+            in MediaRoute2Info route, int requestId);
+    void setSessionVolumeWithManager(IMediaRouter2Manager manager, String sessionId, int volume,
+            int requestId);
+    void releaseSessionWithManager(IMediaRouter2Manager manager, String sessionId, int requestId);
 }
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index abc7e0b..f2b4db1 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -1959,7 +1959,7 @@
      * If this codec is to be used with {@link LinearBlock} and/or {@link
      * GraphicBlock}, pass this flag.
      * <p>
-     * When this flag is set, the following APIs throw IllegalStateException.
+     * When this flag is set, the following APIs throw {@link IncompatibleWithBlockModelException}.
      * <ul>
      * <li>{@link #getInputBuffer}
      * <li>{@link #getInputImage}
@@ -1986,6 +1986,12 @@
     public @interface ConfigureFlag {}
 
     /**
+     * Thrown when the codec is configured for block model and an incompatible API is called.
+     */
+    public class IncompatibleWithBlockModelException extends RuntimeException {
+    }
+
+    /**
      * Configures a component.
      *
      * @param format The format of the input data (decoder) or the desired
@@ -2526,7 +2532,7 @@
         throws CryptoException {
         synchronized(mBufferLock) {
             if (mBufferMode != BUFFER_MODE_LEGACY) {
-                throw new IllegalStateException();
+                throw new IncompatibleWithBlockModelException();
             }
             invalidateByteBuffer(mCachedInputBuffers, index);
             mDequeuedInputBuffers.remove(index);
@@ -2778,7 +2784,7 @@
             int flags) throws CryptoException {
         synchronized(mBufferLock) {
             if (mBufferMode != BUFFER_MODE_LEGACY) {
-                throw new IllegalStateException();
+                throw new IncompatibleWithBlockModelException();
             }
             invalidateByteBuffer(mCachedInputBuffers, index);
             mDequeuedInputBuffers.remove(index);
@@ -2813,7 +2819,7 @@
     public final int dequeueInputBuffer(long timeoutUs) {
         synchronized (mBufferLock) {
             if (mBufferMode != BUFFER_MODE_LEGACY) {
-                throw new IllegalStateException();
+                throw new IncompatibleWithBlockModelException();
             }
         }
         int res = native_dequeueInputBuffer(timeoutUs);
@@ -2848,7 +2854,7 @@
         public boolean isMappable() {
             synchronized (mLock) {
                 if (!mValid) {
-                    throw new IllegalStateException();
+                    throw new IllegalStateException("The linear block is invalid");
                 }
                 return mMappable;
             }
@@ -2867,10 +2873,10 @@
         public @NonNull ByteBuffer map() {
             synchronized (mLock) {
                 if (!mValid) {
-                    throw new IllegalStateException();
+                    throw new IllegalStateException("The linear block is invalid");
                 }
                 if (!mMappable) {
-                    throw new IllegalStateException();
+                    throw new IllegalStateException("The linear block is not mappable");
                 }
                 if (mMapped == null) {
                     mMapped = native_map();
@@ -2896,7 +2902,7 @@
         public void recycle() {
             synchronized (mLock) {
                 if (!mValid) {
-                    throw new IllegalStateException();
+                    throw new IllegalStateException("The linear block is invalid");
                 }
                 if (mMapped != null) {
                     mMapped.setAccessible(false);
@@ -3002,7 +3008,7 @@
         public boolean isMappable() {
             synchronized (mLock) {
                 if (!mValid) {
-                    throw new IllegalStateException();
+                    throw new IllegalStateException("The graphic block is invalid");
                 }
                 return mMappable;
             }
@@ -3021,10 +3027,10 @@
         public @NonNull Image map() {
             synchronized (mLock) {
                 if (!mValid) {
-                    throw new IllegalStateException();
+                    throw new IllegalStateException("The graphic block is invalid");
                 }
                 if (!mMappable) {
-                    throw new IllegalStateException();
+                    throw new IllegalStateException("The graphic block is not mappable");
                 }
                 if (mMapped == null) {
                     mMapped = native_map();
@@ -3050,7 +3056,7 @@
         public void recycle() {
             synchronized (mLock) {
                 if (!mValid) {
-                    throw new IllegalStateException();
+                    throw new IllegalStateException("The graphic block is invalid");
                 }
                 if (mMapped != null) {
                     mMapped.close();
@@ -3127,8 +3133,9 @@
             if (buffer == null) {
                 buffer = new GraphicBlock();
             }
-            if (width < 0 || height < 0) {
-                throw new IllegalArgumentException();
+            if (width <= 0 || height <= 0) {
+                throw new IllegalArgumentException(
+                        "non-positive width or height: " + width + "x" + height);
             }
             synchronized (buffer.mLock) {
                 buffer.native_obtain(width, height, format, usage, codecNames);
@@ -3177,16 +3184,8 @@
          * @param block The linear block object
          * @param offset The byte offset into the input buffer at which the data starts.
          * @param size The number of bytes of valid input data.
-         * @param presentationTimeUs The presentation timestamp in microseconds for this
-         *                           buffer. This is normally the media time at which this
-         *                           buffer should be presented (rendered). When using an output
-         *                           surface, this will be propagated as the {@link
-         *                           SurfaceTexture#getTimestamp timestamp} for the frame (after
-         *                           conversion to nanoseconds).
-         * @param flags A bitmask of flags
-         *              {@link #BUFFER_FLAG_CODEC_CONFIG} and {@link #BUFFER_FLAG_END_OF_STREAM}.
-         *              While not prohibited, most codecs do not use the
-         *              {@link #BUFFER_FLAG_KEY_FRAME} flag for input buffers.
+         * @param cryptoInfo Metadata describing the structure of the encrypted input sample.
+         *                   may be null if clear.
          * @return this object
          * @throws IllegalStateException if a buffer is already set
          */
@@ -3194,59 +3193,17 @@
                 @NonNull LinearBlock block,
                 int offset,
                 int size,
-                long presentationTimeUs,
-                @BufferFlag int flags) {
+                @Nullable MediaCodec.CryptoInfo cryptoInfo) {
             if (!isAccessible()) {
-                throw new IllegalStateException();
+                throw new IllegalStateException("The request is stale");
             }
             if (mLinearBlock != null || mGraphicBlock != null) {
-                throw new IllegalStateException();
+                throw new IllegalStateException("Cannot set block twice");
             }
             mLinearBlock = block;
             mOffset = offset;
             mSize = size;
-            mPresentationTimeUs = presentationTimeUs;
-            mFlags = flags;
-            return this;
-        }
-
-        /**
-         * Set an encrypted linear block to this queue request. Exactly one
-         * buffer must be set for a queue request before calling {@link #queue}.
-         *
-         * @param block The linear block object
-         * @param offset The byte offset into the input buffer at which the data starts.
-         * @param presentationTimeUs The presentation timestamp in microseconds for this
-         *                           buffer. This is normally the media time at which this
-         *                           buffer should be presented (rendered). When using an output
-         *                           surface, this will be propagated as the {@link
-         *                           SurfaceTexture#getTimestamp timestamp} for the frame (after
-         *                           conversion to nanoseconds).
-         * @param cryptoInfo Metadata describing the structure of the encrypted input sample.
-         * @param flags A bitmask of flags
-         *              {@link #BUFFER_FLAG_CODEC_CONFIG} and {@link #BUFFER_FLAG_END_OF_STREAM}.
-         *              While not prohibited, most codecs do not use the
-         *              {@link #BUFFER_FLAG_KEY_FRAME} flag for input buffers.
-         * @return this object
-         * @throws IllegalStateException if a buffer is already set
-         */
-        public @NonNull QueueRequest setEncryptedLinearBlock(
-                @NonNull LinearBlock block,
-                int offset,
-                @NonNull MediaCodec.CryptoInfo cryptoInfo,
-                long presentationTimeUs,
-                @BufferFlag int flags) {
-            if (!isAccessible()) {
-                throw new IllegalStateException();
-            }
-            if (mLinearBlock != null || mGraphicBlock != null) {
-                throw new IllegalStateException();
-            }
-            mLinearBlock = block;
-            mOffset = offset;
             mCryptoInfo = cryptoInfo;
-            mPresentationTimeUs = presentationTimeUs;
-            mFlags = flags;
             return this;
         }
 
@@ -3255,45 +3212,72 @@
          * be set for a queue request before calling {@link #queue}.
          *
          * @param block The graphic block object
+         * @return this object
+         * @throws IllegalStateException if a buffer is already set
+         */
+        public @NonNull QueueRequest setGraphicBlock(
+                @NonNull GraphicBlock block) {
+            if (!isAccessible()) {
+                throw new IllegalStateException("The request is stale");
+            }
+            if (mLinearBlock != null || mGraphicBlock != null) {
+                throw new IllegalStateException("Cannot set block twice");
+            }
+            mGraphicBlock = block;
+            return this;
+        }
+
+        /**
+         * Set timestamp to this queue request.
+         *
          * @param presentationTimeUs The presentation timestamp in microseconds for this
          *                           buffer. This is normally the media time at which this
          *                           buffer should be presented (rendered). When using an output
          *                           surface, this will be propagated as the {@link
          *                           SurfaceTexture#getTimestamp timestamp} for the frame (after
          *                           conversion to nanoseconds).
+         * @return this object
+         */
+        public @NonNull QueueRequest setPresentationTimeUs(long presentationTimeUs) {
+            if (!isAccessible()) {
+                throw new IllegalStateException("The request is stale");
+            }
+            mPresentationTimeUs = presentationTimeUs;
+            return this;
+        }
+
+        /**
+         * Set flags to this queue request.
+         *
          * @param flags A bitmask of flags
          *              {@link #BUFFER_FLAG_CODEC_CONFIG} and {@link #BUFFER_FLAG_END_OF_STREAM}.
          *              While not prohibited, most codecs do not use the
          *              {@link #BUFFER_FLAG_KEY_FRAME} flag for input buffers.
          * @return this object
-         * @throws IllegalStateException if a buffer is already set
          */
-        public @NonNull QueueRequest setGraphicBlock(
-                @NonNull GraphicBlock block,
-                long presentationTimeUs,
-                @BufferFlag int flags) {
+        public @NonNull QueueRequest setFlags(@BufferFlag int flags) {
             if (!isAccessible()) {
-                throw new IllegalStateException();
+                throw new IllegalStateException("The request is stale");
             }
-            if (mLinearBlock != null || mGraphicBlock != null) {
-                throw new IllegalStateException();
-            }
-            mGraphicBlock = block;
-            mPresentationTimeUs = presentationTimeUs;
             mFlags = flags;
             return this;
         }
 
         /**
-         * Add a integer parameter. See {@link MediaFormat} for the list of
-         * supported tunings. If there was {@link MediaCodec#setParameters}
+         * Add an integer parameter.
+         * See {@link MediaFormat} for an exhaustive list of supported keys with
+         * values of type int, that can also be set with {@link MediaFormat#setInteger}.
+         *
+         * If there was {@link MediaCodec#setParameters}
          * call with the same key which is not processed by the codec yet, the
          * value set from this method will override the unprocessed value.
+         *
+         * @return this object
          */
         public @NonNull QueueRequest setIntegerParameter(
                 @NonNull String key, int value) {
             if (!isAccessible()) {
-                throw new IllegalStateException();
+                throw new IllegalStateException("The request is stale");
             }
             mTuningKeys.add(key);
             mTuningValues.add(Integer.valueOf(value));
@@ -3301,15 +3285,20 @@
         }
 
         /**
-         * Add a long parameter. See {@link MediaFormat} for the list of
-         * supported tunings. If there was {@link MediaCodec#setParameters}
+         * Add a long parameter.
+         * See {@link MediaFormat} for an exhaustive list of supported keys with
+         * values of type long, that can also be set with {@link MediaFormat#setLong}.
+         *
+         * If there was {@link MediaCodec#setParameters}
          * call with the same key which is not processed by the codec yet, the
          * value set from this method will override the unprocessed value.
+         *
+         * @return this object
          */
         public @NonNull QueueRequest setLongParameter(
                 @NonNull String key, long value) {
             if (!isAccessible()) {
-                throw new IllegalStateException();
+                throw new IllegalStateException("The request is stale");
             }
             mTuningKeys.add(key);
             mTuningValues.add(Long.valueOf(value));
@@ -3317,15 +3306,20 @@
         }
 
         /**
-         * Add a float parameter. See {@link MediaFormat} for the list of
-         * supported tunings. If there was {@link MediaCodec#setParameters}
+         * Add a float parameter.
+         * See {@link MediaFormat} for an exhaustive list of supported keys with
+         * values of type float, that can also be set with {@link MediaFormat#setFloat}.
+         *
+         * If there was {@link MediaCodec#setParameters}
          * call with the same key which is not processed by the codec yet, the
          * value set from this method will override the unprocessed value.
+         *
+         * @return this object
          */
         public @NonNull QueueRequest setFloatParameter(
                 @NonNull String key, float value) {
             if (!isAccessible()) {
-                throw new IllegalStateException();
+                throw new IllegalStateException("The request is stale");
             }
             mTuningKeys.add(key);
             mTuningValues.add(Float.valueOf(value));
@@ -3333,15 +3327,20 @@
         }
 
         /**
-         * Add a {@link ByteBuffer} parameter. See {@link MediaFormat} for the list of
-         * supported tunings. If there was {@link MediaCodec#setParameters}
+         * Add a {@link ByteBuffer} parameter.
+         * See {@link MediaFormat} for an exhaustive list of supported keys with
+         * values of byte buffer, that can also be set with {@link MediaFormat#setByteBuffer}.
+         *
+         * If there was {@link MediaCodec#setParameters}
          * call with the same key which is not processed by the codec yet, the
          * value set from this method will override the unprocessed value.
+         *
+         * @return this object
          */
         public @NonNull QueueRequest setByteBufferParameter(
                 @NonNull String key, @NonNull ByteBuffer value) {
             if (!isAccessible()) {
-                throw new IllegalStateException();
+                throw new IllegalStateException("The request is stale");
             }
             mTuningKeys.add(key);
             mTuningValues.add(value);
@@ -3349,15 +3348,20 @@
         }
 
         /**
-         * Add a string parameter. See {@link MediaFormat} for the list of
-         * supported tunings. If there was {@link MediaCodec#setParameters}
+         * Add a string parameter.
+         * See {@link MediaFormat} for an exhaustive list of supported keys with
+         * values of type string, that can also be set with {@link MediaFormat#setString}.
+         *
+         * If there was {@link MediaCodec#setParameters}
          * call with the same key which is not processed by the codec yet, the
          * value set from this method will override the unprocessed value.
+         *
+         * @return this object
          */
         public @NonNull QueueRequest setStringParameter(
                 @NonNull String key, @NonNull String value) {
             if (!isAccessible()) {
-                throw new IllegalStateException();
+                throw new IllegalStateException("The request is stale");
             }
             mTuningKeys.add(key);
             mTuningValues.add(value);
@@ -3369,10 +3373,10 @@
          */
         public void queue() {
             if (!isAccessible()) {
-                throw new IllegalStateException();
+                throw new IllegalStateException("The request is stale");
             }
             if (mLinearBlock == null && mGraphicBlock == null) {
-                throw new IllegalStateException();
+                throw new IllegalStateException("No block is set");
             }
             setAccessible(false);
             if (mLinearBlock != null) {
@@ -3447,7 +3451,7 @@
     private final ArrayList<QueueRequest> mQueueRequests = new ArrayList<>();
 
     /**
-     * Return a clear {@link QueueRequest} object for an input slot index.
+     * Return a {@link QueueRequest} object for an input slot index.
      *
      * @param index input slot index from
      *              {@link Callback#onInputBufferAvailable}
@@ -3459,17 +3463,19 @@
     public @NonNull QueueRequest getQueueRequest(int index) {
         synchronized (mBufferLock) {
             if (mBufferMode != BUFFER_MODE_BLOCK) {
-                throw new IllegalStateException();
+                throw new IllegalStateException("The codec is not configured for block model");
             }
             if (index < 0 || index >= mQueueRequests.size()) {
-                throw new IllegalArgumentException();
+                throw new IndexOutOfBoundsException("Expected range of index: [0,"
+                        + (mQueueRequests.size() - 1) + "]; actual: " + index);
             }
             QueueRequest request = mQueueRequests.get(index);
             if (request == null) {
-                throw new IllegalArgumentException();
+                throw new IllegalArgumentException("Unavailable index: " + index);
             }
             if (!request.isAccessible()) {
-                throw new IllegalArgumentException();
+                throw new IllegalArgumentException(
+                        "The request is stale at index " + index);
             }
             return request.clear();
         }
@@ -3529,7 +3535,7 @@
             @NonNull BufferInfo info, long timeoutUs) {
         synchronized (mBufferLock) {
             if (mBufferMode != BUFFER_MODE_LEGACY) {
-                throw new IllegalStateException();
+                throw new IncompatibleWithBlockModelException();
             }
         }
         int res = native_dequeueOutputBuffer(info, timeoutUs);
@@ -3644,7 +3650,8 @@
                     frame.clear();
                     break;
                 default:
-                    throw new IllegalStateException();
+                    throw new IllegalStateException(
+                            "Unrecognized buffer mode: " + mBufferMode);
             }
         }
         releaseOutputBuffer(
@@ -3910,7 +3917,7 @@
     public ByteBuffer[] getInputBuffers() {
         synchronized (mBufferLock) {
             if (mBufferMode != BUFFER_MODE_LEGACY) {
-                throw new IllegalStateException();
+                throw new IncompatibleWithBlockModelException();
             }
             if (mCachedInputBuffers == null) {
                 throw new IllegalStateException();
@@ -3946,7 +3953,7 @@
     public ByteBuffer[] getOutputBuffers() {
         synchronized (mBufferLock) {
             if (mBufferMode != BUFFER_MODE_LEGACY) {
-                throw new IllegalStateException();
+                throw new IncompatibleWithBlockModelException();
             }
             if (mCachedOutputBuffers == null) {
                 throw new IllegalStateException();
@@ -3978,7 +3985,7 @@
     public ByteBuffer getInputBuffer(int index) {
         synchronized (mBufferLock) {
             if (mBufferMode != BUFFER_MODE_LEGACY) {
-                throw new IllegalStateException();
+                throw new IncompatibleWithBlockModelException();
             }
         }
         ByteBuffer newBuffer = getBuffer(true /* input */, index);
@@ -4012,7 +4019,7 @@
     public Image getInputImage(int index) {
         synchronized (mBufferLock) {
             if (mBufferMode != BUFFER_MODE_LEGACY) {
-                throw new IllegalStateException();
+                throw new IncompatibleWithBlockModelException();
             }
         }
         Image newImage = getImage(true /* input */, index);
@@ -4046,7 +4053,7 @@
     public ByteBuffer getOutputBuffer(int index) {
         synchronized (mBufferLock) {
             if (mBufferMode != BUFFER_MODE_LEGACY) {
-                throw new IllegalStateException();
+                throw new IncompatibleWithBlockModelException();
             }
         }
         ByteBuffer newBuffer = getBuffer(false /* input */, index);
@@ -4079,7 +4086,7 @@
     public Image getOutputImage(int index) {
         synchronized (mBufferLock) {
             if (mBufferMode != BUFFER_MODE_LEGACY) {
-                throw new IllegalStateException();
+                throw new IncompatibleWithBlockModelException();
             }
         }
         Image newImage = getImage(false /* input */, index);
@@ -4106,7 +4113,7 @@
          */
         public @Nullable LinearBlock getLinearBlock() {
             if (mGraphicBlock != null) {
-                throw new IllegalStateException();
+                throw new IllegalStateException("This output frame is not linear");
             }
             return mLinearBlock;
         }
@@ -4118,7 +4125,7 @@
          */
         public @Nullable GraphicBlock getGraphicBlock() {
             if (mLinearBlock != null) {
-                throw new IllegalStateException();
+                throw new IllegalStateException("This output frame is not graphic");
             }
             return mGraphicBlock;
         }
@@ -4139,7 +4146,7 @@
 
         /**
          * Returns a read-only {@link MediaFormat} for this frame. The returned
-         * object is valid only while the client is holding the output frame.
+         * object is valid only until the client calls {@link MediaCodec#releaseOutputBuffer}.
          */
         public @NonNull MediaFormat getFormat() {
             return mFormat;
@@ -4151,7 +4158,7 @@
          * Client can find out what the change is by querying {@link MediaFormat}
          * object returned from {@link #getFormat}.
          */
-        public void getChangedKeys(@NonNull Set<String> keys) {
+        public void retrieveChangedKeys(@NonNull Set<String> keys) {
             keys.clear();
             keys.addAll(mChangedKeys);
         }
@@ -4211,17 +4218,19 @@
     public @NonNull OutputFrame getOutputFrame(int index) {
         synchronized (mBufferLock) {
             if (mBufferMode != BUFFER_MODE_BLOCK) {
-                throw new IllegalStateException();
+                throw new IllegalStateException("The codec is not configured for block model");
             }
             if (index < 0 || index >= mOutputFrames.size()) {
-                throw new IllegalArgumentException();
+                throw new IndexOutOfBoundsException("Expected range of index: [0,"
+                        + (mQueueRequests.size() - 1) + "]; actual: " + index);
             }
             OutputFrame frame = mOutputFrames.get(index);
             if (frame == null) {
-                throw new IllegalArgumentException();
+                throw new IllegalArgumentException("Unavailable index: " + index);
             }
             if (!frame.isAccessible()) {
-                throw new IllegalArgumentException();
+                throw new IllegalArgumentException(
+                        "The output frame is stale at index " + index);
             }
             if (!frame.isLoaded()) {
                 native_getOutputFrame(frame, index);
diff --git a/media/java/android/media/MediaRoute2Info.java b/media/java/android/media/MediaRoute2Info.java
index bf04fe8..8d63cf04 100644
--- a/media/java/android/media/MediaRoute2Info.java
+++ b/media/java/android/media/MediaRoute2Info.java
@@ -104,10 +104,12 @@
 
     /** @hide */
     @IntDef({
-            DEVICE_TYPE_UNKNOWN, DEVICE_TYPE_REMOTE_TV,
-            DEVICE_TYPE_REMOTE_SPEAKER, DEVICE_TYPE_BLUETOOTH})
+            TYPE_UNKNOWN, TYPE_BUILTIN_SPEAKER, TYPE_WIRED_HEADSET,
+            TYPE_WIRED_HEADPHONES, TYPE_BLUETOOTH_A2DP, TYPE_HDMI, TYPE_USB_DEVICE,
+            TYPE_USB_ACCESSORY, TYPE_DOCK, TYPE_USB_HEADSET, TYPE_HEARING_AID,
+            TYPE_REMOTE_TV, TYPE_REMOTE_SPEAKER, TYPE_GROUP})
     @Retention(RetentionPolicy.SOURCE)
-    public @interface DeviceType {}
+    public @interface Type {}
 
     /**
      * The default receiver device type of the route indicating the type is unknown.
@@ -140,6 +142,121 @@
      */
     public static final int DEVICE_TYPE_BLUETOOTH = 3;
 
+
+    /**
+     * The default route type indicating the type is unknown.
+     *
+     * @see #getType
+     * @hide
+     */
+    public static final int TYPE_UNKNOWN = 0;
+
+    /**
+     * A route type describing the speaker system (i.e. a mono speaker or stereo speakers) built
+     * in a device.
+     *
+     * @see #getType
+     * @hide
+     */
+    public static final int TYPE_BUILTIN_SPEAKER = AudioDeviceInfo.TYPE_BUILTIN_SPEAKER;
+
+    /**
+     * A route type describing a headset, which is the combination of a headphones and microphone.
+     *
+     * @see #getType
+     * @hide
+     */
+    public static final int TYPE_WIRED_HEADSET = AudioDeviceInfo.TYPE_WIRED_HEADSET;
+
+    /**
+     * A route type describing a pair of wired headphones.
+     *
+     * @see #getType
+     * @hide
+     */
+    public static final int TYPE_WIRED_HEADPHONES = AudioDeviceInfo.TYPE_WIRED_HEADPHONES;
+
+    /**
+     * A route type indicating the presentation of the media is happening
+     * on a bluetooth device such as a bluetooth speaker.
+     *
+     * @see #getType
+     * @hide
+     */
+    public static final int TYPE_BLUETOOTH_A2DP = AudioDeviceInfo.TYPE_BLUETOOTH_A2DP;
+
+    /**
+     * A route type describing an HDMI connection.
+     *
+     * @see #getType
+     * @hide
+     */
+    public static final int TYPE_HDMI = AudioDeviceInfo.TYPE_HDMI;
+
+    /**
+     * A route type describing a USB audio device.
+     *
+     * @see #getType
+     * @hide
+     */
+    public static final int TYPE_USB_DEVICE = AudioDeviceInfo.TYPE_USB_DEVICE;
+
+    /**
+     * A route type describing a USB audio device in accessory mode.
+     *
+     * @see #getType
+     * @hide
+     */
+    public static final int TYPE_USB_ACCESSORY = AudioDeviceInfo.TYPE_USB_ACCESSORY;
+
+    /**
+     * A route type describing the audio device associated with a dock.
+     *
+     * @see #getType
+     * @hide
+     */
+    public static final int TYPE_DOCK = AudioDeviceInfo.TYPE_DOCK;
+
+    /**
+     * A device type describing a USB audio headset.
+     *
+     * @see #getType
+     * @hide
+     */
+    public static final int TYPE_USB_HEADSET = AudioDeviceInfo.TYPE_USB_HEADSET;
+
+    /**
+     * A route type describing a Hearing Aid.
+     *
+     * @see #getType
+     * @hide
+     */
+    public static final int TYPE_HEARING_AID = AudioDeviceInfo.TYPE_HEARING_AID;
+
+    /**
+     * A route type indicating the presentation of the media is happening on a TV.
+     *
+     * @see #getType
+     * @hide
+     */
+    public static final int TYPE_REMOTE_TV = 1001;
+
+    /**
+     * A route type indicating the presentation of the media is happening on a speaker.
+     *
+     * @see #getType
+     * @hide
+     */
+    public static final int TYPE_REMOTE_SPEAKER = 1002;
+
+    /**
+     * A route type indicating the presentation of the media is happening on multiple devices.
+     *
+     * @see #getType
+     * @hide
+     */
+    public static final int TYPE_GROUP = 2000;
+
     /**
      * Media feature: Live audio.
      * <p>
@@ -196,8 +313,8 @@
     final String mId;
     final CharSequence mName;
     final List<String> mFeatures;
-    @DeviceType
-    final int mDeviceType;
+    @Type
+    final int mType;
     final boolean mIsSystem;
     final Uri mIconUri;
     final CharSequence mDescription;
@@ -214,7 +331,7 @@
         mId = builder.mId;
         mName = builder.mName;
         mFeatures = builder.mFeatures;
-        mDeviceType = builder.mDeviceType;
+        mType = builder.mType;
         mIsSystem = builder.mIsSystem;
         mIconUri = builder.mIconUri;
         mDescription = builder.mDescription;
@@ -231,7 +348,7 @@
         mId = in.readString();
         mName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
         mFeatures = in.createStringArrayList();
-        mDeviceType = in.readInt();
+        mType = in.readInt();
         mIsSystem = in.readBoolean();
         mIconUri = in.readParcelable(null);
         mDescription = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
@@ -285,9 +402,26 @@
      * {@link #DEVICE_TYPE_REMOTE_TV}, {@link #DEVICE_TYPE_REMOTE_SPEAKER},
      * {@link #DEVICE_TYPE_BLUETOOTH}.
      */
-    @DeviceType
+    @Type
     public int getDeviceType() {
-        return mDeviceType;
+        return getType();
+    }
+
+    /**
+     * Gets the type of this route.
+     *
+     * @return The type of this route:
+     * {@link #TYPE_UNKNOWN},
+     * {@link #TYPE_BUILTIN_SPEAKER}, {@link #TYPE_WIRED_HEADSET}, {@link #TYPE_WIRED_HEADPHONES},
+     * {@link #TYPE_BLUETOOTH_A2DP}, {@link #TYPE_HDMI}, {@link #TYPE_DOCK},
+     * {@Link #TYPE_USB_DEVICE}, {@link #TYPE_USB_ACCESSORY}, {@link #TYPE_USB_HEADSET}
+     * {@link #TYPE_HEARING_AID},
+     * {@link #TYPE_REMOTE_TV}, {@link #TYPE_REMOTE_SPEAKER}, {@link #TYPE_GROUP}.
+     * @hide
+     */
+    @Type
+    public int getType() {
+        return mType;
     }
 
     /**
@@ -437,7 +571,7 @@
         return Objects.equals(mId, other.mId)
                 && Objects.equals(mName, other.mName)
                 && Objects.equals(mFeatures, other.mFeatures)
-                && (mDeviceType == other.mDeviceType)
+                && (mType == other.mType)
                 && (mIsSystem == other.mIsSystem)
                 && Objects.equals(mIconUri, other.mIconUri)
                 && Objects.equals(mDescription, other.mDescription)
@@ -452,7 +586,7 @@
     @Override
     public int hashCode() {
         // Note: mExtras is not included.
-        return Objects.hash(mId, mName, mFeatures, mDeviceType, mIsSystem, mIconUri, mDescription,
+        return Objects.hash(mId, mName, mFeatures, mType, mIsSystem, mIconUri, mDescription,
                 mConnectionState, mClientPackageName, mVolumeHandling, mVolumeMax, mVolume,
                 mProviderId);
     }
@@ -488,7 +622,7 @@
         dest.writeString(mId);
         TextUtils.writeToParcel(mName, dest, flags);
         dest.writeStringList(mFeatures);
-        dest.writeInt(mDeviceType);
+        dest.writeInt(mType);
         dest.writeBoolean(mIsSystem);
         dest.writeParcelable(mIconUri, flags);
         TextUtils.writeToParcel(mDescription, dest, flags);
@@ -509,8 +643,8 @@
         final CharSequence mName;
         final List<String> mFeatures;
 
-        @DeviceType
-        int mDeviceType = DEVICE_TYPE_UNKNOWN;
+        @Type
+        int mType = TYPE_UNKNOWN;
         boolean mIsSystem;
         Uri mIconUri;
         CharSequence mDescription;
@@ -557,7 +691,7 @@
             mId = routeInfo.mId;
             mName = routeInfo.mName;
             mFeatures = new ArrayList<>(routeInfo.mFeatures);
-            mDeviceType = routeInfo.mDeviceType;
+            mType = routeInfo.mType;
             mIsSystem = routeInfo.mIsSystem;
             mIconUri = routeInfo.mIconUri;
             mDescription = routeInfo.mDescription;
@@ -621,8 +755,17 @@
          * Sets the route's device type.
          */
         @NonNull
-        public Builder setDeviceType(@DeviceType int deviceType) {
-            mDeviceType = deviceType;
+        public Builder setDeviceType(@Type int type) {
+            return setType(type);
+        }
+
+        /**
+         * Sets the route's type.
+         * @hide
+         */
+        @NonNull
+        public Builder setType(@Type int type) {
+            mType = type;
             return this;
         }
 
diff --git a/media/java/android/media/MediaRoute2ProviderService.java b/media/java/android/media/MediaRoute2ProviderService.java
index 38233fd..aa0eda1 100644
--- a/media/java/android/media/MediaRoute2ProviderService.java
+++ b/media/java/android/media/MediaRoute2ProviderService.java
@@ -19,6 +19,7 @@
 import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
 
 import android.annotation.CallSuper;
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SdkConstant;
@@ -37,6 +38,8 @@
 
 import com.android.internal.annotations.GuardedBy;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
@@ -51,7 +54,7 @@
  * Media apps which use {@link MediaRouter2} can request to play their media on the routes.
  * </p><p>
  * When {@link MediaRouter2 media router} wants to play media on a route,
- * {@link #onCreateSession(String, String, long, Bundle)} will be called to handle the request.
+ * {@link #onCreateSession(long, String, String, Bundle)} will be called to handle the request.
  * A session can be considered as a group of currently selected routes for each connection.
  * Create and manage the sessions by yourself, and notify the {@link RoutingSessionInfo
  * session infos} when there are any changes.
@@ -61,6 +64,8 @@
  * a {@link MediaRouter2 media router} by an application. See
  * {@link #onDiscoveryPreferenceChanged(RouteDiscoveryPreference)} for the details.
  * </p>
+ * Use {@link #notifyRequestFailed(long, int)} to notify the failure with previously received
+ * request ID.
  */
 public abstract class MediaRoute2ProviderService extends Service {
     private static final String TAG = "MR2ProviderService";
@@ -79,7 +84,53 @@
      *
      * @see #notifySessionCreated(RoutingSessionInfo, long)
      */
-    public static final long REQUEST_ID_UNKNOWN = 0;
+    public static final long REQUEST_ID_NONE = 0;
+
+    /**
+     * The request has failed due to unknown reason.
+     *
+     * @see #notifyRequestFailed(long, int)
+     */
+    public static final int REASON_UNKNOWN_ERROR = 0;
+
+    /**
+     * The request has failed since this service rejected the request.
+     *
+     * @see #notifyRequestFailed(long, int)
+     */
+    public static final int REASON_REJECTED = 1;
+
+    /**
+     * The request has failed due to a network error.
+     *
+     * @see #notifyRequestFailed(long, int)
+     */
+    public static final int REASON_NETWORK_ERROR = 2;
+
+    /**
+     * The request has failed since the requested route is no longer available.
+     *
+     * @see #notifyRequestFailed(long, int)
+     */
+    public static final int REASON_ROUTE_NOT_AVAILABLE = 3;
+
+    /**
+     * The request has failed since the request is not valid. For example, selecting a route
+     * which is not selectable.
+     *
+     * @see #notifyRequestFailed(long, int)
+     */
+    public static final int REASON_INVALID_COMMAND = 4;
+
+    /**
+     * @hide
+     */
+    @IntDef(prefix = "REASON_", value = {
+            REASON_UNKNOWN_ERROR, REASON_REJECTED, REASON_NETWORK_ERROR, REASON_ROUTE_NOT_AVAILABLE,
+            REASON_INVALID_COMMAND
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface Reason {}
 
     private final Handler mHandler;
     private final Object mSessionLock = new Object();
@@ -116,20 +167,23 @@
     /**
      * Called when a volume setting is requested on a route of the provider
      *
+     * @param requestId the id of this request
      * @param routeId the id of the route
      * @param volume the target volume
-     * @see MediaRoute2Info#getVolumeMax()
+     * @see MediaRoute2Info.Builder#setVolume(int)
      */
-    public abstract void onSetRouteVolume(@NonNull String routeId, int volume);
+    public abstract void onSetRouteVolume(long requestId, @NonNull String routeId, int volume);
 
     /**
      * Called when {@link MediaRouter2.RoutingController#setVolume(int)} is called on
      * a routing session of the provider
      *
+     * @param requestId the id of this request
      * @param sessionId the id of the routing session
      * @param volume the target volume
+     * @see RoutingSessionInfo.Builder#setVolume(int)
      */
-    public abstract void onSetSessionVolume(@NonNull String sessionId, int volume);
+    public abstract void onSetSessionVolume(long requestId, @NonNull String sessionId, int volume);
 
     /**
      * Gets information of the session with the given id.
@@ -161,14 +215,15 @@
     /**
      * Notifies clients of that the session is created and ready for use.
      * <p>
-     * If this session is created without any creation request, use {@link #REQUEST_ID_UNKNOWN}
+     * If this session is created without any creation request, use {@link #REQUEST_ID_NONE}
      * as the request ID.
      *
      * @param sessionInfo information of the new session.
      *                    The {@link RoutingSessionInfo#getId() id} of the session must be unique.
      * @param requestId id of the previous request to create this session provided in
-     *                  {@link #onCreateSession(String, String, long, Bundle)}
-     * @see #onCreateSession(String, String, long, Bundle)
+     *                  {@link #onCreateSession(long, String, String, Bundle)}. Can be
+     *                  {@link #REQUEST_ID_NONE} if this session is created without any request.
+     * @see #onCreateSession(long, String, String, Bundle)
      * @see #getSessionInfo(String)
      */
     public final void notifySessionCreated(@NonNull RoutingSessionInfo sessionInfo,
@@ -201,8 +256,8 @@
      * Notifies clients of that the session could not be created.
      *
      * @param requestId id of the previous request to create the session provided in
-     *                  {@link #onCreateSession(String, String, long, Bundle)}.
-     * @see #onCreateSession(String, String, long, Bundle)
+     *                  {@link #onCreateSession(long, String, String, Bundle)}.
+     * @see #onCreateSession(long, String, String, Bundle)
      */
     public final void notifySessionCreationFailed(long requestId) {
         if (mRemoteCallback == null) {
@@ -246,7 +301,7 @@
      * Notifies that the session is released.
      *
      * @param sessionId id of the released session.
-     * @see #onReleaseSession(String)
+     * @see #onReleaseSession(long, String)
      */
     public final void notifySessionReleased(@NonNull String sessionId) {
         if (TextUtils.isEmpty(sessionId)) {
@@ -273,6 +328,29 @@
     }
 
     /**
+     * Notifies to the client that the request has failed.
+     *
+     * @param requestId the ID of the previous request
+     * @param reason the reason why the request has failed
+     *
+     * @see #REASON_UNKNOWN_ERROR
+     * @see #REASON_REJECTED
+     * @see #REASON_NETWORK_ERROR
+     * @see #REASON_ROUTE_NOT_AVAILABLE
+     * @see #REASON_INVALID_COMMAND
+     */
+    public final void notifyRequestFailed(long requestId, @Reason int reason) {
+        if (mRemoteCallback == null) {
+            return;
+        }
+        try {
+            mRemoteCallback.notifyRequestFailed(requestId, reason);
+        } catch (RemoteException ex) {
+            Log.w(TAG, "Failed to notify that the request has failed.");
+        }
+    }
+
+    /**
      * Called when the service receives a request to create a session.
      * <p>
      * You should create and maintain your own session and notifies the client of
@@ -288,9 +366,9 @@
      * If you can't create the session or want to reject the request, call
      * {@link #notifySessionCreationFailed(long)} with the given {@code requestId}.
      *
+     * @param requestId the id of this request
      * @param packageName the package name of the application that selected the route
      * @param routeId the id of the route initially being connected
-     * @param requestId the id of this session creation request
      * @param sessionHints an optional bundle of app-specific arguments sent by
      *                     {@link MediaRouter2}, or null if none. The contents of this bundle
      *                     may affect the result of session creation.
@@ -299,8 +377,8 @@
      * @see RoutingSessionInfo.Builder#addSelectedRoute(String)
      * @see RoutingSessionInfo.Builder#setControlHints(Bundle)
      */
-    public abstract void onCreateSession(@NonNull String packageName, @NonNull String routeId,
-            long requestId, @Nullable Bundle sessionHints);
+    public abstract void onCreateSession(long requestId, @NonNull String packageName,
+            @NonNull String routeId, @Nullable Bundle sessionHints);
 
     /**
      * Called when the session should be released. A client of the session or system can request
@@ -312,44 +390,48 @@
      * Note: Calling {@link #notifySessionReleased(String)} will <em>NOT</em> trigger
      * this method to be called.
      *
+     * @param requestId the id of this request
      * @param sessionId id of the session being released.
      * @see #notifySessionReleased(String)
      * @see #getSessionInfo(String)
      */
-    public abstract void onReleaseSession(@NonNull String sessionId);
+    public abstract void onReleaseSession(long requestId, @NonNull String sessionId);
 
-    //TODO: make a way to reject the request
     /**
      * Called when a client requests selecting a route for the session.
      * After the route is selected, call {@link #notifySessionUpdated(RoutingSessionInfo)}
      * to update session info.
      *
+     * @param requestId the id of this request
      * @param sessionId id of the session
      * @param routeId id of the route
      */
-    public abstract void onSelectRoute(@NonNull String sessionId, @NonNull String routeId);
+    public abstract void onSelectRoute(long requestId, @NonNull String sessionId,
+            @NonNull String routeId);
 
-    //TODO: make a way to reject the request
     /**
      * Called when a client requests deselecting a route from the session.
      * After the route is deselected, call {@link #notifySessionUpdated(RoutingSessionInfo)}
      * to update session info.
      *
+     * @param requestId the id of this request
      * @param sessionId id of the session
      * @param routeId id of the route
      */
-    public abstract void onDeselectRoute(@NonNull String sessionId, @NonNull String routeId);
+    public abstract void onDeselectRoute(long requestId, @NonNull String sessionId,
+            @NonNull String routeId);
 
-    //TODO: make a way to reject the request
     /**
      * Called when a client requests transferring a session to a route.
      * After the transfer is finished, call {@link #notifySessionUpdated(RoutingSessionInfo)}
      * to update session info.
      *
+     * @param requestId the id of this request
      * @param sessionId id of the session
      * @param routeId id of the route
      */
-    public abstract void onTransferToRoute(@NonNull String sessionId, @NonNull String routeId);
+    public abstract void onTransferToRoute(long requestId, @NonNull String sessionId,
+            @NonNull String routeId);
 
     /**
      * Called when the {@link RouteDiscoveryPreference discovery preference} has changed.
@@ -439,12 +521,12 @@
         }
 
         @Override
-        public void setRouteVolume(String routeId, int volume) {
+        public void setRouteVolume(String routeId, int volume, long requestId) {
             if (!checkCallerisSystem()) {
                 return;
             }
             mHandler.sendMessage(obtainMessage(MediaRoute2ProviderService::onSetRouteVolume,
-                    MediaRoute2ProviderService.this, routeId, volume));
+                    MediaRoute2ProviderService.this, requestId, routeId, volume));
         }
 
         @Override
@@ -454,12 +536,12 @@
                 return;
             }
             mHandler.sendMessage(obtainMessage(MediaRoute2ProviderService::onCreateSession,
-                    MediaRoute2ProviderService.this, packageName, routeId, requestId,
+                    MediaRoute2ProviderService.this, requestId, packageName, routeId,
                     requestCreateSession));
         }
 
         @Override
-        public void selectRoute(@NonNull String sessionId, String routeId) {
+        public void selectRoute(String sessionId, String routeId, long requestId) {
             if (!checkCallerisSystem()) {
                 return;
             }
@@ -468,11 +550,11 @@
                 return;
             }
             mHandler.sendMessage(obtainMessage(MediaRoute2ProviderService::onSelectRoute,
-                    MediaRoute2ProviderService.this, sessionId, routeId));
+                    MediaRoute2ProviderService.this, requestId, sessionId, routeId));
         }
 
         @Override
-        public void deselectRoute(@NonNull String sessionId, String routeId) {
+        public void deselectRoute(String sessionId, String routeId, long requestId) {
             if (!checkCallerisSystem()) {
                 return;
             }
@@ -481,11 +563,11 @@
                 return;
             }
             mHandler.sendMessage(obtainMessage(MediaRoute2ProviderService::onDeselectRoute,
-                    MediaRoute2ProviderService.this, sessionId, routeId));
+                    MediaRoute2ProviderService.this, requestId, sessionId, routeId));
         }
 
         @Override
-        public void transferToRoute(@NonNull String sessionId, String routeId) {
+        public void transferToRoute(String sessionId, String routeId, long requestId) {
             if (!checkCallerisSystem()) {
                 return;
             }
@@ -494,20 +576,20 @@
                 return;
             }
             mHandler.sendMessage(obtainMessage(MediaRoute2ProviderService::onTransferToRoute,
-                    MediaRoute2ProviderService.this, sessionId, routeId));
+                    MediaRoute2ProviderService.this, requestId, sessionId, routeId));
         }
 
         @Override
-        public void setSessionVolume(String sessionId, int volume) {
+        public void setSessionVolume(String sessionId, int volume, long requestId) {
             if (!checkCallerisSystem()) {
                 return;
             }
             mHandler.sendMessage(obtainMessage(MediaRoute2ProviderService::onSetSessionVolume,
-                    MediaRoute2ProviderService.this, sessionId, volume));
+                    MediaRoute2ProviderService.this, requestId, sessionId, volume));
         }
 
         @Override
-        public void releaseSession(@NonNull String sessionId) {
+        public void releaseSession(String sessionId, long requestId) {
             if (!checkCallerisSystem()) {
                 return;
             }
@@ -516,7 +598,7 @@
                 return;
             }
             mHandler.sendMessage(obtainMessage(MediaRoute2ProviderService::onReleaseSession,
-                    MediaRoute2ProviderService.this, sessionId));
+                    MediaRoute2ProviderService.this, requestId, sessionId));
         }
     }
 }
diff --git a/media/java/android/media/MediaRouter2.java b/media/java/android/media/MediaRouter2.java
index 28bb4c1..079fee8 100644
--- a/media/java/android/media/MediaRouter2.java
+++ b/media/java/android/media/MediaRouter2.java
@@ -21,6 +21,7 @@
 import android.annotation.CallbackExecutor;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.TestApi;
 import android.content.Context;
 import android.os.Bundle;
 import android.os.Handler;
@@ -721,8 +722,7 @@
             RoutingController newController) {
         for (TransferCallbackRecord record: mTransferCallbackRecords) {
             record.mExecutor.execute(
-                    () -> record.mTransferCallback.onTransferred(oldController,
-                            newController));
+                    () -> record.mTransferCallback.onTransferred(oldController, newController));
         }
     }
 
@@ -817,7 +817,7 @@
          * @return An optional bundle of app-specific arguments to send to the provider,
          *         or null if none. The contents of this bundle may affect the result of
          *         controller creation.
-         * @see MediaRoute2ProviderService#onCreateSession(String, String, long, Bundle)
+         * @see MediaRoute2ProviderService#onCreateSession(long, String, String, Bundle)
          */
         @Nullable
         Bundle onGetControllerHints(@NonNull MediaRoute2Info route);
@@ -866,6 +866,20 @@
         }
 
         /**
+         * Gets the original session id set by
+         * {@link RoutingSessionInfo.Builder#Builder(String, String)}.
+         *
+         * @hide
+         */
+        @NonNull
+        @TestApi
+        public String getOriginalId() {
+            synchronized (mControllerLock) {
+                return mSessionInfo.getOriginalId();
+            }
+        }
+
+        /**
          * @return the control hints used to control routing session if available.
          */
         @Nullable
diff --git a/media/java/android/media/MediaRouter2Manager.java b/media/java/android/media/MediaRouter2Manager.java
index 636ee92..ff2c863 100644
--- a/media/java/android/media/MediaRouter2Manager.java
+++ b/media/java/android/media/MediaRouter2Manager.java
@@ -337,7 +337,8 @@
         }
         if (client != null) {
             try {
-                mMediaRouterService.setRouteVolumeWithManager(client, route, volume);
+                int requestId = mNextRequestId.getAndIncrement();
+                mMediaRouterService.setRouteVolumeWithManager(client, route, volume, requestId);
             } catch (RemoteException ex) {
                 Log.e(TAG, "Unable to send control request.", ex);
             }
@@ -368,8 +369,9 @@
         }
         if (client != null) {
             try {
+                int requestId = mNextRequestId.getAndIncrement();
                 mMediaRouterService.setSessionVolumeWithManager(
-                        client, sessionInfo.getId(), volume);
+                        client, sessionInfo.getId(), volume, requestId);
             } catch (RemoteException ex) {
                 Log.e(TAG, "Unable to send control request.", ex);
             }
@@ -443,6 +445,12 @@
         }
     }
 
+    void notifyRequestFailed(int reason) {
+        for (CallbackRecord record : mCallbackRecords) {
+            record.mExecutor.execute(() -> record.mCallback.onRequestFailed(reason));
+        }
+    }
+
     void updatePreferredFeatures(String packageName, List<String> preferredFeatures) {
         List<String> prevFeatures = mPreferredFeaturesMap.put(packageName, preferredFeatures);
         if ((prevFeatures == null && preferredFeatures.size() == 0)
@@ -593,7 +601,9 @@
             }
             if (client != null) {
                 try {
-                    mMediaRouterService.selectRouteWithManager(mClient, getSessionId(), route);
+                    int requestId = mNextRequestId.getAndIncrement();
+                    mMediaRouterService.selectRouteWithManager(
+                            mClient, getSessionId(), route, requestId);
                 } catch (RemoteException ex) {
                     Log.e(TAG, "Unable to select route for session.", ex);
                 }
@@ -635,7 +645,9 @@
             }
             if (client != null) {
                 try {
-                    mMediaRouterService.deselectRouteWithManager(mClient, getSessionId(), route);
+                    int requestId = mNextRequestId.getAndIncrement();
+                    mMediaRouterService.deselectRouteWithManager(
+                            mClient, getSessionId(), route, requestId);
                 } catch (RemoteException ex) {
                     Log.e(TAG, "Unable to remove route from session.", ex);
                 }
@@ -678,7 +690,9 @@
             }
             if (client != null) {
                 try {
-                    mMediaRouterService.transferToRouteWithManager(mClient, getSessionId(), route);
+                    int requestId = mNextRequestId.getAndIncrement();
+                    mMediaRouterService.transferToRouteWithManager(
+                            mClient, getSessionId(), route, requestId);
                 } catch (RemoteException ex) {
                     Log.e(TAG, "Unable to transfer to route for session.", ex);
                 }
@@ -696,7 +710,9 @@
             }
             if (client != null) {
                 try {
-                    mMediaRouterService.releaseSessionWithManager(mClient, getSessionId());
+                    int requestId = mNextRequestId.getAndIncrement();
+                    mMediaRouterService.releaseSessionWithManager(
+                            mClient, getSessionId(), requestId);
                 } catch (RemoteException ex) {
                     Log.e(TAG, "Unable to notify of controller release", ex);
                 }
@@ -783,6 +799,17 @@
         public void onPreferredFeaturesChanged(@NonNull String packageName,
                 @NonNull List<String> preferredFeatures) {}
 
+        /**
+         * Called when a previous request has failed.
+         *
+         * @param reason the reason that the request has failed. Can be one of followings:
+         *               {@link MediaRoute2ProviderService#REASON_UNKNOWN_ERROR},
+         *               {@link MediaRoute2ProviderService#REASON_REJECTED},
+         *               {@link MediaRoute2ProviderService#REASON_NETWORK_ERROR},
+         *               {@link MediaRoute2ProviderService#REASON_ROUTE_NOT_AVAILABLE},
+         *               {@link MediaRoute2ProviderService#REASON_INVALID_COMMAND},
+         */
+        public void onRequestFailed(int reason) {}
     }
 
     final class CallbackRecord {
@@ -826,6 +853,13 @@
         }
 
         @Override
+        public void notifyRequestFailed(int requestId, int reason) {
+            // Note: requestId is not used.
+            mHandler.sendMessage(obtainMessage(MediaRouter2Manager::notifyRequestFailed,
+                    MediaRouter2Manager.this, reason));
+        }
+
+        @Override
         public void notifyPreferredFeaturesChanged(String packageName, List<String> features) {
             mHandler.sendMessage(obtainMessage(MediaRouter2Manager::updatePreferredFeatures,
                     MediaRouter2Manager.this, packageName, features));
diff --git a/media/java/android/media/RingtoneManager.java b/media/java/android/media/RingtoneManager.java
index d058243..8deb0c4 100644
--- a/media/java/android/media/RingtoneManager.java
+++ b/media/java/android/media/RingtoneManager.java
@@ -512,15 +512,19 @@
      * @return The position of the {@link Uri}, or -1 if it cannot be found.
      */
     public int getRingtonePosition(Uri ringtoneUri) {
-        if (ringtoneUri == null) return -1;
-        final long ringtoneId = ContentUris.parseId(ringtoneUri);
-        
-        final Cursor cursor = getCursor();
-        cursor.moveToPosition(-1);
-        while (cursor.moveToNext()) {
-            if (ringtoneId == cursor.getLong(ID_COLUMN_INDEX)) {
-                return cursor.getPosition();
+        try {
+            if (ringtoneUri == null) return -1;
+            final long ringtoneId = ContentUris.parseId(ringtoneUri);
+
+            final Cursor cursor = getCursor();
+            cursor.moveToPosition(-1);
+            while (cursor.moveToNext()) {
+                if (ringtoneId == cursor.getLong(ID_COLUMN_INDEX)) {
+                    return cursor.getPosition();
+                }
             }
+        } catch (NumberFormatException e) {
+            Log.e(TAG, "NumberFormatException while getting ringtone position, returning -1", e);
         }
         return -1;
     }
diff --git a/media/java/android/media/tv/tuner/TunerUtils.java b/media/java/android/media/tv/tuner/TunerUtils.java
index 5ecb8f0..2258ee5 100644
--- a/media/java/android/media/tv/tuner/TunerUtils.java
+++ b/media/java/android/media/tv/tuner/TunerUtils.java
@@ -16,6 +16,7 @@
 
 package android.media.tv.tuner;
 
+import android.annotation.Nullable;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.hardware.tv.tuner.V1_0.Constants;
@@ -165,5 +166,33 @@
                 "Invalid filter types. Main type=" + mainType + ", subtype=" + subtype);
     }
 
+    /**
+     * Gets an throwable instance for the corresponding result.
+     */
+    @Nullable
+    public static void throwExceptionForResult(
+            @TunerConstants.Result int r, @Nullable String msg) {
+        if (msg == null) {
+            msg = "";
+        }
+        switch (r) {
+            case TunerConstants.RESULT_INVALID_ARGUMENT:
+                throw new IllegalArgumentException(msg);
+            case TunerConstants.RESULT_INVALID_STATE:
+                throw new IllegalStateException(msg);
+            case TunerConstants.RESULT_NOT_INITIALIZED:
+                throw new IllegalStateException("Invalid state: not initialized. " + msg);
+            case TunerConstants.RESULT_OUT_OF_MEMORY:
+                throw new OutOfMemoryError(msg);
+            case TunerConstants.RESULT_UNAVAILABLE:
+                throw new IllegalStateException("Invalid state: resource unavailable. " + msg);
+            case TunerConstants.RESULT_UNKNOWN_ERROR:
+                throw new RuntimeException("Unknown error" + msg);
+            default:
+                break;
+        }
+        throw new RuntimeException("Unexpected result " + r + ".  " + msg);
+    }
+
     private TunerUtils() {}
 }
diff --git a/media/java/android/media/tv/tuner/filter/TimeFilter.java b/media/java/android/media/tv/tuner/filter/TimeFilter.java
index a926d59..371ccc4 100644
--- a/media/java/android/media/tv/tuner/filter/TimeFilter.java
+++ b/media/java/android/media/tv/tuner/filter/TimeFilter.java
@@ -17,7 +17,9 @@
 package android.media.tv.tuner.filter;
 
 import android.annotation.SystemApi;
+import android.media.tv.tuner.TunerConstants;
 import android.media.tv.tuner.TunerConstants.Result;
+import android.media.tv.tuner.TunerUtils;
 
 /**
  *  A timer filter is used to filter data based on timestamps.
@@ -51,6 +53,8 @@
     private native Long nativeGetSourceTime();
     private native int nativeClose();
 
+    private long mNativeContext;
+
     private boolean mEnable = false;
 
     // Called by JNI code
@@ -139,6 +143,9 @@
      */
     @Override
     public void close() {
-        nativeClose();
+        int res = nativeClose();
+        if (res != TunerConstants.RESULT_SUCCESS) {
+            TunerUtils.throwExceptionForResult(res, "Failed to close time filter.");
+        }
     }
 }
diff --git a/media/jni/Android.bp b/media/jni/Android.bp
index c17b1b7..47ec7e6 100644
--- a/media/jni/Android.bp
+++ b/media/jni/Android.bp
@@ -160,8 +160,3 @@
         "-Wunreachable-code",
     ],
 }
-
-subdirs = [
-    "audioeffect",
-    "soundpool",
-]
diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp
index f4d2d03..4f31f6c 100644
--- a/media/jni/android_media_tv_Tuner.cpp
+++ b/media/jni/android_media_tv_Tuner.cpp
@@ -118,10 +118,12 @@
 struct fields_t {
     jfieldID tunerContext;
     jfieldID filterContext;
+    jfieldID timeFilterContext;
     jfieldID descramblerContext;
     jfieldID dvrContext;
     jmethodID frontendInitID;
     jmethodID filterInitID;
+    jmethodID timeFilterInitID;
     jmethodID dvrInitID;
     jmethodID onFrontendEventID;
     jmethodID onFilterStatusID;
@@ -237,6 +239,25 @@
     return mFilterSp;
 }
 
+/////////////// TimeFilter ///////////////////////
+
+TimeFilter::TimeFilter(sp<ITimeFilter> sp, jobject obj) : mTimeFilterSp(sp) {
+    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    mTimeFilterObj = env->NewWeakGlobalRef(obj);
+}
+
+TimeFilter::~TimeFilter() {
+    ALOGD("~TimeFilter");
+    JNIEnv *env = AndroidRuntime::getJNIEnv();
+
+    env->DeleteWeakGlobalRef(mTimeFilterObj);
+    mTimeFilterObj = NULL;
+}
+
+sp<ITimeFilter> TimeFilter::getITimeFilter() {
+    return mTimeFilterSp;
+}
+
 /////////////// FrontendCallback ///////////////////////
 
 FrontendCallback::FrontendCallback(jweak tunerObj, FrontendId id) : mObject(tunerObj), mId(id) {}
@@ -841,6 +862,36 @@
     return filterObj;
 }
 
+jobject JTuner::openTimeFilter() {
+    if (mDemux == NULL) {
+        if (!openDemux()) {
+            return NULL;
+        }
+    }
+    sp<ITimeFilter> iTimeFilterSp;
+    Result res;
+    mDemux->openTimeFilter(
+            [&](Result r, const sp<ITimeFilter>& filter) {
+                iTimeFilterSp = filter;
+                res = r;
+            });
+
+    if (res != Result::SUCCESS || iTimeFilterSp == NULL) {
+        return NULL;
+    }
+
+    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    jobject timeFilterObj =
+            env->NewObject(
+                    env->FindClass("android/media/tv/tuner/filter/TimeFilter"),
+                    gFields.timeFilterInitID);
+    sp<TimeFilter> timeFilterSp = new TimeFilter(iTimeFilterSp, timeFilterObj);
+    timeFilterSp->incStrong(timeFilterObj);
+    env->SetLongField(timeFilterObj, gFields.timeFilterContext, (jlong)timeFilterSp.get());
+
+    return timeFilterObj;
+}
+
 jobject JTuner::openDvr(DvrType type, int bufferSize) {
     ALOGD("JTuner::openDvr");
     if (mDemux == NULL) {
@@ -1420,6 +1471,10 @@
     gFields.onFilterStatusID =
             env->GetMethodID(filterClazz, "onFilterStatus", "(I)V");
 
+    jclass timeFilterClazz = env->FindClass("android/media/tv/tuner/filter/TimeFilter");
+    gFields.timeFilterContext = env->GetFieldID(timeFilterClazz, "mNativeContext", "J");
+    gFields.timeFilterInitID = env->GetMethodID(timeFilterClazz, "<init>", "()V");
+
     jclass descramblerClazz = env->FindClass("android/media/tv/tuner/Descrambler");
     gFields.descramblerContext = env->GetFieldID(descramblerClazz, "mNativeContext", "J");
     gFields.descramblerInitID =
@@ -1515,18 +1570,35 @@
 static jobject android_media_tv_Tuner_open_filter(
         JNIEnv *env, jobject thiz, jint type, jint subType, jlong bufferSize) {
     sp<JTuner> tuner = getTuner(env, thiz);
+    DemuxFilterMainType mainType = static_cast<DemuxFilterMainType>(type);
     DemuxFilterType filterType {
-        .mainType = static_cast<DemuxFilterMainType>(type),
+        .mainType = mainType,
     };
 
-    // TODO: other sub types
-    filterType.subType.tsFilterType(static_cast<DemuxTsFilterType>(subType));
+    switch(mainType) {
+        case DemuxFilterMainType::TS:
+            filterType.subType.tsFilterType(static_cast<DemuxTsFilterType>(subType));
+            break;
+        case DemuxFilterMainType::MMTP:
+            filterType.subType.mmtpFilterType(static_cast<DemuxMmtpFilterType>(subType));
+            break;
+        case DemuxFilterMainType::IP:
+            filterType.subType.ipFilterType(static_cast<DemuxIpFilterType>(subType));
+            break;
+        case DemuxFilterMainType::TLV:
+            filterType.subType.tlvFilterType(static_cast<DemuxTlvFilterType>(subType));
+            break;
+        case DemuxFilterMainType::ALP:
+            filterType.subType.alpFilterType(static_cast<DemuxAlpFilterType>(subType));
+            break;
+    }
 
     return tuner->openFilter(filterType, bufferSize);
 }
 
-static jobject android_media_tv_Tuner_open_time_filter(JNIEnv, jobject) {
-    return NULL;
+static jobject android_media_tv_Tuner_open_time_filter(JNIEnv *env, jobject thiz) {
+    sp<JTuner> tuner = getTuner(env, thiz);
+    return tuner->openTimeFilter();
 }
 
 static DemuxFilterSectionBits getFilterSectionBits(JNIEnv *env, const jobject& settings) {
@@ -1987,26 +2059,98 @@
     return 0;
 }
 
-// TODO: implement TimeFilter functions
+static sp<TimeFilter> getTimeFilter(JNIEnv *env, jobject filter) {
+    return (TimeFilter *)env->GetLongField(filter, gFields.timeFilterContext);
+}
+
 static int android_media_tv_Tuner_time_filter_set_timestamp(
-        JNIEnv, jobject, jlong) {
-    return 0;
+        JNIEnv *env, jobject filter, jlong timestamp) {
+    sp<TimeFilter> filterSp = getTimeFilter(env, filter);
+    if (filterSp == NULL) {
+        ALOGD("Failed set timestamp: time filter not found");
+        return (int) Result::INVALID_STATE;
+    }
+    sp<ITimeFilter> iFilterSp = filterSp->getITimeFilter();
+    Result r = iFilterSp->setTimeStamp(static_cast<uint64_t>(timestamp));
+    return (int) r;
 }
 
-static int android_media_tv_Tuner_time_filter_clear_timestamp(JNIEnv, jobject) {
-    return 0;
+static int android_media_tv_Tuner_time_filter_clear_timestamp(JNIEnv *env, jobject filter) {
+    sp<TimeFilter> filterSp = getTimeFilter(env, filter);
+    if (filterSp == NULL) {
+        ALOGD("Failed clear timestamp: time filter not found");
+        return (int) Result::INVALID_STATE;
+    }
+    sp<ITimeFilter> iFilterSp = filterSp->getITimeFilter();
+    Result r = iFilterSp->clearTimeStamp();
+    return (int) r;
 }
 
-static jobject android_media_tv_Tuner_time_filter_get_timestamp(JNIEnv, jobject) {
-    return NULL;
+static jobject android_media_tv_Tuner_time_filter_get_timestamp(JNIEnv *env, jobject filter) {
+    sp<TimeFilter> filterSp = getTimeFilter(env, filter);
+    if (filterSp == NULL) {
+        ALOGD("Failed get timestamp: time filter not found");
+        return NULL;
+    }
+
+    sp<ITimeFilter> iFilterSp = filterSp->getITimeFilter();
+    Result res;
+    uint64_t timestamp;
+    iFilterSp->getTimeStamp(
+            [&](Result r, uint64_t t) {
+                res = r;
+                timestamp = t;
+            });
+    if (res != Result::SUCCESS) {
+        return NULL;
+    }
+
+    jclass longClazz = env->FindClass("java/lang/Long");
+    jmethodID longInit = env->GetMethodID(longClazz, "<init>", "(J)V");
+
+    jobject longObj = env->NewObject(longClazz, longInit, static_cast<jlong>(timestamp));
+    return longObj;
 }
 
-static jobject android_media_tv_Tuner_time_filter_get_source_time(JNIEnv, jobject) {
-    return NULL;
+static jobject android_media_tv_Tuner_time_filter_get_source_time(JNIEnv *env, jobject filter) {
+    sp<TimeFilter> filterSp = getTimeFilter(env, filter);
+    if (filterSp == NULL) {
+        ALOGD("Failed get source time: time filter not found");
+        return NULL;
+    }
+
+    sp<ITimeFilter> iFilterSp = filterSp->getITimeFilter();
+    Result res;
+    uint64_t timestamp;
+    iFilterSp->getSourceTime(
+            [&](Result r, uint64_t t) {
+                res = r;
+                timestamp = t;
+            });
+    if (res != Result::SUCCESS) {
+        return NULL;
+    }
+
+    jclass longClazz = env->FindClass("java/lang/Long");
+    jmethodID longInit = env->GetMethodID(longClazz, "<init>", "(J)V");
+
+    jobject longObj = env->NewObject(longClazz, longInit, static_cast<jlong>(timestamp));
+    return longObj;
 }
 
-static int android_media_tv_Tuner_time_filter_close(JNIEnv, jobject) {
-    return 0;
+static int android_media_tv_Tuner_time_filter_close(JNIEnv *env, jobject filter) {
+    sp<TimeFilter> filterSp = getTimeFilter(env, filter);
+    if (filterSp == NULL) {
+        ALOGD("Failed close time filter: time filter not found");
+        return (int) Result::INVALID_STATE;
+    }
+
+    Result r = filterSp->getITimeFilter()->close();
+    if (r == Result::SUCCESS) {
+        filterSp->decStrong(filter);
+        env->SetLongField(filter, gFields.timeFilterContext, 0);
+    }
+    return (int) r;
 }
 
 static jobject android_media_tv_Tuner_open_descrambler(JNIEnv *env, jobject thiz) {
diff --git a/media/jni/android_media_tv_Tuner.h b/media/jni/android_media_tv_Tuner.h
index d899bbd..c5590b9 100644
--- a/media/jni/android_media_tv_Tuner.h
+++ b/media/jni/android_media_tv_Tuner.h
@@ -54,6 +54,7 @@
 using ::android::hardware::tv::tuner::V1_0::IFrontendCallback;
 using ::android::hardware::tv::tuner::V1_0::ILnb;
 using ::android::hardware::tv::tuner::V1_0::ILnbCallback;
+using ::android::hardware::tv::tuner::V1_0::ITimeFilter;
 using ::android::hardware::tv::tuner::V1_0::ITuner;
 using ::android::hardware::tv::tuner::V1_0::LnbEventType;
 using ::android::hardware::tv::tuner::V1_0::LnbId;
@@ -127,6 +128,14 @@
     jweak mFilterObj;
 };
 
+struct TimeFilter : public RefBase {
+    TimeFilter(sp<ITimeFilter> sp, jweak obj);
+    ~TimeFilter();
+    sp<ITimeFilter> getITimeFilter();
+    sp<ITimeFilter> mTimeFilterSp;
+    jweak mTimeFilterObj;
+};
+
 struct JTuner : public RefBase {
     JTuner(JNIEnv *env, jobject thiz);
     sp<ITuner> getTunerService();
@@ -142,6 +151,7 @@
     jobject getLnbIds();
     jobject openLnbById(int id);
     jobject openFilter(DemuxFilterType type, int bufferSize);
+    jobject openTimeFilter();
     jobject openDescrambler();
     jobject openDvr(DvrType type, int bufferSize);
 
diff --git a/media/native/Android.bp b/media/native/Android.bp
deleted file mode 100644
index b44c296..0000000
--- a/media/native/Android.bp
+++ /dev/null
@@ -1 +0,0 @@
-subdirs = ["*"]
diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java
index e80562b..bcff6a1 100644
--- a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java
+++ b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java
@@ -19,6 +19,8 @@
 import static android.media.MediaRoute2Info.FEATURE_LIVE_AUDIO;
 import static android.media.MediaRoute2Info.PLAYBACK_VOLUME_FIXED;
 import static android.media.MediaRoute2Info.PLAYBACK_VOLUME_VARIABLE;
+import static android.media.MediaRoute2ProviderService.REASON_REJECTED;
+import static android.media.MediaRoute2ProviderService.REQUEST_ID_NONE;
 
 import static com.android.mediaroutertest.SampleMediaRoute2ProviderService.FEATURE_SAMPLE;
 import static com.android.mediaroutertest.SampleMediaRoute2ProviderService.FEATURE_SPECIAL;
@@ -32,6 +34,7 @@
 import static com.android.mediaroutertest.SampleMediaRoute2ProviderService.VOLUME_MAX;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 
@@ -55,7 +58,6 @@
 import org.junit.runner.RunWith;
 
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -69,6 +71,7 @@
 @SmallTest
 public class MediaRouter2ManagerTest {
     private static final String TAG = "MediaRouter2ManagerTest";
+    private static final int WAIT_TIME_MS = 2000;
     private static final int TIMEOUT_MS = 5000;
 
     private Context mContext;
@@ -111,6 +114,11 @@
         releaseAllSessions();
         // unregister callbacks
         clearCallbacks();
+
+        SampleMediaRoute2ProviderService instance = SampleMediaRoute2ProviderService.getInstance();
+        if (instance != null) {
+            instance.setProxy(null);
+        }
     }
 
     @Test
@@ -296,7 +304,7 @@
         String selectedSystemRouteId =
                 MediaRouter2Utils.getOriginalId(
                 mManager.getActiveSessions().get(0).getSelectedRoutes().get(0));
-        Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(Collections.emptyList());
+        Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(FEATURES_ALL);
         MediaRoute2Info volRoute = routes.get(selectedSystemRouteId);
         assertNotNull(volRoute);
 
@@ -398,6 +406,53 @@
         }
     }
 
+    /**
+     * Tests that {@link android.media.MediaRoute2ProviderService#notifyRequestFailed(long, int)}
+     * should invoke the callback only when the right requestId is used.
+     */
+    @Test
+    public void testOnRequestFailedCalledForProperRequestId() throws Exception {
+        Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(FEATURES_ALL);
+        MediaRoute2Info volRoute = routes.get(ROUTE_ID_VARIABLE_VOLUME);
+
+        SampleMediaRoute2ProviderService instance = SampleMediaRoute2ProviderService.getInstance();
+        assertNotNull(instance);
+
+        final List<Long> requestIds = new ArrayList<>();
+        final CountDownLatch onSetRouteVolumeLatch = new CountDownLatch(1);
+        instance.setProxy(new SampleMediaRoute2ProviderService.Proxy() {
+            @Override
+            public void onSetRouteVolume(String routeId, int volume, long requestId) {
+                requestIds.add(requestId);
+                onSetRouteVolumeLatch.countDown();
+            }
+        });
+
+        addManagerCallback(new MediaRouter2Manager.Callback() {});
+        mManager.setRouteVolume(volRoute, 0);
+        assertTrue(onSetRouteVolumeLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        assertFalse(requestIds.isEmpty());
+
+        final int failureReason = REASON_REJECTED;
+        final CountDownLatch onRequestFailedLatch = new CountDownLatch(1);
+        addManagerCallback(new MediaRouter2Manager.Callback() {
+            @Override
+            public void onRequestFailed(int reason) {
+                if (reason == failureReason) {
+                    onRequestFailedLatch.countDown();
+                }
+            }
+        });
+
+        final long invalidRequestId = REQUEST_ID_NONE;
+        instance.notifyRequestFailed(invalidRequestId, failureReason);
+        assertFalse(onRequestFailedLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+
+        final long validRequestId = requestIds.get(0);
+        instance.notifyRequestFailed(validRequestId, failureReason);
+        assertTrue(onRequestFailedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+    }
+
     @Test
     public void testVolumeHandling() throws Exception {
         Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(FEATURES_ALL);
@@ -429,10 +484,11 @@
             }
 
             @Override
-            public void onControlCategoriesChanged(String packageName,
+            public void onPreferredFeaturesChanged(String packageName,
                     List<String> preferredFeatures) {
                 if (TextUtils.equals(mPackageName, packageName)
-                        && preferredFeatures.equals(routeFeatures)) {
+                        && preferredFeatures.size() == routeFeatures.size()
+                        && preferredFeatures.containsAll(routeFeatures)) {
                     featuresLatch.countDown();
                 }
             }
diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/SampleMediaRoute2ProviderService.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/SampleMediaRoute2ProviderService.java
index 3faefdb..0e7c7fc 100644
--- a/media/tests/MediaRouter/src/com/android/mediaroutertest/SampleMediaRoute2ProviderService.java
+++ b/media/tests/MediaRouter/src/com/android/mediaroutertest/SampleMediaRoute2ProviderService.java
@@ -16,9 +16,9 @@
 
 package com.android.mediaroutertest;
 
-import static android.media.MediaRoute2Info.DEVICE_TYPE_REMOTE_SPEAKER;
-import static android.media.MediaRoute2Info.DEVICE_TYPE_REMOTE_TV;
 import static android.media.MediaRoute2Info.PLAYBACK_VOLUME_VARIABLE;
+import static android.media.MediaRoute2Info.TYPE_REMOTE_SPEAKER;
+import static android.media.MediaRoute2Info.TYPE_REMOTE_TV;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -75,15 +75,16 @@
 
     @GuardedBy("sLock")
     private static SampleMediaRoute2ProviderService sInstance;
+    private Proxy mProxy;
 
     private void initializeRoutes() {
         MediaRoute2Info route1 = new MediaRoute2Info.Builder(ROUTE_ID1, ROUTE_NAME1)
                 .addFeature(FEATURE_SAMPLE)
-                .setDeviceType(DEVICE_TYPE_REMOTE_TV)
+                .setType(TYPE_REMOTE_TV)
                 .build();
         MediaRoute2Info route2 = new MediaRoute2Info.Builder(ROUTE_ID2, ROUTE_NAME2)
                 .addFeature(FEATURE_SAMPLE)
-                .setDeviceType(DEVICE_TYPE_REMOTE_SPEAKER)
+                .setType(TYPE_REMOTE_SPEAKER)
                 .build();
         MediaRoute2Info route3 = new MediaRoute2Info.Builder(
                 ROUTE_ID3_SESSION_CREATION_FAILED, ROUTE_NAME3)
@@ -179,7 +180,13 @@
     }
 
     @Override
-    public void onSetRouteVolume(String routeId, int volume) {
+    public void onSetRouteVolume(long requestId, String routeId, int volume) {
+        Proxy proxy = mProxy;
+        if (proxy != null) {
+            proxy.onSetRouteVolume(routeId, volume, requestId);
+            return;
+        }
+
         MediaRoute2Info route = mRoutes.get(routeId);
         if (route == null) {
             return;
@@ -192,7 +199,7 @@
     }
 
     @Override
-    public void onSetSessionVolume(String sessionId, int volume) {
+    public void onSetSessionVolume(long requestId, String sessionId, int volume) {
         RoutingSessionInfo sessionInfo = getSessionInfo(sessionId);
         if (sessionInfo == null) {
             return;
@@ -205,7 +212,7 @@
     }
 
     @Override
-    public void onCreateSession(String packageName, String routeId, long requestId,
+    public void onCreateSession(long requestId, String packageName, String routeId,
             @Nullable Bundle sessionHints) {
         MediaRoute2Info route = mRoutes.get(routeId);
         if (route == null || TextUtils.equals(ROUTE_ID3_SESSION_CREATION_FAILED, routeId)) {
@@ -238,7 +245,7 @@
     }
 
     @Override
-    public void onReleaseSession(String sessionId) {
+    public void onReleaseSession(long requestId, String sessionId) {
         RoutingSessionInfo sessionInfo = getSessionInfo(sessionId);
         if (sessionInfo == null) {
             return;
@@ -258,7 +265,7 @@
     }
 
     @Override
-    public void onSelectRoute(String sessionId, String routeId) {
+    public void onSelectRoute(long requestId, String sessionId, String routeId) {
         RoutingSessionInfo sessionInfo = getSessionInfo(sessionId);
         MediaRoute2Info route = mRoutes.get(routeId);
         if (route == null || sessionInfo == null) {
@@ -280,7 +287,7 @@
     }
 
     @Override
-    public void onDeselectRoute(String sessionId, String routeId) {
+    public void onDeselectRoute(long requestId, String sessionId, String routeId) {
         RoutingSessionInfo sessionInfo = getSessionInfo(sessionId);
         MediaRoute2Info route = mRoutes.get(routeId);
 
@@ -308,7 +315,7 @@
     }
 
     @Override
-    public void onTransferToRoute(String sessionId, String routeId) {
+    public void onTransferToRoute(long requestId, String sessionId, String routeId) {
         RoutingSessionInfo sessionInfo = getSessionInfo(sessionId);
         MediaRoute2Info route = mRoutes.get(routeId);
 
@@ -347,10 +354,18 @@
         }
 
         String sessionId = mRouteIdToSessionId.get(routeId);
-        onDeselectRoute(sessionId, routeId);
+        onDeselectRoute(REQUEST_ID_NONE, sessionId, routeId);
     }
 
     void publishRoutes() {
         notifyRoutes(mRoutes.values());
     }
+
+    public void setProxy(@Nullable Proxy proxy) {
+        mProxy = proxy;
+    }
+
+    public static class Proxy {
+        public void onSetRouteVolume(String routeId, int volume, long requestId) {}
+    }
 }
diff --git a/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java b/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java
index c9ac765..873d7d7 100644
--- a/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java
+++ b/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java
@@ -25,8 +25,11 @@
 import android.app.KeyguardManager;
 import android.car.Car;
 import android.car.media.CarAudioManager;
+import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.res.TypedArray;
 import android.content.res.XmlResourceParser;
 import android.graphics.Color;
@@ -38,6 +41,7 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
+import android.os.UserHandle;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.SparseArray;
@@ -171,6 +175,17 @@
                 mCarAudioManager.registerCarVolumeCallback(mVolumeChangeCallback);
             };
 
+    private final BroadcastReceiver mHomeButtonPressedBroadcastReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (!intent.getAction().equals(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)) {
+                return;
+            }
+
+            dismissH(Events.DISMISS_REASON_VOLUME_CONTROLLER);
+        }
+    };
+
     public CarVolumeDialogImpl(Context context) {
         mContext = context;
         mKeyguard = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
@@ -204,12 +219,18 @@
     @Override
     public void init(int windowType, Callback callback) {
         initDialog();
+
+        mContext.registerReceiverAsUser(mHomeButtonPressedBroadcastReceiver, UserHandle.CURRENT,
+                new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS), /* broadcastPermission= */
+                null, /* scheduler= */ null);
     }
 
     @Override
     public void destroy() {
         mHandler.removeCallbacksAndMessages(/* token= */ null);
 
+        mContext.unregisterReceiver(mHomeButtonPressedBroadcastReceiver);
+
         cleanupAudioManager();
     }
 
diff --git a/packages/DynamicSystemInstallationService/AndroidManifest.xml b/packages/DynamicSystemInstallationService/AndroidManifest.xml
index d718eae..b4d520d 100644
--- a/packages/DynamicSystemInstallationService/AndroidManifest.xml
+++ b/packages/DynamicSystemInstallationService/AndroidManifest.xml
@@ -7,6 +7,7 @@
     <uses-permission android:name="android.permission.MANAGE_DYNAMIC_SYSTEM" />
     <uses-permission android:name="android.permission.REBOOT" />
     <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
+    <uses-permission android:name="android.permission.READ_OEM_UNLOCK_STATE" />
 
     <application
         android:allowBackup="false"
diff --git a/packages/DynamicSystemInstallationService/res/values/strings.xml b/packages/DynamicSystemInstallationService/res/values/strings.xml
index 7595d2b..e124be6 100644
--- a/packages/DynamicSystemInstallationService/res/values/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values/strings.xml
@@ -18,6 +18,8 @@
     <string name="notification_install_inprogress">Install in progress</string>
     <!-- Displayed on notification: Dynamic System installation failed [CHAR LIMIT=128] -->
     <string name="notification_install_failed">Install failed</string>
+    <!-- Displayed on notification: Image validation failed [CHAR LIMIT=128] -->
+    <string name="notification_image_validation_failed">Image validation failed. Abort installation.</string>
     <!-- Displayed on notification: We are running in Dynamic System [CHAR LIMIT=128] -->
     <string name="notification_dynsystem_in_use">Currently running a dynamic system. Restart to use the original Android version.</string>
 
@@ -25,10 +27,11 @@
     <string name="notification_action_cancel">Cancel</string>
     <!-- Action on notification: Discard installation [CHAR LIMIT=16] -->
     <string name="notification_action_discard">Discard</string>
-    <!-- Action on notification: Uninstall Dynamic System [CHAR LIMIT=16] -->
-    <string name="notification_action_uninstall">Uninstall</string>
     <!-- Action on notification: Restart to Dynamic System [CHAR LIMIT=16] -->
     <string name="notification_action_reboot_to_dynsystem">Restart</string>
+    <!-- Action on notification: Restart to original Android version [CHAR LIMIT=16] -->
+    <string name="notification_action_reboot_to_origin">Restart</string>
+
 
     <!-- Toast when installed Dynamic System is discarded [CHAR LIMIT=64] -->
     <string name="toast_dynsystem_discarded">Discarded dynamic system</string>
diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
index 9bae223..37a77be 100644
--- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
+++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
@@ -80,6 +80,7 @@
     static final String KEY_ENABLE_WHEN_COMPLETED = "KEY_ENABLE_WHEN_COMPLETED";
     static final String KEY_DSU_SLOT = "KEY_DSU_SLOT";
     static final String DEFAULT_DSU_SLOT = "dsu";
+    static final String KEY_PUBKEY = "KEY_PUBKEY";
 
     /*
      * Intent actions
@@ -267,6 +268,7 @@
         long userdataSize = intent.getLongExtra(DynamicSystemClient.KEY_USERDATA_SIZE, 0);
         mEnableWhenCompleted = intent.getBooleanExtra(KEY_ENABLE_WHEN_COMPLETED, false);
         String dsuSlot = intent.getStringExtra(KEY_DSU_SLOT);
+        String publicKey = intent.getStringExtra(KEY_PUBKEY);
 
         if (TextUtils.isEmpty(dsuSlot)) {
             dsuSlot = DEFAULT_DSU_SLOT;
@@ -274,7 +276,7 @@
         // TODO: better constructor or builder
         mInstallTask =
                 new InstallationAsyncTask(
-                        url, dsuSlot, systemSize, userdataSize, this, mDynSystem, this);
+                        url, dsuSlot, publicKey, systemSize, userdataSize, this, mDynSystem, this);
 
         mInstallTask.execute();
 
@@ -408,6 +410,10 @@
     }
 
     private Notification buildNotification(int status, int cause) {
+        return buildNotification(status, cause, null);
+    }
+
+    private Notification buildNotification(int status, int cause, Throwable detail) {
         Notification.Builder builder = new Notification.Builder(this, NOTIFICATION_CHANNEL_ID)
                 .setSmallIcon(R.drawable.ic_system_update_googblue_24dp)
                 .setProgress(0, 0, false);
@@ -456,14 +462,19 @@
                         .setStyle(new Notification.BigTextStyle().bigText(msgInUse));
 
                 builder.addAction(new Notification.Action.Builder(
-                        null, getString(R.string.notification_action_uninstall),
+                        null, getString(R.string.notification_action_reboot_to_origin),
                         createPendingIntent(ACTION_REBOOT_TO_NORMAL)).build());
 
                 break;
 
             case STATUS_NOT_STARTED:
                 if (cause != CAUSE_NOT_SPECIFIED && cause != CAUSE_INSTALL_CANCELLED) {
-                    builder.setContentText(getString(R.string.notification_install_failed));
+                    if (detail instanceof InstallationAsyncTask.ImageValidationException) {
+                        builder.setContentText(
+                                getString(R.string.notification_image_validation_failed));
+                    } else {
+                        builder.setContentText(getString(R.string.notification_install_failed));
+                    }
                 } else {
                     // no need to notify the user if the task is not started, or cancelled.
                 }
@@ -525,7 +536,7 @@
                 break;
         }
 
-        Log.d(TAG, "status=" + statusString + ", cause=" + causeString);
+        Log.d(TAG, "status=" + statusString + ", cause=" + causeString + ", detail=" + detail);
 
         boolean notifyOnNotificationBar = true;
 
@@ -538,7 +549,7 @@
         }
 
         if (notifyOnNotificationBar) {
-            mNM.notify(NOTIFICATION_ID, buildNotification(status, cause));
+            mNM.notify(NOTIFICATION_ID, buildNotification(status, cause, detail));
         }
 
         for (int i = mClients.size() - 1; i >= 0; i--) {
diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java
index 438c435..f8952ac 100644
--- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java
+++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java
@@ -17,11 +17,13 @@
 package com.android.dynsystem;
 
 import android.content.Context;
+import android.gsi.AvbPublicKey;
 import android.net.Uri;
 import android.os.AsyncTask;
 import android.os.MemoryFile;
 import android.os.ParcelFileDescriptor;
 import android.os.image.DynamicSystemManager;
+import android.service.persistentdata.PersistentDataBlockManager;
 import android.util.Log;
 import android.webkit.URLUtil;
 
@@ -51,18 +53,46 @@
     private static final List<String> UNSUPPORTED_PARTITIONS =
             Arrays.asList("vbmeta", "boot", "userdata", "dtbo", "super_empty", "system_other");
 
-    private class UnsupportedUrlException extends RuntimeException {
+    private class UnsupportedUrlException extends Exception {
         private UnsupportedUrlException(String message) {
             super(message);
         }
     }
 
-    private class UnsupportedFormatException extends RuntimeException {
+    private class UnsupportedFormatException extends Exception {
         private UnsupportedFormatException(String message) {
             super(message);
         }
     }
 
+    static class ImageValidationException extends Exception {
+        ImageValidationException(String message) {
+            super(message);
+        }
+
+        ImageValidationException(Throwable cause) {
+            super(cause);
+        }
+    }
+
+    static class RevocationListFetchException extends ImageValidationException {
+        RevocationListFetchException(Throwable cause) {
+            super(cause);
+        }
+    }
+
+    static class KeyRevokedException extends ImageValidationException {
+        KeyRevokedException(String message) {
+            super(message);
+        }
+    }
+
+    static class PublicKeyException extends ImageValidationException {
+        PublicKeyException(String message) {
+            super(message);
+        }
+    }
+
     /** UNSET means the installation is not completed */
     static final int RESULT_UNSET = 0;
     static final int RESULT_OK = 1;
@@ -97,12 +127,14 @@
 
     private final String mUrl;
     private final String mDsuSlot;
+    private final String mPublicKey;
     private final long mSystemSize;
     private final long mUserdataSize;
     private final Context mContext;
     private final DynamicSystemManager mDynSystem;
     private final ProgressListener mListener;
     private final boolean mIsNetworkUrl;
+    private final boolean mIsDeviceBootloaderUnlocked;
     private DynamicSystemManager.Session mInstallationSession;
     private KeyRevocationList mKeyRevocationList;
 
@@ -115,6 +147,7 @@
     InstallationAsyncTask(
             String url,
             String dsuSlot,
+            String publicKey,
             long systemSize,
             long userdataSize,
             Context context,
@@ -122,12 +155,20 @@
             ProgressListener listener) {
         mUrl = url;
         mDsuSlot = dsuSlot;
+        mPublicKey = publicKey;
         mSystemSize = systemSize;
         mUserdataSize = userdataSize;
         mContext = context;
         mDynSystem = dynSystem;
         mListener = listener;
         mIsNetworkUrl = URLUtil.isNetworkUrl(mUrl);
+        PersistentDataBlockManager pdbManager =
+                (PersistentDataBlockManager)
+                        mContext.getSystemService(Context.PERSISTENT_DATA_BLOCK_SERVICE);
+        mIsDeviceBootloaderUnlocked =
+                (pdbManager != null)
+                        && (pdbManager.getFlashLockState()
+                                == PersistentDataBlockManager.FLASH_LOCK_UNLOCKED);
     }
 
     @Override
@@ -157,8 +198,6 @@
                 return null;
             }
 
-            // TODO(yochiang): do post-install public key check (revocation list / boot-ramdisk)
-
             mDynSystem.finishInstallation();
         } catch (Exception e) {
             Log.e(TAG, e.toString(), e);
@@ -242,23 +281,26 @@
                     String.format(Locale.US, "Unsupported URL: %s", mUrl));
         }
 
-        // TODO(yochiang): Bypass this check if device is unlocked
         try {
             String listUrl = mContext.getString(R.string.key_revocation_list_url);
             mKeyRevocationList = KeyRevocationList.fromUrl(new URL(listUrl));
         } catch (IOException | JSONException e) {
-            Log.d(TAG, "Failed to fetch Dynamic System Key Revocation List");
             mKeyRevocationList = new KeyRevocationList();
-            keyRevocationThrowOrWarning(e);
+            imageValidationThrowOrWarning(new RevocationListFetchException(e));
+        }
+        if (mKeyRevocationList.isRevoked(mPublicKey)) {
+            imageValidationThrowOrWarning(new KeyRevokedException(mPublicKey));
         }
     }
 
-    private void keyRevocationThrowOrWarning(Exception e) throws Exception {
-        if (mIsNetworkUrl) {
-            throw e;
-        } else {
-            // If DSU is being installed from a local file URI, then be permissive
+    private void imageValidationThrowOrWarning(ImageValidationException e)
+            throws ImageValidationException {
+        if (mIsDeviceBootloaderUnlocked || !mIsNetworkUrl) {
+            // If device is OEM unlocked or DSU is being installed from a local file URI,
+            // then be permissive.
             Log.w(TAG, e.toString());
+        } else {
+            throw e;
         }
     }
 
@@ -294,7 +336,8 @@
         }
     }
 
-    private void installImages() throws IOException, InterruptedException {
+    private void installImages()
+            throws IOException, InterruptedException, ImageValidationException {
         if (mStream != null) {
             if (mIsZip) {
                 installStreamingZipUpdate();
@@ -306,12 +349,14 @@
         }
     }
 
-    private void installStreamingGzUpdate() throws IOException, InterruptedException {
+    private void installStreamingGzUpdate()
+            throws IOException, InterruptedException, ImageValidationException {
         Log.d(TAG, "To install a streaming GZ update");
         installImage("system", mSystemSize, new GZIPInputStream(mStream), 1);
     }
 
-    private void installStreamingZipUpdate() throws IOException, InterruptedException {
+    private void installStreamingZipUpdate()
+            throws IOException, InterruptedException, ImageValidationException {
         Log.d(TAG, "To install a streaming ZIP update");
 
         ZipInputStream zis = new ZipInputStream(mStream);
@@ -330,7 +375,8 @@
         }
     }
 
-    private void installLocalZipUpdate() throws IOException, InterruptedException {
+    private void installLocalZipUpdate()
+            throws IOException, InterruptedException, ImageValidationException {
         Log.d(TAG, "To install a local ZIP update");
 
         Enumeration<? extends ZipEntry> entries = mZipFile.entries();
@@ -349,8 +395,9 @@
         }
     }
 
-    private boolean installImageFromAnEntry(ZipEntry entry, InputStream is,
-            int numInstalledPartitions) throws IOException, InterruptedException {
+    private boolean installImageFromAnEntry(
+            ZipEntry entry, InputStream is, int numInstalledPartitions)
+            throws IOException, InterruptedException, ImageValidationException {
         String name = entry.getName();
 
         Log.d(TAG, "ZipEntry: " + name);
@@ -373,8 +420,9 @@
         return true;
     }
 
-    private void installImage(String partitionName, long uncompressedSize, InputStream is,
-            int numInstalledPartitions) throws IOException, InterruptedException {
+    private void installImage(
+            String partitionName, long uncompressedSize, InputStream is, int numInstalledPartitions)
+            throws IOException, InterruptedException, ImageValidationException {
 
         SparseInputStream sis = new SparseInputStream(new BufferedInputStream(is));
 
@@ -445,6 +493,24 @@
                 publishProgress(progress);
             }
         }
+
+        AvbPublicKey avbPublicKey = new AvbPublicKey();
+        if (!mInstallationSession.getAvbPublicKey(avbPublicKey)) {
+            imageValidationThrowOrWarning(new PublicKeyException("getAvbPublicKey() failed"));
+        } else {
+            String publicKey = toHexString(avbPublicKey.sha1);
+            if (mKeyRevocationList.isRevoked(publicKey)) {
+                imageValidationThrowOrWarning(new KeyRevokedException(publicKey));
+            }
+        }
+    }
+
+    private static String toHexString(byte[] bytes) {
+        StringBuilder sb = new StringBuilder();
+        for (byte b : bytes) {
+            sb.append(String.format("%02x", b));
+        }
+        return sb.toString();
     }
 
     private void close() {
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 59881e7..d25e3e2 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -886,6 +886,11 @@
     <!-- UI debug setting: enable gpu debug layers summary [CHAR LIMIT=50] -->
     <string name="enable_gpu_debug_layers_summary">Allow loading GPU debug layers for debug apps</string>
 
+    <!-- UI debug setting: enable verbose vendor logging [CHAR LIMIT=30] -->
+    <string name="enable_verbose_vendor_logging">Enable verbose vendor logging</string>
+    <!-- UI debug setting: enable verbose vendor logging summary [CHAR LIMIT=100] -->
+    <string name="enable_verbose_vendor_logging_summary">Allow additional vendor logs to be included in bug reports, may contain private information</string>
+
     <!-- UI debug setting: scaling factor for window animations [CHAR LIMIT=25] -->
     <string name="window_animation_scale_title">Window animation scale</string>
 
@@ -1260,9 +1265,12 @@
     <!-- The notice header of Third-party licenses. not translatable -->
     <string name="notice_header" translatable="false"></string>
 
-    <!-- Name of the this device. [CHAR LIMIT=30] -->
-    <string name="media_transfer_this_device_name">This device</string>
+    <!-- Name of the phone device. [CHAR LIMIT=30] -->
+    <string name="media_transfer_this_device_name">Phone speaker</string>
 
     <!-- Warning message to tell user is have problem during profile connect, it need to turn off device and back on. [CHAR_LIMIT=NONE] -->
     <string name="profile_connect_timeout_subtext">Problem connecting. Turn device off &amp; back on</string>
+
+    <!-- Name of the 3.5mm audio device. [CHAR LIMIT=40] -->
+    <string name="media_transfer_wired_device_name">Wired audio device</string>
 </resources>
diff --git a/packages/SettingsLib/src/com/android/settingslib/display/DisplayDensityUtils.java b/packages/SettingsLib/src/com/android/settingslib/display/DisplayDensityUtils.java
index e0ca1ab..a38091d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/display/DisplayDensityUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/display/DisplayDensityUtils.java
@@ -97,7 +97,7 @@
 
         final Resources res = context.getResources();
         final DisplayMetrics metrics = new DisplayMetrics();
-        context.getDisplay().getRealMetrics(metrics);
+        context.getDisplayNoVerify().getRealMetrics(metrics);
 
         final int currentDensity = metrics.densityDpi;
         int currentDensityIndex = -1;
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index aad46e9..2dc6f39 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -989,6 +989,11 @@
                             String value = setting != null ? setting.getValue() : null;
                             updateGlobalSetting(Settings.Global.ADB_ENABLED,
                                     value, null, true, userId, true);
+
+                            setting = getGlobalSetting(Settings.Global.ADB_WIFI_ENABLED);
+                            value = setting != null ? setting.getValue() : null;
+                            updateGlobalSetting(Settings.Global.ADB_WIFI_ENABLED,
+                                    value, null, true, userId, true);
                         }
                     } finally {
                         Binder.restoreCallingIdentity(identity);
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 4dc372a..0f2ee6a 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -111,6 +111,7 @@
                     Settings.Global.ADAPTIVE_BATTERY_MANAGEMENT_ENABLED,
                     Settings.Global.ADB_ALLOWED_CONNECTION_TIME,
                     Settings.Global.ADB_ENABLED,
+                    Settings.Global.ADB_WIFI_ENABLED,
                     Settings.Global.ADD_USERS_WHEN_LOCKED,
                     Settings.Global.AIRPLANE_MODE_ON,
                     Settings.Global.AIRPLANE_MODE_RADIOS,
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index de174b1..e066230 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -86,7 +86,9 @@
 
 android_library {
     name: "SystemUI-tests",
-    manifest: "tests/AndroidManifest.xml",
+    manifest: "tests/AndroidManifest-base.xml",
+    additional_manifests: ["tests/AndroidManifest.xml"],
+
     resource_dirs: [
         "tests/res",
         "res-product",
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 5458676e..f141578 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -457,6 +457,25 @@
             android:excludeFromRecents="true">
         </activity>
 
+        <!-- started from WirelessDebuggingManager -->
+        <activity android:name=".wifi.WifiDebuggingActivity"
+            android:permission="android.permission.MANAGE_DEBUGGING"
+            android:theme="@style/Theme.SystemUI.Dialog.Alert"
+            android:finishOnCloseSystemDialogs="true"
+            android:excludeFromRecents="true">
+        </activity>
+        <activity-alias
+            android:name=".WifiDebuggingActivityAlias"
+            android:permission="android.permission.DUMP"
+            android:targetActivity=".wifi.WifiDebuggingActivity"
+            android:exported="true">
+        </activity-alias>
+        <activity android:name=".wifi.WifiDebuggingSecondaryUserActivity"
+            android:theme="@style/Theme.SystemUI.Dialog.Alert"
+            android:finishOnCloseSystemDialogs="true"
+            android:excludeFromRecents="true">
+        </activity>
+
         <!-- started from NetworkPolicyManagerService -->
         <activity
             android:name=".net.NetworkOverLimitActivity"
@@ -696,8 +715,7 @@
         <provider
             android:name="com.android.keyguard.clock.ClockOptionsProvider"
             android:authorities="com.android.keyguard.clock"
-            android:enabled="false"
-            android:exported="false"
+            android:exported="true"
             android:grantUriPermissions="true">
         </provider>
 
diff --git a/packages/SystemUI/res/layout/people_strip.xml b/packages/SystemUI/res/layout/people_strip.xml
index 982aa8e..c2dbaca 100644
--- a/packages/SystemUI/res/layout/people_strip.xml
+++ b/packages/SystemUI/res/layout/people_strip.xml
@@ -19,39 +19,34 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="@dimen/notification_section_header_height"
+    android:paddingStart="4dp"
+    android:paddingEnd="4dp"
     android:focusable="true"
     android:clickable="true"
 >
 
-    <com.android.systemui.statusbar.notification.row.NotificationBackgroundView
-        android:id="@+id/backgroundNormal"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent" />
-
-    <com.android.systemui.statusbar.notification.row.NotificationBackgroundView
-        android:id="@+id/backgroundDimmed"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent" />
-
     <LinearLayout
         android:id="@+id/people_list"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
-        android:gravity="center"
+        android:layout_marginEnd="8dp"
+        android:gravity="bottom"
         android:orientation="horizontal">
 
-        <TextView
+        <FrameLayout
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:layout_weight="1"
-            android:layout_marginStart="@dimen/notification_section_header_padding_left"
-            android:gravity="start"
-            android:textAlignment="gravity"
-            android:text="@string/notification_section_header_conversations"
-            android:textSize="12sp"
-            android:textColor="@color/notification_section_header_label_color"
-            android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
-        />
+            android:gravity="start|center_vertical"
+            android:layout_weight="1">
+
+            <TextView
+                style="@style/TextAppearance.NotificationSectionHeaderButton"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/notification_section_header_conversations"
+            />
+
+        </FrameLayout>
 
         <ImageView
             android:layout_width="48dp"
@@ -84,16 +79,10 @@
         <ImageView
             android:layout_width="48dp"
             android:layout_height="48dp"
-            android:layout_marginEnd="8dp"
             android:padding="8dp"
             android:scaleType="fitCenter"
         />
 
     </LinearLayout>
 
-    <com.android.systemui.statusbar.notification.FakeShadowView
-        android:id="@+id/fake_shadow"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent" />
-
 </com.android.systemui.statusbar.notification.stack.PeopleHubView>
diff --git a/packages/SystemUI/res/layout/status_bar_notification_footer.xml b/packages/SystemUI/res/layout/status_bar_notification_footer.xml
index 174a3b8..36ba66a 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_footer.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_footer.xml
@@ -25,9 +25,9 @@
     <com.android.systemui.statusbar.AlphaOptimizedFrameLayout
         android:id="@+id/content"
         android:layout_width="match_parent"
-        android:layout_height="wrap_content" >
+        android:layout_height="wrap_content">
         <com.android.systemui.statusbar.notification.row.FooterViewButton
-            style="@android:style/Widget.Material.Button.Borderless"
+            style="@style/TextAppearance.NotificationSectionHeaderButton"
             android:id="@+id/manage_text"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
@@ -35,10 +35,9 @@
             android:focusable="true"
             android:contentDescription="@string/accessibility_manage_notification"
             android:text="@string/manage_notifications_text"
-            android:textColor="?attr/wallpaperTextColor"
-            android:textAllCaps="false"/>
+        />
         <com.android.systemui.statusbar.notification.row.FooterViewButton
-            style="@android:style/Widget.Material.Button.Borderless"
+            style="@style/TextAppearance.NotificationSectionHeaderButton"
             android:id="@+id/dismiss_text"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
@@ -46,6 +45,6 @@
             android:focusable="true"
             android:contentDescription="@string/accessibility_clear_all"
             android:text="@string/clear_all_notifications_text"
-            android:textColor="?attr/wallpaperTextColor"/>
+        />
     </com.android.systemui.statusbar.AlphaOptimizedFrameLayout>
 </com.android.systemui.statusbar.notification.row.FooterView>
diff --git a/packages/SystemUI/res/layout/status_bar_notification_section_header.xml b/packages/SystemUI/res/layout/status_bar_notification_section_header.xml
index 508619a..0043d7a 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_section_header.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_section_header.xml
@@ -19,32 +19,21 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="@dimen/notification_section_header_height"
+    android:paddingStart="4dp"
+    android:paddingEnd="4dp"
     android:focusable="true"
     android:clickable="true"
     >
 
-    <com.android.systemui.statusbar.notification.row.NotificationBackgroundView
-        android:id="@+id/backgroundNormal"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent" />
-    <com.android.systemui.statusbar.notification.row.NotificationBackgroundView
-        android:id="@+id/backgroundDimmed"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent" />
-
     <LinearLayout
         android:id="@+id/content"
         android:layout_width="match_parent"
-        android:layout_height="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_gravity="bottom"
         android:gravity="center_vertical"
         android:orientation="horizontal"
         >
         <include layout="@layout/status_bar_notification_section_header_contents"/>
     </LinearLayout>
 
-    <com.android.systemui.statusbar.notification.FakeShadowView
-        android:id="@+id/fake_shadow"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent" />
-
 </com.android.systemui.statusbar.notification.stack.SectionHeaderView>
diff --git a/packages/SystemUI/res/layout/status_bar_notification_section_header_contents.xml b/packages/SystemUI/res/layout/status_bar_notification_section_header_contents.xml
index feabd1c..df4b047 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_section_header_contents.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_section_header_contents.xml
@@ -16,26 +16,30 @@
 
 <!-- Used by both status_bar_notification_header and SectionHeaderView -->
 <merge xmlns:android="http://schemas.android.com/apk/res/android" >
-    <TextView
-        android:id="@+id/header_label"
+    <FrameLayout
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_weight="1"
-        android:layout_marginStart="@dimen/notification_section_header_padding_left"
-        android:gravity="start"
-        android:textAlignment="gravity"
-        android:text="@string/notification_section_header_gentle"
-        android:textSize="12sp"
-        android:textColor="@color/notification_section_header_label_color"
-        android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
-    />
+        android:gravity="start|center_vertical"
+        android:layout_weight="1">
+
+        <TextView
+            style="@style/TextAppearance.NotificationSectionHeaderButton"
+            android:id="@+id/header_label"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/notification_section_header_gentle"
+        />
+
+    </FrameLayout>
     <ImageView
         android:id="@+id/btn_clear_all"
-        android:layout_width="@dimen/notification_section_header_height"
-        android:layout_height="@dimen/notification_section_header_height"
-        android:layout_marginEnd="4dp"
+        android:layout_width="48dp"
+        android:layout_height="48dp"
         android:src="@drawable/status_bar_notification_section_header_clear_btn"
         android:contentDescription="@string/accessibility_notification_section_header_gentle_clear_all"
         android:scaleType="center"
+        android:tint="?attr/wallpaperTextColor"
+        android:tintMode="src_in"
+        android:visibility="gone"
     />
 </merge>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 15575a4..f9b0666 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -744,7 +744,7 @@
     <!-- The top padding of the clear all button -->
     <dimen name="clear_all_padding_top">12dp</dimen>
 
-    <dimen name="notification_section_header_height">48dp</dimen>
+    <dimen name="notification_section_header_height">56dp</dimen>
     <dimen name="notification_section_header_padding_left">16dp</dimen>
 
     <!-- Largest size an avatar might need to be drawn in the user picker, status bar, or
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 5e9feff..4aafec8 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -168,6 +168,24 @@
     <!-- Message of notification shown when trying to enable USB debugging but a secondary user is the current foreground user. -->
     <string name="usb_debugging_secondary_user_message">The user currently signed in to this device can\'t turn on USB debugging. To use this feature, switch to the primary user.</string>
 
+    <!-- Title of confirmation dialog for wireless debugging [CHAR LIMIT=NONE] -->
+    <string name="wifi_debugging_title">Allow wireless debugging on this network?</string>
+
+    <!-- Message of confirmation dialog for wireless debugging [CHAR LIMIT=NONE] -->
+    <string name="wifi_debugging_message">Network Name (SSID)\n<xliff:g id="ssid" example="My wifi">%1$s</xliff:g>\n\nWi\u2011Fi Address (BSSID)\n<xliff:g id="bssid" example="AB:CD:EF:12:34:56">%2$s</xliff:g></string>
+
+    <!-- Option to always allow wireless debugging on this network [CHAR LIMIT=NONE] -->
+    <string name="wifi_debugging_always">Always allow on this network</string>
+
+    <!-- Button label for confirming acceptance of enabling wireless debugging [CHAR LIMIT=15] -->
+    <string name="wifi_debugging_allow">Allow</string>
+
+    <!-- Title of notification shown when trying to enable wireless debugging but a secondary user is the current foreground user. [CHAR LIMIT=NONE] -->
+    <string name="wifi_debugging_secondary_user_title">Wireless debugging not allowed</string>
+
+    <!-- Message of notification shown when trying to enable wireless debugging but a secondary user is the current foreground user. [CHAR LIMIT=NONE] -->
+    <string name="wifi_debugging_secondary_user_message">The user currently signed in to this device can\u2019t turn on wireless debugging. To use this feature, switch to the primary user.</string>
+
     <!-- Title of USB contaminant presence dialog [CHAR LIMIT=NONE] -->
     <string name="usb_contaminant_title">USB port disabled</string>
 
@@ -1204,6 +1222,9 @@
     <!-- Section title for notifications that do not vibrate or make noise. [CHAR LIMIT=40] -->
     <string name="notification_section_header_gentle">Silent notifications</string>
 
+    <!-- Section title for notifications that vibrate or make noise. [CHAR LIMIT=40] -->
+    <string name="notification_section_header_alerting">Alerting notifications</string>
+
     <!-- Section title for conversational notifications. [CHAR LIMIT=40] -->
     <string name="notification_section_header_conversations">Conversations</string>
 
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 557e2d6..36c4526 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -554,6 +554,14 @@
         <item name="android:gravity">center</item>
     </style>
 
+    <style
+        name="TextAppearance.NotificationSectionHeaderButton"
+        parent="@android:style/Widget.Material.Button.Borderless">
+        <item name="android:textColor">?attr/wallpaperTextColor</item>
+        <item name="android:textAllCaps">false</item>
+        <item name="android:textSize">16sp</item>
+    </style>
+
     <style name="TextAppearance.HeadsUpStatusBarText"
            parent="@*android:style/TextAppearance.DeviceDefault.Notification.Info">
     </style>
@@ -661,5 +669,5 @@
         <item name="android:textSize">12sp</item>
         <item name="android:textColor">@color/control_secondary_text</item>
     </style>
-
+    
 </resources>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/WallpaperManagerCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/WallpaperManagerCompat.java
new file mode 100644
index 0000000..b813e21
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/WallpaperManagerCompat.java
@@ -0,0 +1,32 @@
+/*
+ * 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.systemui.shared.system;
+
+import android.app.WallpaperManager;
+import android.content.Context;
+
+public class WallpaperManagerCompat {
+    private final WallpaperManager mWallpaperManager;
+
+    public WallpaperManagerCompat(Context context) {
+        mWallpaperManager = context.getSystemService(WallpaperManager.class);
+    }
+
+    public void setWallpaperZoomOut(float zoom) {
+        mWallpaperManager.setWallpaperZoomOut(zoom);
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
index e475ef1..6f06f69 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
@@ -51,7 +51,7 @@
 public class KeyguardClockSwitch extends RelativeLayout {
 
     private static final String TAG = "KeyguardClockSwitch";
-    private static final boolean CUSTOM_CLOCKS_ENABLED = false;
+    private static final boolean CUSTOM_CLOCKS_ENABLED = true;
 
     /**
      * Animation fraction when text is transitioned to/from bold.
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
index 571c4ae..11bf24d 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
@@ -72,11 +72,12 @@
         @Override
         public void onDisplayChanged(int displayId) {
             if (displayId == DEFAULT_DISPLAY) return;
-            final Display display = mDisplayService.getDisplay(displayId);
-            if (display != null && mShowing) {
-                final Presentation presentation = mPresentations.get(displayId);
-                if (presentation != null && !presentation.getDisplay().equals(display)) {
-                    hidePresentation(displayId);
+            final Presentation presentation = mPresentations.get(displayId);
+            if (presentation != null && mShowing) {
+                hidePresentation(displayId);
+                // update DisplayInfo.
+                final Display display = mDisplayService.getDisplay(displayId);
+                if (display != null) {
                     showPresentation(display);
                 }
             }
@@ -266,6 +267,11 @@
         }
 
         @Override
+        public void cancel() {
+            // Do not allow anything to cancel KeyguardPresetation except KeyguardDisplayManager.
+        }
+
+        @Override
         public void onDetachedFromWindow() {
             mClock.removeCallbacks(mMoveTextRunnable);
         }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityView.java
index 09d4d5f..20b1e0d 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityView.java
@@ -57,6 +57,12 @@
     int PROMPT_REASON_PREPARE_FOR_UPDATE = 6;
 
     /**
+     * Primary auth is required because the user uses weak/convenience biometrics and hasn't used
+     * primary auth since a while
+     */
+    int PROMPT_REASON_NON_STRONG_BIOMETRIC_TIMEOUT = 7;
+
+    /**
      * Interface back to keyguard to tell it when security
      * @param callback
      */
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
index 61caf3b..241f96e 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
@@ -149,7 +149,7 @@
                             new WindowlessWindowManager(context.getResources().getConfiguration(),
                                     surfaceControl, input);
                     mUniversalSmartspaceViewHost = new SurfaceControlViewHost(context,
-                            context.getDisplay(), windowlessWindowManager);
+                            context.getDisplayNoVerify(), windowlessWindowManager);
                     WindowManager.LayoutParams layoutParams =
                             new WindowManager.LayoutParams(
                                     surfaceControl.getWidth(),
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 9ba3860..f57571d 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -80,6 +80,7 @@
 import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
 import android.telephony.TelephonyManager;
 import android.util.Log;
+import android.util.SparseArray;
 import android.util.SparseBooleanArray;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -91,6 +92,7 @@
 import com.android.systemui.Dumpable;
 import com.android.systemui.R;
 import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.shared.system.TaskStackChangeListener;
@@ -108,6 +110,7 @@
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.TimeZone;
+import java.util.concurrent.Executor;
 import java.util.function.Consumer;
 
 import javax.inject.Inject;
@@ -264,6 +267,7 @@
     // If the user long pressed the lock icon, disabling face auth for the current session.
     private boolean mLockIconPressed;
     private int mActiveMobileDataSubscription = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+    private final Executor mBackgroundExecutor;
 
     /**
      * Short delay before restarting biometric authentication after a successful try
@@ -320,12 +324,22 @@
                 }
             };
 
+    private class BiometricAuthenticated {
+        private final boolean mAuthenticated;
+        private final boolean mIsStrongBiometric;
+
+        BiometricAuthenticated(boolean authenticated, boolean isStrongBiometric) {
+            this.mAuthenticated = authenticated;
+            this.mIsStrongBiometric = isStrongBiometric;
+        }
+    }
+
     private SparseBooleanArray mUserIsUnlocked = new SparseBooleanArray();
     private SparseBooleanArray mUserHasTrust = new SparseBooleanArray();
     private SparseBooleanArray mUserTrustIsManaged = new SparseBooleanArray();
     private SparseBooleanArray mUserTrustIsUsuallyManaged = new SparseBooleanArray();
-    private SparseBooleanArray mUserFingerprintAuthenticated = new SparseBooleanArray();
-    private SparseBooleanArray mUserFaceAuthenticated = new SparseBooleanArray();
+    private SparseArray<BiometricAuthenticated> mUserFingerprintAuthenticated = new SparseArray<>();
+    private SparseArray<BiometricAuthenticated> mUserFaceAuthenticated = new SparseArray<>();
     private SparseBooleanArray mUserFaceUnlockRunning = new SparseBooleanArray();
     private Map<Integer, Intent> mSecondaryLockscreenRequirement = new HashMap<Integer, Intent>();
 
@@ -523,10 +537,11 @@
     }
 
     @VisibleForTesting
-    protected void onFingerprintAuthenticated(int userId) {
+    protected void onFingerprintAuthenticated(int userId, boolean isStrongBiometric) {
         Assert.isMainThread();
         Trace.beginSection("KeyGuardUpdateMonitor#onFingerPrintAuthenticated");
-        mUserFingerprintAuthenticated.put(userId, true);
+        mUserFingerprintAuthenticated.put(userId,
+                new BiometricAuthenticated(true, isStrongBiometric));
         // Update/refresh trust state only if user can skip bouncer
         if (getUserCanSkipBouncer(userId)) {
             mTrustManager.unlockedByBiometricForUser(userId, BiometricSourceType.FINGERPRINT);
@@ -536,7 +551,8 @@
         for (int i = 0; i < mCallbacks.size(); i++) {
             KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
             if (cb != null) {
-                cb.onBiometricAuthenticated(userId, BiometricSourceType.FINGERPRINT);
+                cb.onBiometricAuthenticated(userId, BiometricSourceType.FINGERPRINT,
+                        isStrongBiometric);
             }
         }
 
@@ -546,9 +562,21 @@
         // Only authenticate fingerprint once when assistant is visible
         mAssistantVisible = false;
 
+        // Report unlock with strong or non-strong biometric
+        reportSuccessfulBiometricUnlock(isStrongBiometric, userId);
+
         Trace.endSection();
     }
 
+    private void reportSuccessfulBiometricUnlock(boolean isStrongBiometric, int userId) {
+        mBackgroundExecutor.execute(new Runnable() {
+            @Override
+            public void run() {
+                mLockPatternUtils.reportSuccessfulBiometricUnlock(isStrongBiometric, userId);
+            }
+        });
+    }
+
     private void handleFingerprintAuthFailed() {
         Assert.isMainThread();
         for (int i = 0; i < mCallbacks.size(); i++) {
@@ -574,7 +602,7 @@
         }
     }
 
-    private void handleFingerprintAuthenticated(int authUserId) {
+    private void handleFingerprintAuthenticated(int authUserId, boolean isStrongBiometric) {
         Trace.beginSection("KeyGuardUpdateMonitor#handlerFingerPrintAuthenticated");
         try {
             final int userId;
@@ -592,7 +620,7 @@
                 Log.d(TAG, "Fingerprint disabled by DPM for userId: " + userId);
                 return;
             }
-            onFingerprintAuthenticated(userId);
+            onFingerprintAuthenticated(userId, isStrongBiometric);
         } finally {
             setFingerprintRunningState(BIOMETRIC_STATE_STOPPED);
         }
@@ -683,10 +711,11 @@
     }
 
     @VisibleForTesting
-    protected void onFaceAuthenticated(int userId) {
+    protected void onFaceAuthenticated(int userId, boolean isStrongBiometric) {
         Trace.beginSection("KeyGuardUpdateMonitor#onFaceAuthenticated");
         Assert.isMainThread();
-        mUserFaceAuthenticated.put(userId, true);
+        mUserFaceAuthenticated.put(userId,
+                new BiometricAuthenticated(true, isStrongBiometric));
         // Update/refresh trust state only if user can skip bouncer
         if (getUserCanSkipBouncer(userId)) {
             mTrustManager.unlockedByBiometricForUser(userId, BiometricSourceType.FACE);
@@ -697,7 +726,8 @@
             KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
             if (cb != null) {
                 cb.onBiometricAuthenticated(userId,
-                        BiometricSourceType.FACE);
+                        BiometricSourceType.FACE,
+                        isStrongBiometric);
             }
         }
 
@@ -707,6 +737,9 @@
         // Only authenticate face once when assistant is visible
         mAssistantVisible = false;
 
+        // Report unlock with strong or non-strong biometric
+        reportSuccessfulBiometricUnlock(isStrongBiometric, userId);
+
         Trace.endSection();
     }
 
@@ -737,7 +770,7 @@
         }
     }
 
-    private void handleFaceAuthenticated(int authUserId) {
+    private void handleFaceAuthenticated(int authUserId, boolean isStrongBiometric) {
         Trace.beginSection("KeyGuardUpdateMonitor#handlerFaceAuthenticated");
         try {
             if (mGoingToSleep) {
@@ -760,7 +793,7 @@
                 return;
             }
             if (DEBUG_FACE) Log.d(TAG, "Face auth succeeded for user " + userId);
-            onFaceAuthenticated(userId);
+            onFaceAuthenticated(userId, isStrongBiometric);
         } finally {
             setFaceRunningState(BIOMETRIC_STATE_STOPPED);
         }
@@ -914,9 +947,13 @@
      * Returns whether the user is unlocked with biometrics.
      */
     public boolean getUserUnlockedWithBiometric(int userId) {
-        boolean fingerprintOrFace = mUserFingerprintAuthenticated.get(userId)
-                || mUserFaceAuthenticated.get(userId);
-        return fingerprintOrFace && isUnlockingWithBiometricAllowed();
+        BiometricAuthenticated fingerprint = mUserFingerprintAuthenticated.get(userId);
+        BiometricAuthenticated face = mUserFaceAuthenticated.get(userId);
+        boolean fingerprintAllowed = fingerprint != null && fingerprint.mAuthenticated
+                && isUnlockingWithBiometricAllowed(fingerprint.mIsStrongBiometric);
+        boolean faceAllowed = face != null && face.mAuthenticated
+                && isUnlockingWithBiometricAllowed(face.mIsStrongBiometric);
+        return fingerprintAllowed || faceAllowed;
     }
 
     public boolean getUserTrustIsManaged(int userId) {
@@ -970,8 +1007,8 @@
         return mUserTrustIsUsuallyManaged.get(userId);
     }
 
-    public boolean isUnlockingWithBiometricAllowed() {
-        return mStrongAuthTracker.isUnlockingWithBiometricAllowed();
+    public boolean isUnlockingWithBiometricAllowed(boolean isStrongBiometric) {
+        return mStrongAuthTracker.isUnlockingWithBiometricAllowed(isStrongBiometric);
     }
 
     public boolean isUserInLockdown(int userId) {
@@ -1169,7 +1206,7 @@
         @Override
         public void onAuthenticationSucceeded(AuthenticationResult result) {
             Trace.beginSection("KeyguardUpdateMonitor#onAuthenticationSucceeded");
-            handleFingerprintAuthenticated(result.getUserId());
+            handleFingerprintAuthenticated(result.getUserId(), result.isStrongBiometric());
             Trace.endSection();
         }
 
@@ -1201,7 +1238,7 @@
         @Override
         public void onAuthenticationSucceeded(FaceManager.AuthenticationResult result) {
             Trace.beginSection("KeyguardUpdateMonitor#onAuthenticationSucceeded");
-            handleFaceAuthenticated(result.getUserId());
+            handleFaceAuthenticated(result.getUserId(), result.isStrongBiometric());
             Trace.endSection();
         }
 
@@ -1305,9 +1342,9 @@
             mStrongAuthRequiredChangedCallback = strongAuthRequiredChangedCallback;
         }
 
-        public boolean isUnlockingWithBiometricAllowed() {
+        public boolean isUnlockingWithBiometricAllowed(boolean isStrongBiometric) {
             int userId = getCurrentUser();
-            return isBiometricAllowedForUser(userId);
+            return isBiometricAllowedForUser(isStrongBiometric, userId);
         }
 
         public boolean hasUserAuthenticatedSinceBoot() {
@@ -1438,12 +1475,14 @@
             Context context,
             @Main Looper mainLooper,
             BroadcastDispatcher broadcastDispatcher,
-            DumpController dumpController) {
+            DumpController dumpController,
+            @Background Executor backgroundExecutor) {
         mContext = context;
         mSubscriptionManager = SubscriptionManager.from(context);
         mDeviceProvisioned = isDeviceProvisionedInSettingsDb();
         mStrongAuthTracker = new StrongAuthTracker(context, this::notifyStrongAuthStateChanged);
         dumpController.registerDumpable(this);
+        mBackgroundExecutor = backgroundExecutor;
 
         mHandler = new Handler(mainLooper) {
             @Override
@@ -1753,14 +1792,16 @@
     }
 
     private boolean shouldListenForFingerprintAssistant() {
+        BiometricAuthenticated fingerprint = mUserFingerprintAuthenticated.get(getCurrentUser());
         return mAssistantVisible && mKeyguardOccluded
-                && !mUserFingerprintAuthenticated.get(getCurrentUser(), false)
+                && !(fingerprint != null && fingerprint.mAuthenticated)
                 && !mUserHasTrust.get(getCurrentUser(), false);
     }
 
     private boolean shouldListenForFaceAssistant() {
+        BiometricAuthenticated face = mUserFaceAuthenticated.get(getCurrentUser());
         return mAssistantVisible && mKeyguardOccluded
-                && !mUserFaceAuthenticated.get(getCurrentUser(), false)
+                && !(face != null && face.mAuthenticated)
                 && !mUserHasTrust.get(getCurrentUser(), false);
     }
 
@@ -1817,7 +1858,7 @@
     public void onLockIconPressed() {
         mLockIconPressed = true;
         final int userId = getCurrentUser();
-        mUserFaceAuthenticated.put(userId, false);
+        mUserFaceAuthenticated.put(userId, null);
         updateFaceListeningState();
         mStrongAuthTracker.onStrongAuthRequiredChanged(userId);
     }
@@ -2691,9 +2732,12 @@
         if (mFpm != null && mFpm.isHardwareDetected()) {
             final int userId = ActivityManager.getCurrentUser();
             final int strongAuthFlags = mStrongAuthTracker.getStrongAuthForUser(userId);
+            BiometricAuthenticated fingerprint = mUserFingerprintAuthenticated.get(userId);
             pw.println("  Fingerprint state (user=" + userId + ")");
-            pw.println("    allowed=" + isUnlockingWithBiometricAllowed());
-            pw.println("    auth'd=" + mUserFingerprintAuthenticated.get(userId));
+            pw.println("    allowed="
+                    + (fingerprint != null
+                            && isUnlockingWithBiometricAllowed(fingerprint.mIsStrongBiometric)));
+            pw.println("    auth'd=" + (fingerprint != null && fingerprint.mAuthenticated));
             pw.println("    authSinceBoot="
                     + getStrongAuthTracker().hasUserAuthenticatedSinceBoot());
             pw.println("    disabled(DPM)=" + isFingerprintDisabled(userId));
@@ -2706,9 +2750,12 @@
         if (mFaceManager != null && mFaceManager.isHardwareDetected()) {
             final int userId = ActivityManager.getCurrentUser();
             final int strongAuthFlags = mStrongAuthTracker.getStrongAuthForUser(userId);
+            BiometricAuthenticated face = mUserFaceAuthenticated.get(userId);
             pw.println("  Face authentication state (user=" + userId + ")");
-            pw.println("    allowed=" + isUnlockingWithBiometricAllowed());
-            pw.println("    auth'd=" + mUserFaceAuthenticated.get(userId));
+            pw.println("    allowed="
+                    + (face != null && isUnlockingWithBiometricAllowed(face.mIsStrongBiometric)));
+            pw.println("    auth'd="
+                    + (face != null && face.mAuthenticated));
             pw.println("    authSinceBoot="
                     + getStrongAuthTracker().hasUserAuthenticatedSinceBoot());
             pw.println("    disabled(DPM)=" + isFaceDisabled(userId));
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
index 49f72a9..12e0ecd 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
@@ -239,7 +239,8 @@
      * @param userId the user id for which the biometric sample was authenticated
      * @param biometricSourceType
      */
-    public void onBiometricAuthenticated(int userId, BiometricSourceType biometricSourceType) { }
+    public void onBiometricAuthenticated(int userId, BiometricSourceType biometricSourceType,
+            boolean isStrongBiometric) { }
 
     /**
      * Called when biometric authentication provides help string (e.g. "Try again")
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java b/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java
index 9cd4aec..0367464 100644
--- a/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java
+++ b/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java
@@ -149,8 +149,6 @@
         LayoutInflater layoutInflater = injectionInflater.injectable(LayoutInflater.from(context));
 
         addBuiltinClock(() -> new DefaultClockController(res, layoutInflater, colorExtractor));
-        addBuiltinClock(() -> new BubbleClockController(res, layoutInflater, colorExtractor));
-        addBuiltinClock(() -> new AnalogClockController(res, layoutInflater, colorExtractor));
 
         // Store the size of the display for generation of clock preview.
         DisplayMetrics dm = res.getDisplayMetrics();
@@ -211,7 +209,8 @@
         return mContentObserver;
     }
 
-    private void addBuiltinClock(Supplier<ClockPlugin> pluginSupplier) {
+    @VisibleForTesting
+    void addBuiltinClock(Supplier<ClockPlugin> pluginSupplier) {
         ClockPlugin plugin = pluginSupplier.get();
         mPreviewClocks.addClockPlugin(plugin);
         mBuiltinClocks.add(pluginSupplier);
diff --git a/packages/SystemUI/src/com/android/systemui/CornerHandleView.java b/packages/SystemUI/src/com/android/systemui/CornerHandleView.java
index 8503396..85ce313 100644
--- a/packages/SystemUI/src/com/android/systemui/CornerHandleView.java
+++ b/packages/SystemUI/src/com/android/systemui/CornerHandleView.java
@@ -57,7 +57,6 @@
         mPaint.setStyle(Paint.Style.STROKE);
         mPaint.setStrokeCap(Paint.Cap.ROUND);
         mPaint.setStrokeWidth(getStrokePx());
-        setLayerType(View.LAYER_TYPE_SOFTWARE, mPaint);
 
         final int dualToneDarkTheme = Utils.getThemeAttr(mContext, R.attr.darkIconTheme);
         final int dualToneLightTheme = Utils.getThemeAttr(mContext, R.attr.lightIconTheme);
@@ -118,14 +117,8 @@
         // Handle color is same as home handle color.
         int color = (int) ArgbEvaluator.getInstance().evaluate(darkIntensity,
                 mLightColor, mDarkColor);
-        // Shadow color is inverse of handle color.
-        int shadowColor = (int) ArgbEvaluator.getInstance().evaluate(darkIntensity,
-                mDarkColor, mLightColor);
         if (mPaint.getColor() != color) {
             mPaint.setColor(color);
-            mPaint.setShadowLayer(/** radius */ getResources().getDimensionPixelSize(
-                    com.android.internal.R.dimen.assist_handle_shadow_radius), /** shadowDx */ 0,
-                    /** shadowDy */ 0, /** color */ shadowColor);
             if (getVisibility() == VISIBLE && getAlpha() > 0) {
                 invalidate();
             } else {
diff --git a/packages/SystemUI/src/com/android/systemui/LatencyTester.java b/packages/SystemUI/src/com/android/systemui/LatencyTester.java
index 1a47dac..dc0cb03 100644
--- a/packages/SystemUI/src/com/android/systemui/LatencyTester.java
+++ b/packages/SystemUI/src/com/android/systemui/LatencyTester.java
@@ -96,6 +96,7 @@
     private void fakeWakeAndUnlock() {
         mBiometricUnlockController.onBiometricAcquired(BiometricSourceType.FINGERPRINT);
         mBiometricUnlockController.onBiometricAuthenticated(
-                KeyguardUpdateMonitor.getCurrentUser(), BiometricSourceType.FINGERPRINT);
+                KeyguardUpdateMonitor.getCurrentUser(), BiometricSourceType.FINGERPRINT,
+                true /* isStrongBiometric */);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
index c9104dc..6ce6353 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
@@ -96,6 +96,7 @@
     private static final boolean DEBUG_SCREENSHOT_ROUNDED_CORNERS =
             SystemProperties.getBoolean("debug.screenshot_rounded_corners", false);
     private static final boolean VERBOSE = false;
+    private static final boolean DEBUG_COLOR = DEBUG_SCREENSHOT_ROUNDED_CORNERS;
 
     private DisplayManager mDisplayManager;
     private boolean mIsRegistered;
@@ -454,6 +455,9 @@
 
     private void updateColorInversion(int colorsInvertedValue) {
         int tint = colorsInvertedValue != 0 ? Color.WHITE : Color.BLACK;
+        if (DEBUG_COLOR) {
+            tint = Color.RED;
+        }
         ColorStateList tintList = ColorStateList.valueOf(tint);
 
         if (mOverlays == null) {
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerImpl.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerImpl.java
index 6a64c83..f719cc6 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerImpl.java
@@ -130,7 +130,8 @@
             new KeyguardUpdateMonitorCallback() {
                 @Override
                 public void onBiometricAuthenticated(int userId,
-                        BiometricSourceType biometricSourceType) {
+                        BiometricSourceType biometricSourceType,
+                        boolean isStrongBiometric) {
                     if (userId == KeyguardUpdateMonitor.getCurrentUser()
                             && biometricSourceType == BiometricSourceType.FACE) {
                         mJustUnlockedWithFace = true;
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java b/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java
index 2f3e336..a084ae6 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java
@@ -78,7 +78,8 @@
             new KeyguardUpdateMonitorCallback() {
                 @Override
                 public void onBiometricAuthenticated(int userId,
-                        BiometricSourceType biometricSourceType) {
+                        BiometricSourceType biometricSourceType,
+                        boolean isStrongBiometric) {
                     if (userId == KeyguardUpdateMonitor.getCurrentUser()
                             && biometricSourceType == BiometricSourceType.FACE) {
                         mJustUnlockedWithFace = true;
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 374153c..2e6c955 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -22,6 +22,7 @@
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST;
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW;
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT;
+import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_NON_STRONG_BIOMETRICS_TIMEOUT;
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_TIMEOUT;
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_FOR_UNATTENDED_UPDATE;
 import static com.android.systemui.DejankUtils.whitelistIpcs;
@@ -538,7 +539,8 @@
         }
 
         @Override
-        public void onBiometricAuthenticated(int userId, BiometricSourceType biometricSourceType) {
+        public void onBiometricAuthenticated(int userId, BiometricSourceType biometricSourceType,
+                boolean isStrongBiometric) {
             if (mLockPatternUtils.isSecure(userId)) {
                 mLockPatternUtils.getDevicePolicyManager().reportSuccessfulBiometricAttempt(
                         userId);
@@ -675,6 +677,9 @@
                 return KeyguardSecurityView.PROMPT_REASON_AFTER_LOCKOUT;
             } else if (any && (strongAuth & STRONG_AUTH_REQUIRED_FOR_UNATTENDED_UPDATE) != 0) {
                 return KeyguardSecurityView.PROMPT_REASON_PREPARE_FOR_UPDATE;
+            } else if (any && (strongAuth
+                    & STRONG_AUTH_REQUIRED_AFTER_NON_STRONG_BIOMETRICS_TIMEOUT) != 0) {
+                return KeyguardSecurityView.PROMPT_REASON_NON_STRONG_BIOMETRIC_TIMEOUT;
             }
             return KeyguardSecurityView.PROMPT_REASON_NONE;
         }
@@ -1842,6 +1847,13 @@
             mShowKeyguardWakeLock.release();
         }
         mKeyguardDisplayManager.show();
+
+        // schedule 4hr idle timeout after which non-strong biometrics (i.e. weak or convenience
+        // biometric) can't be used to unlock device until unlocking with strong biometric or
+        // primary auth (i.e. PIN/pattern/password)
+        mLockPatternUtils.scheduleNonStrongBiometricIdleTimeout(
+                KeyguardUpdateMonitor.getCurrentUser());
+
         Trace.endSection();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSMediaPlayer.java b/packages/SystemUI/src/com/android/systemui/qs/QSMediaPlayer.java
index 6c69718..011893d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSMediaPlayer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSMediaPlayer.java
@@ -244,7 +244,10 @@
         ActivityStarter mActivityStarter = Dependency.get(ActivityStarter.class);
         mSeamless.setOnClickListener(v -> {
             final Intent intent = new Intent()
-                    .setAction(MediaOutputSliceConstants.ACTION_MEDIA_OUTPUT);
+                    .setAction(MediaOutputSliceConstants.ACTION_MEDIA_OUTPUT)
+                    .putExtra(MediaOutputSliceConstants.EXTRA_PACKAGE_NAME,
+                        mController.getPackageName())
+                    .putExtra(MediaOutputSliceConstants.KEY_MEDIA_SESSION_TOKEN, token);
             mActivityStarter.startActivity(intent, false, true /* dismissShade */,
                     Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
         });
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java
index 84891ec..6663237 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java
@@ -108,7 +108,7 @@
         Log.d(TAG, "Starting countdown");
         // Close QS, otherwise the permission dialog appears beneath it
         getHost().collapsePanels();
-        mController.launchRecordPrompt(this);
+        mController.launchRecordPrompt();
     }
 
     private void cancelCountdown() {
@@ -129,6 +129,11 @@
         }
 
         @Override
+        public void onCountdownEnd() {
+            refreshState();
+        }
+
+        @Override
         public void onRecordingStart() {
             refreshState();
         }
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java
index 6ad9c40..8dad08e 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java
@@ -23,7 +23,6 @@
 import android.os.CountDownTimer;
 import android.util.Log;
 
-import com.android.systemui.qs.tiles.ScreenRecordTile;
 import com.android.systemui.statusbar.policy.CallbackController;
 
 import java.util.ArrayList;
@@ -62,7 +61,7 @@
     /**
      * Show dialog of screen recording options to user.
      */
-    public void launchRecordPrompt(ScreenRecordTile tileToUpdate) {
+    public void launchRecordPrompt() {
         final ComponentName launcherComponent = new ComponentName(SYSUI_PACKAGE,
                 SYSUI_SCREENRECORD_LAUNCHER);
         final Intent intent = new Intent();
@@ -73,15 +72,17 @@
 
     /**
      * Start counting down in preparation to start a recording
-     * @param ms Time in ms to count down
+     * @param ms Total time in ms to wait before starting
+     * @param interval Time in ms per countdown step
      * @param startIntent Intent to start a recording
      * @param stopIntent Intent to stop a recording
      */
-    public void startCountdown(long ms, PendingIntent startIntent, PendingIntent stopIntent) {
+    public void startCountdown(long ms, long interval, PendingIntent startIntent,
+            PendingIntent stopIntent) {
         mIsStarting = true;
         mStopIntent = stopIntent;
 
-        mCountDownTimer = new CountDownTimer(ms, 1000) {
+        mCountDownTimer = new CountDownTimer(ms, interval) {
             @Override
             public void onTick(long millisUntilFinished) {
                 for (RecordingStateChangeCallback cb : mListeners) {
@@ -94,7 +95,7 @@
                 mIsStarting = false;
                 mIsRecording = true;
                 for (RecordingStateChangeCallback cb : mListeners) {
-                    cb.onRecordingEnd();
+                    cb.onCountdownEnd();
                 }
                 try {
                     startIntent.send();
@@ -120,7 +121,7 @@
         mIsStarting = false;
 
         for (RecordingStateChangeCallback cb : mListeners) {
-            cb.onRecordingEnd();
+            cb.onCountdownEnd();
         }
     }
 
@@ -144,16 +145,12 @@
      * Stop the recording
      */
     public void stopRecording() {
-        updateState(false);
         try {
             mStopIntent.send();
+            updateState(false);
         } catch (PendingIntent.CanceledException e) {
             Log.e(TAG, "Error stopping: " + e.getMessage());
         }
-
-        for (RecordingStateChangeCallback cb : mListeners) {
-            cb.onRecordingEnd();
-        }
     }
 
     /**
@@ -193,6 +190,12 @@
         default void onCountdown(long millisUntilFinished) {}
 
         /**
+         * Called when a countdown to recording has ended. This is a separate method so that if
+         * needed, listeners can handle cases where recording fails to start
+         */
+        default void onCountdownEnd() {}
+
+        /**
          * Called when a screen recording has started
          */
         default void onRecordingStart() {}
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java
index 566f12b..26973d0 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java
@@ -34,6 +34,7 @@
  */
 public class ScreenRecordDialog extends Activity {
     private static final long DELAY_MS = 3000;
+    private static final long INTERVAL_MS = 1000;
 
     private final RecordingController mController;
     private Switch mAudioSwitch;
@@ -83,6 +84,6 @@
                 RecordingService.REQUEST_CODE,
                 RecordingService.getStopIntent(this),
                 PendingIntent.FLAG_UPDATE_CURRENT);
-        mController.startCountdown(DELAY_MS, startIntent, stopIntent);
+        mController.startCountdown(DELAY_MS, INTERVAL_MS, startIntent, stopIntent);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
index 9e1e347..f06cd54 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
@@ -497,9 +497,9 @@
         flashOutAnimator.addUpdateListener(animation ->
                 mScreenshotFlash.setAlpha((float) animation.getAnimatedValue()));
 
-        final PointF startPos = new PointF((float) bounds.left, (float) bounds.top);
-        final PointF finalPos = new PointF(mScreenshotOffsetXPx,
-                mDisplayMetrics.heightPixels - mScreenshotOffsetYPx - height * cornerScale);
+        final PointF startPos = new PointF(bounds.centerX(), bounds.centerY());
+        final PointF finalPos = new PointF(mScreenshotOffsetXPx + width * cornerScale / 2f,
+                mDisplayMetrics.heightPixels - mScreenshotOffsetYPx - height * cornerScale / 2f);
 
         ValueAnimator toCorner = ValueAnimator.ofFloat(0, 1);
         toCorner.setDuration(SCREENSHOT_TO_CORNER_Y_DURATION_MS);
@@ -517,11 +517,13 @@
             }
 
             if (t < xPositionPct) {
-                mScreenshotView.setX(MathUtils.lerp(
-                        startPos.x, finalPos.x, mFastOutSlowIn.getInterpolation(t / xPositionPct)));
+                float xCenter = MathUtils.lerp(startPos.x, finalPos.x,
+                        mFastOutSlowIn.getInterpolation(t / xPositionPct));
+                mScreenshotView.setX(xCenter - width * mScreenshotView.getScaleX() / 2f);
             }
-            mScreenshotView.setY(MathUtils.lerp(
-                    startPos.y, finalPos.y, mFastOutSlowIn.getInterpolation(t)));
+            float yCenter = MathUtils.lerp(startPos.y, finalPos.y,
+                    mFastOutSlowIn.getInterpolation(t));
+            mScreenshotView.setY(yCenter - height * mScreenshotView.getScaleY() / 2f);
         });
 
         toCorner.addListener(new AnimatorListenerAdapter() {
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java b/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java
index 7de70f5..2571521 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java
@@ -281,7 +281,8 @@
                         .putExtra(GlobalScreenshot.EXTRA_ID, mScreenshotId)
                         .putExtra(GlobalScreenshot.EXTRA_SMART_ACTIONS_ENABLED,
                                 mSmartActionsEnabled)
-                        .setAction(Intent.ACTION_SEND),
+                        .setAction(Intent.ACTION_SEND)
+                        .addFlags(Intent.FLAG_RECEIVER_FOREGROUND),
                 PendingIntent.FLAG_CANCEL_CURRENT, UserHandle.SYSTEM);
 
         Notification.Action.Builder shareActionBuilder = new Notification.Action.Builder(
@@ -310,7 +311,8 @@
                         .putExtra(GlobalScreenshot.EXTRA_ID, mScreenshotId)
                         .putExtra(GlobalScreenshot.EXTRA_SMART_ACTIONS_ENABLED,
                                 mSmartActionsEnabled)
-                        .setAction(Intent.ACTION_EDIT),
+                        .setAction(Intent.ACTION_EDIT)
+                        .addFlags(Intent.FLAG_RECEIVER_FOREGROUND),
                 PendingIntent.FLAG_CANCEL_CURRENT, UserHandle.SYSTEM);
         Notification.Action.Builder editActionBuilder = new Notification.Action.Builder(
                 Icon.createWithResource(r, R.drawable.ic_screenshot_edit),
@@ -324,7 +326,8 @@
                             .putExtra(GlobalScreenshot.SCREENSHOT_URI_ID, uri.toString())
                             .putExtra(GlobalScreenshot.EXTRA_ID, mScreenshotId)
                             .putExtra(GlobalScreenshot.EXTRA_SMART_ACTIONS_ENABLED,
-                                    mSmartActionsEnabled),
+                                    mSmartActionsEnabled)
+                            .addFlags(Intent.FLAG_RECEIVER_FOREGROUND),
                     PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT);
             Notification.Action.Builder deleteActionBuilder = new Notification.Action.Builder(
                     Icon.createWithResource(r, R.drawable.ic_screenshot_delete),
@@ -361,9 +364,9 @@
             String actionType = extras.getString(
                     ScreenshotNotificationSmartActionsProvider.ACTION_TYPE,
                     ScreenshotNotificationSmartActionsProvider.DEFAULT_ACTION_TYPE);
-            Intent intent = new Intent(context,
-                    GlobalScreenshot.SmartActionsReceiver.class).putExtra(
-                    GlobalScreenshot.EXTRA_ACTION_INTENT, action.actionIntent);
+            Intent intent = new Intent(context, GlobalScreenshot.SmartActionsReceiver.class)
+                    .putExtra(GlobalScreenshot.EXTRA_ACTION_INTENT, action.actionIntent)
+                    .addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
             addIntentExtras(mScreenshotId, intent, actionType, mSmartActionsEnabled);
             PendingIntent broadcastIntent = PendingIntent.getBroadcast(context,
                     mRandom.nextInt(),
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
index 2daefbd..56cdff4 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
@@ -137,7 +137,8 @@
                         try {
                             mLastImeTarget = ActivityTaskManager.getTaskOrganizerController()
                                     .getImeTarget(displayId);
-                            mShouldAdjustForIme = !mSplitLayout.mDisplayLayout.isLandscape()
+                            mShouldAdjustForIme = mLastImeTarget != null
+                                    && !mSplitLayout.mDisplayLayout.isLandscape()
                                     && (mLastImeTarget.asBinder()
                                     == mSplits.mSecondary.token.asBinder());
                         } catch (RemoteException e) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BlurUtils.kt b/packages/SystemUI/src/com/android/systemui/statusbar/BlurUtils.kt
index ab69d47..4bb8621 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BlurUtils.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BlurUtils.kt
@@ -90,7 +90,7 @@
     }
 
     override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>) {
-        IndentingPrintWriter(pw, "  ").use {
+        IndentingPrintWriter(pw, "  ").let {
             it.println("BlurUtils:")
             it.increaseIndent()
             it.println("minBlurRadius: $minBlurRadius")
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 7d3d406..4f8e6cf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -645,7 +645,13 @@
         @Override
         public void onBiometricHelp(int msgId, String helpString,
                 BiometricSourceType biometricSourceType) {
-            if (!mKeyguardUpdateMonitor.isUnlockingWithBiometricAllowed()) {
+            // TODO(b/141025588): refactor to reduce repetition of code/comments
+            // Only checking if unlocking with Biometric is allowed (no matter strong or non-strong
+            // as long as primary auth, i.e. PIN/pattern/password, is not required), so it's ok to
+            // pass true for isStrongBiometric to isUnlockingWithBiometricAllowed() to bypass the
+            // check of whether non-strong biometric is allowed
+            if (!mKeyguardUpdateMonitor
+                    .isUnlockingWithBiometricAllowed(true /* isStrongBiometric */)) {
                 return;
             }
             boolean showSwipeToUnlock =
@@ -705,13 +711,21 @@
 
         private boolean shouldSuppressFingerprintError(int msgId,
                 KeyguardUpdateMonitor updateMonitor) {
-            return ((!updateMonitor.isUnlockingWithBiometricAllowed()
+            // Only checking if unlocking with Biometric is allowed (no matter strong or non-strong
+            // as long as primary auth, i.e. PIN/pattern/password, is not required), so it's ok to
+            // pass true for isStrongBiometric to isUnlockingWithBiometricAllowed() to bypass the
+            // check of whether non-strong biometric is allowed
+            return ((!updateMonitor.isUnlockingWithBiometricAllowed(true /* isStrongBiometric */)
                     && msgId != FingerprintManager.FINGERPRINT_ERROR_LOCKOUT_PERMANENT)
                     || msgId == FingerprintManager.FINGERPRINT_ERROR_CANCELED);
         }
 
         private boolean shouldSuppressFaceError(int msgId, KeyguardUpdateMonitor updateMonitor) {
-            return ((!updateMonitor.isUnlockingWithBiometricAllowed()
+            // Only checking if unlocking with Biometric is allowed (no matter strong or non-strong
+            // as long as primary auth, i.e. PIN/pattern/password, is not required), so it's ok to
+            // pass true for isStrongBiometric to isUnlockingWithBiometricAllowed() to bypass the
+            // check of whether non-strong biometric is allowed
+            return ((!updateMonitor.isUnlockingWithBiometricAllowed(true /* isStrongBiometric */)
                     && msgId != FaceManager.FACE_ERROR_LOCKOUT_PERMANENT)
                     || msgId == FaceManager.FACE_ERROR_CANCELED);
         }
@@ -745,8 +759,9 @@
         }
 
         @Override
-        public void onBiometricAuthenticated(int userId, BiometricSourceType biometricSourceType) {
-            super.onBiometricAuthenticated(userId, biometricSourceType);
+        public void onBiometricAuthenticated(int userId, BiometricSourceType biometricSourceType,
+                boolean isStrongBiometric) {
+            super.onBiometricAuthenticated(userId, biometricSourceType, isStrongBiometric);
             mHandler.sendEmptyMessage(MSG_HIDE_TRANSIENT);
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
index 9c626f7..12add8c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
@@ -159,6 +159,7 @@
     private boolean mDismissed;
     private Runnable mOnDismissListener;
     private boolean mIncreasedSize;
+    private boolean mTintIcons = true;
 
     public StatusBarIconView(Context context, String slot, StatusBarNotification sbn) {
         this(context, slot, sbn, false);
@@ -612,6 +613,11 @@
     }
 
     private void updateIconColor() {
+        if (!mTintIcons) {
+            setColorFilter(null);
+            return;
+        }
+
         if (mCurrentSetColor != NO_COLOR) {
             if (mMatrixColorFilter == null) {
                 mMatrix = new float[4 * 5];
@@ -953,6 +959,19 @@
         maybeUpdateIconScaleDimens();
     }
 
+    /**
+     * Sets whether the icon should be tinted. If the state differs from the supplied setting, this
+     * will update the icon colors.
+     *
+     * @param shouldTint Whether the icon should be tinted.
+     */
+    public void setTintIcons(boolean shouldTint) {
+        if (mTintIcons != shouldTint) {
+            mTintIcons = shouldTint;
+            updateIconColor();
+        }
+    }
+
     public interface OnVisibilityChangedListener {
         void onVisibilityChanged(int newVisibility);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManager.kt
index 0095511..48386dc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManager.kt
@@ -22,6 +22,7 @@
 import com.android.internal.annotations.VisibleForTesting
 import com.android.internal.config.sysui.SystemUiDeviceConfigFlags.NOTIFICATIONS_USE_PEOPLE_FILTERING
 import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_ALERTING
+import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_HEADS_UP
 import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_PEOPLE
 import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_SILENT
 import com.android.systemui.util.DeviceConfigProxy
@@ -45,7 +46,7 @@
     fun getNotificationBuckets(): IntArray {
         return when {
             isFilteringEnabled() ->
-                intArrayOf(BUCKET_PEOPLE, BUCKET_ALERTING, BUCKET_SILENT)
+                intArrayOf(BUCKET_HEADS_UP, BUCKET_PEOPLE, BUCKET_ALERTING, BUCKET_SILENT)
             NotificationUtils.useNewInterruptionModel(context) ->
                 intArrayOf(BUCKET_ALERTING, BUCKET_SILENT)
             else ->
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
index f482d37..25a832d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
@@ -29,6 +29,8 @@
 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST;
 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK;
 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR;
+import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_DYNAMIC;
+import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_PINNED;
 
 import static com.android.systemui.statusbar.notification.collection.NotifCollection.REASON_NOT_CANCELED;
 import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_ALERTING;
@@ -42,6 +44,9 @@
 import android.app.Person;
 import android.app.RemoteInputHistoryItem;
 import android.content.Context;
+import android.content.pm.LauncherApps;
+import android.content.pm.LauncherApps.ShortcutQuery;
+import android.content.pm.ShortcutInfo;
 import android.graphics.drawable.Icon;
 import android.net.Uri;
 import android.os.Bundle;
@@ -50,6 +55,7 @@
 import android.service.notification.SnoozeCriterion;
 import android.service.notification.StatusBarNotification;
 import android.util.ArraySet;
+import android.util.Log;
 import android.view.View;
 import android.widget.ImageView;
 
@@ -75,6 +81,8 @@
 import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager;
 
 import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
 import java.util.Objects;
 
@@ -94,11 +102,15 @@
  * clean this up in the future.
  */
 public final class NotificationEntry extends ListEntry {
+    private static final String TAG = "NotificationEntry";
 
     private final String mKey;
     private StatusBarNotification mSbn;
     private Ranking mRanking;
 
+    private StatusBarIcon mSmallIcon;
+    private StatusBarIcon mPeopleAvatar;
+
     /*
      * Bookkeeping members
      */
@@ -459,12 +471,7 @@
      */
     public void createIcons(Context context, StatusBarNotification sbn)
             throws InflationException {
-        Notification n = sbn.getNotification();
-        final Icon smallIcon = n.getSmallIcon();
-        if (smallIcon == null) {
-            throw new InflationException("No small icon in notification from "
-                    + sbn.getPackageName());
-        }
+        StatusBarIcon ic = getIcon(context, sbn, false /* redact */);
 
         // Construct the icon.
         icon = new StatusBarIconView(context,
@@ -482,21 +489,20 @@
         aodIcon.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
         aodIcon.setIncreasedSize(true);
 
-        final StatusBarIcon ic = new StatusBarIcon(
-                sbn.getUser(),
-                sbn.getPackageName(),
-                smallIcon,
-                n.iconLevel,
-                n.number,
-                StatusBarIconView.contentDescForNotification(context, n));
-
-        if (!icon.set(ic) || !expandedIcon.set(ic) || !aodIcon.set(ic)) {
+        try {
+            setIcons(ic, Collections.singletonList(icon));
+            if (isSensitive()) {
+                ic = getIcon(context, sbn, true /* redact */);
+            }
+            setIcons(ic, Arrays.asList(expandedIcon, aodIcon));
+        } catch (InflationException e) {
             icon = null;
             expandedIcon = null;
             centeredIcon = null;
             aodIcon = null;
-            throw new InflationException("Couldn't create icon: " + ic);
+            throw e;
         }
+
         expandedIcon.setVisibility(View.INVISIBLE);
         expandedIcon.setOnVisibilityChangedListener(
                 newVisibility -> {
@@ -510,10 +516,130 @@
             centeredIcon = new StatusBarIconView(context,
                     sbn.getPackageName() + "/0x" + Integer.toHexString(sbn.getId()), sbn);
             centeredIcon.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
-
-            if (!centeredIcon.set(ic)) {
+            try {
+                setIcons(ic, Collections.singletonList(centeredIcon));
+            } catch (InflationException e) {
                 centeredIcon = null;
-                throw new InflationException("Couldn't update centered icon: " + ic);
+                throw e;
+            }
+        }
+    }
+
+    /**
+     * Determines if this icon should be tinted based on the sensitivity of the icon, its context
+     * and the user's indicated sensitivity preference.
+     *
+     * @param ic The icon that should/should not be tinted.
+     * @return
+     */
+    private boolean shouldTintIcon(StatusBarIconView ic) {
+        boolean usedInSensitiveContext = (ic == expandedIcon || ic == aodIcon);
+        return !isImportantConversation() || (usedInSensitiveContext && isSensitive());
+    }
+
+
+    private void setIcons(StatusBarIcon ic, List<StatusBarIconView> icons)
+            throws InflationException {
+        for (StatusBarIconView icon: icons) {
+            if (icon == null) {
+              continue;
+            }
+            icon.setTintIcons(shouldTintIcon(icon));
+            if (!icon.set(ic)) {
+                throw new InflationException("Couldn't create icon" + ic);
+            }
+        }
+    }
+
+    private StatusBarIcon getIcon(Context context, StatusBarNotification sbn, boolean redact)
+            throws InflationException {
+        Notification n = sbn.getNotification();
+        final boolean showPeopleAvatar = isImportantConversation() && !redact;
+
+        // If cached, return corresponding cached values
+        if (showPeopleAvatar && mPeopleAvatar != null) {
+            return mPeopleAvatar;
+        } else if (!showPeopleAvatar && mSmallIcon != null) {
+            return mSmallIcon;
+        }
+
+        Icon icon = showPeopleAvatar ? createPeopleAvatar(context) : n.getSmallIcon();
+        if (icon == null) {
+            throw new InflationException("No icon in notification from " + sbn.getPackageName());
+        }
+
+        StatusBarIcon ic = new StatusBarIcon(
+                    sbn.getUser(),
+                    sbn.getPackageName(),
+                    icon,
+                    n.iconLevel,
+                    n.number,
+                    StatusBarIconView.contentDescForNotification(context, n));
+
+        // Cache if important conversation.
+        if (isImportantConversation()) {
+            if (showPeopleAvatar) {
+                mPeopleAvatar = ic;
+            } else {
+                mSmallIcon = ic;
+            }
+        }
+        return ic;
+    }
+
+    private Icon createPeopleAvatar(Context context) throws InflationException {
+        // Attempt to extract form shortcut.
+        String conversationId = getChannel().getConversationId();
+        ShortcutQuery query = new ShortcutQuery()
+                .setPackage(mSbn.getPackageName())
+                .setQueryFlags(FLAG_MATCH_DYNAMIC | FLAG_MATCH_PINNED)
+                .setShortcutIds(Collections.singletonList(conversationId));
+        List<ShortcutInfo> shortcuts = context.getSystemService(LauncherApps.class)
+                .getShortcuts(query, mSbn.getUser());
+        Icon ic = null;
+        if (shortcuts != null && !shortcuts.isEmpty()) {
+            ic = shortcuts.get(0).getIcon();
+        }
+
+        // Fall back to notification large icon if available
+        if (ic == null) {
+            ic = mSbn.getNotification().getLargeIcon();
+        }
+
+        // Fall back to extract from message
+        if (ic == null) {
+            Bundle extras = mSbn.getNotification().extras;
+            List<Message> messages = Message.getMessagesFromBundleArray(
+                    extras.getParcelableArray(Notification.EXTRA_MESSAGES));
+            Person user = extras.getParcelable(Notification.EXTRA_MESSAGING_PERSON);
+
+            for (int i = messages.size() - 1; i >= 0; i--) {
+                Message message = messages.get(i);
+                Person sender = message.getSenderPerson();
+                if (sender != null && sender != user) {
+                    ic = message.getSenderPerson().getIcon();
+                    break;
+                }
+            }
+        }
+
+        // Revert to small icon if still not available
+        if (ic == null) {
+            ic = mSbn.getNotification().getSmallIcon();
+        }
+        if (ic == null) {
+            throw new InflationException("No icon in notification from " + mSbn.getPackageName());
+        }
+        return ic;
+    }
+
+    private void updateSensitiveIconState() {
+        try {
+            StatusBarIcon ic = getIcon(getRow().getContext(), mSbn, isSensitive());
+            setIcons(ic, Arrays.asList(expandedIcon, aodIcon));
+        } catch (InflationException e) {
+            if (Log.isLoggable(TAG, Log.DEBUG)) {
+                Log.d(TAG, "Unable to update icon", e);
             }
         }
     }
@@ -544,30 +670,32 @@
             throws InflationException {
         if (icon != null) {
             // Update the icon
-            Notification n = sbn.getNotification();
-            final StatusBarIcon ic = new StatusBarIcon(
-                    mSbn.getUser(),
-                    mSbn.getPackageName(),
-                    n.getSmallIcon(),
-                    n.iconLevel,
-                    n.number,
-                    StatusBarIconView.contentDescForNotification(context, n));
+            mSmallIcon = null;
+            mPeopleAvatar = null;
+
+            StatusBarIcon ic = getIcon(context, sbn, false /* redact */);
+
             icon.setNotification(sbn);
             expandedIcon.setNotification(sbn);
             aodIcon.setNotification(sbn);
-            if (!icon.set(ic) || !expandedIcon.set(ic) || !aodIcon.set(ic)) {
-                throw new InflationException("Couldn't update icon: " + ic);
+            setIcons(ic, Arrays.asList(icon, expandedIcon));
+
+            if (isSensitive()) {
+                ic = getIcon(context, sbn, true /* redact */);
             }
+            setIcons(ic, Collections.singletonList(aodIcon));
 
             if (centeredIcon != null) {
                 centeredIcon.setNotification(sbn);
-                if (!centeredIcon.set(ic)) {
-                    throw new InflationException("Couldn't update centered icon: " + ic);
-                }
+                setIcons(ic, Collections.singletonList(centeredIcon));
             }
         }
     }
 
+    private boolean isImportantConversation() {
+        return getChannel() != null && getChannel().isImportantConversation();
+    }
+
     public int getContrastedColor(Context context, boolean isLowPriority,
             int backgroundColor) {
         int rawColor = isLowPriority ? Notification.COLOR_DEFAULT :
@@ -996,6 +1124,7 @@
         getRow().setSensitive(sensitive, deviceSensitive);
         if (sensitive != mSensitive) {
             mSensitive = sensitive;
+            updateSensitiveIconState();
             if (mOnSensitiveChangedListener != null) {
                 mOnSensitiveChangedListener.run();
             }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt
index e612c07..9c942a5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt
@@ -28,6 +28,7 @@
 import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider
 import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier
 import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_ALERTING
+import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_HEADS_UP
 import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_PEOPLE
 import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_SILENT
 import com.android.systemui.statusbar.phone.NotificationGroupManager
@@ -90,12 +91,12 @@
         val bIsHighPriority = b.isHighPriority()
 
         when {
-            usePeopleFiltering && aIsPeople != bIsPeople -> if (aIsPeople) -1 else 1
-            usePeopleFiltering && aIsImportantPeople != bIsImportantPeople ->
-                if (aIsImportantPeople) -1 else 1
             aHeadsUp != bHeadsUp -> if (aHeadsUp) -1 else 1
             // Provide consistent ranking with headsUpManager
             aHeadsUp -> headsUpManager.compare(a, b)
+            usePeopleFiltering && aIsPeople != bIsPeople -> if (aIsPeople) -1 else 1
+            usePeopleFiltering && aIsImportantPeople != bIsImportantPeople ->
+                if (aIsImportantPeople) -1 else 1
             // Upsort current media notification.
             aMedia != bMedia -> if (aMedia) -1 else 1
             // Upsort PRIORITY_MAX system notifications
@@ -162,7 +163,9 @@
         isMedia: Boolean,
         isSystemMax: Boolean
     ) {
-        if (usePeopleFiltering && entry.isPeopleNotification()) {
+        if (usePeopleFiltering && isHeadsUp) {
+            entry.bucket = BUCKET_HEADS_UP
+        } else if (usePeopleFiltering && entry.isPeopleNotification()) {
             entry.bucket = BUCKET_PEOPLE
         } else if (isHeadsUp || isMedia || isSystemMax || entry.isHighPriority()) {
             entry.bucket = BUCKET_ALERTING
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubModule.kt
index efcef71..16574ab 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubModule.kt
@@ -24,8 +24,8 @@
 
     @Binds
     abstract fun peopleHubSectionFooterViewAdapter(
-        impl: PeopleHubSectionFooterViewAdapterImpl
-    ): PeopleHubSectionFooterViewAdapter
+        impl: PeopleHubViewAdapterImpl
+    ): PeopleHubViewAdapter
 
     @Binds
     abstract fun peopleHubDataSource(impl: PeopleHubDataSourceImpl): DataSource<PeopleHubModel>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubViewController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubViewController.kt
index ec1d6de..e28d03f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubViewController.kt
@@ -25,17 +25,16 @@
 import android.view.View
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.plugins.ActivityStarter
-import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager
 import javax.inject.Inject
 import javax.inject.Singleton
 
 /** Boundary between the View and PeopleHub, as seen by the View. */
-interface PeopleHubSectionFooterViewAdapter {
-    fun bindView(viewBoundary: PeopleHubSectionFooterViewBoundary)
+interface PeopleHubViewAdapter {
+    fun bindView(viewBoundary: PeopleHubViewBoundary): Subscription
 }
 
-/** Abstract `View` representation of PeopleHub footer in [NotificationSectionsManager]. */
-interface PeopleHubSectionFooterViewBoundary {
+/** Abstract `View` representation of PeopleHub. */
+interface PeopleHubViewBoundary {
     /** View used for animating the activity launch caused by clicking a person in the hub. */
     val associatedViewForClickAnimation: View
 
@@ -57,23 +56,22 @@
 }
 
 /**
- * Wraps a [PeopleHubSectionFooterViewBoundary] in a [DataListener], and connects it to the data
+ * Wraps a [PeopleHubViewBoundary] in a [DataListener], and connects it to the data
  * pipeline.
  *
  * @param dataSource PeopleHub data pipeline.
  */
 @Singleton
-class PeopleHubSectionFooterViewAdapterImpl @Inject constructor(
+class PeopleHubViewAdapterImpl @Inject constructor(
     private val dataSource: DataSource<@JvmSuppressWildcards PeopleHubViewModelFactory>
-) : PeopleHubSectionFooterViewAdapter {
+) : PeopleHubViewAdapter {
 
-    override fun bindView(viewBoundary: PeopleHubSectionFooterViewBoundary) {
-        dataSource.registerListener(PeopleHubDataListenerImpl(viewBoundary))
-    }
+    override fun bindView(viewBoundary: PeopleHubViewBoundary): Subscription =
+            dataSource.registerListener(PeopleHubDataListenerImpl(viewBoundary))
 }
 
 private class PeopleHubDataListenerImpl(
-    private val viewBoundary: PeopleHubSectionFooterViewBoundary
+    private val viewBoundary: PeopleHubViewBoundary
 ) : DataListener<PeopleHubViewModelFactory> {
 
     override fun onDataChanged(data: PeopleHubViewModelFactory) {
@@ -92,7 +90,7 @@
  * Converts [PeopleHubModel]s into [PeopleHubViewModelFactory]s.
  *
  * This class serves as the glue between the View layer (which depends on
- * [PeopleHubSectionFooterViewBoundary]) and the Data layer (which produces [PeopleHubModel]s).
+ * [PeopleHubViewBoundary]) and the Data layer (which produces [PeopleHubModel]s).
  */
 @Singleton
 class PeopleHubViewModelFactoryDataSourceImpl @Inject constructor(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
index a0fef00..e79d89f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
@@ -67,29 +67,34 @@
 
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        final int givenSize = MeasureSpec.getSize(heightMeasureSpec);
+        final int givenHeight = MeasureSpec.getSize(heightMeasureSpec);
         final int viewHorizontalPadding = getPaddingStart() + getPaddingEnd();
+
+        // Max height is as large as possible, unless otherwise requested
         int ownMaxHeight = Integer.MAX_VALUE;
         int heightMode = MeasureSpec.getMode(heightMeasureSpec);
-        if (heightMode != MeasureSpec.UNSPECIFIED && givenSize != 0) {
-            ownMaxHeight = Math.min(givenSize, ownMaxHeight);
+        if (heightMode != MeasureSpec.UNSPECIFIED && givenHeight != 0) {
+            // Set our max height to what was requested from the parent
+            ownMaxHeight = Math.min(givenHeight, ownMaxHeight);
         }
-        int newHeightSpec = MeasureSpec.makeMeasureSpec(ownMaxHeight, MeasureSpec.AT_MOST);
+
+        // height of the largest child
         int maxChildHeight = 0;
+        int atMostOwnMaxHeightSpec = MeasureSpec.makeMeasureSpec(ownMaxHeight, MeasureSpec.AT_MOST);
         int childCount = getChildCount();
         for (int i = 0; i < childCount; i++) {
             View child = getChildAt(i);
             if (child.getVisibility() == GONE) {
                 continue;
             }
-            int childHeightSpec = newHeightSpec;
+            int childHeightSpec = atMostOwnMaxHeightSpec;
             ViewGroup.LayoutParams layoutParams = child.getLayoutParams();
             if (layoutParams.height != ViewGroup.LayoutParams.MATCH_PARENT) {
                 if (layoutParams.height >= 0) {
-                    // An actual height is set
-                    childHeightSpec = layoutParams.height > ownMaxHeight
-                        ? MeasureSpec.makeMeasureSpec(ownMaxHeight, MeasureSpec.EXACTLY)
-                        : MeasureSpec.makeMeasureSpec(layoutParams.height, MeasureSpec.EXACTLY);
+                    // If an actual height is set, cap it to the max height
+                    childHeightSpec = MeasureSpec.makeMeasureSpec(
+                            Math.min(layoutParams.height, ownMaxHeight),
+                            MeasureSpec.EXACTLY);
                 }
                 child.measure(getChildMeasureSpec(
                         widthMeasureSpec, viewHorizontalPadding, layoutParams.width),
@@ -100,15 +105,22 @@
                 mMatchParentViews.add(child);
             }
         }
+
+        // Set our own height to the given height, or the height of the largest child
         int ownHeight = heightMode == MeasureSpec.EXACTLY
-                ? givenSize : Math.min(ownMaxHeight, maxChildHeight);
-        newHeightSpec = MeasureSpec.makeMeasureSpec(ownHeight, MeasureSpec.EXACTLY);
+                ? givenHeight
+                : Math.min(ownMaxHeight, maxChildHeight);
+        int exactlyOwnHeightSpec = MeasureSpec.makeMeasureSpec(ownHeight, MeasureSpec.EXACTLY);
+
+        // Now that we know our own height, measure the children that are MATCH_PARENT
         for (View child : mMatchParentViews) {
             child.measure(getChildMeasureSpec(
                     widthMeasureSpec, viewHorizontalPadding, child.getLayoutParams().width),
-                    newHeightSpec);
+                    exactlyOwnHeightSpec);
         }
         mMatchParentViews.clear();
+
+        // Finish up
         int width = MeasureSpec.getSize(widthMeasureSpec);
         setMeasuredDimension(width, ownHeight);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java
index 23433cb..b3561c2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java
@@ -16,11 +16,10 @@
 
 package com.android.systemui.statusbar.notification.stack;
 
-import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.ROWS_GENTLE;
-
 import static java.lang.annotation.RetentionPolicy.SOURCE;
 
 import android.annotation.IntDef;
+import android.annotation.LayoutRes;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.Intent;
@@ -35,18 +34,21 @@
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager;
 import com.android.systemui.statusbar.notification.people.DataListener;
-import com.android.systemui.statusbar.notification.people.PeopleHubSectionFooterViewAdapter;
-import com.android.systemui.statusbar.notification.people.PeopleHubSectionFooterViewBoundary;
+import com.android.systemui.statusbar.notification.people.PeopleHubViewAdapter;
+import com.android.systemui.statusbar.notification.people.PeopleHubViewBoundary;
 import com.android.systemui.statusbar.notification.people.PersonViewModel;
+import com.android.systemui.statusbar.notification.people.Subscription;
 import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
-import com.android.systemui.statusbar.notification.row.dagger.NotificationRowComponent;
+import com.android.systemui.statusbar.notification.row.ExpandableView;
+import com.android.systemui.statusbar.notification.row.StackScrollerDecorView;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
 
 import java.lang.annotation.Retention;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Objects;
 
 import javax.inject.Inject;
 
@@ -63,63 +65,65 @@
     private static final String TAG = "NotifSectionsManager";
     private static final boolean DEBUG = false;
 
-    private NotificationStackScrollLayout mParent;
     private final ActivityStarter mActivityStarter;
     private final StatusBarStateController mStatusBarStateController;
     private final ConfigurationController mConfigurationController;
-    private final int mNumberOfSections;
+    private final PeopleHubViewAdapter mPeopleHubViewAdapter;
     private final NotificationSectionsFeatureManager mSectionsFeatureManager;
-    private final NotificationRowComponent.Builder mNotificationRowComponentBuilder;
+    private final int mNumberOfSections;
+
+    private final PeopleHubViewBoundary mPeopleHubViewBoundary = new PeopleHubViewBoundary() {
+        @Override
+        public void setVisible(boolean isVisible) {
+            if (mPeopleHubVisible != isVisible) {
+                mPeopleHubVisible = isVisible;
+                if (mInitialized) {
+                    updateSectionBoundaries();
+                }
+            }
+        }
+
+        @NonNull
+        @Override
+        public View getAssociatedViewForClickAnimation() {
+            return mPeopleHubView;
+        }
+
+        @NonNull
+        @Override
+        public Sequence<DataListener<PersonViewModel>> getPersonViewAdapters() {
+            return mPeopleHubView.getPersonViewAdapters();
+        }
+    };
+
+    private NotificationStackScrollLayout mParent;
     private boolean mInitialized = false;
 
     private SectionHeaderView mGentleHeader;
-    private boolean mGentleHeaderVisible = false;
-
-    private boolean mPeopleHubVisible = false;
-    private PeopleHubView mPeopleHubView;
-    private final PeopleHubSectionFooterViewAdapter mPeopleHubViewAdapter;
-    private final PeopleHubSectionFooterViewBoundary mPeopleHubViewBoundary =
-            new PeopleHubSectionFooterViewBoundary() {
-                @Override
-                public void setVisible(boolean isVisible) {
-                    if (mPeopleHubVisible != isVisible) {
-                        mPeopleHubVisible = isVisible;
-                        if (mInitialized) {
-                            updateSectionBoundaries();
-                        }
-                    }
-                }
-
-                @NonNull
-                @Override
-                public View getAssociatedViewForClickAnimation() {
-                    return mPeopleHubView;
-                }
-
-                @NonNull
-                @Override
-                public Sequence<DataListener<PersonViewModel>> getPersonViewAdapters() {
-                    return mPeopleHubView.getPersonViewAdapters();
-                }
-            };
-
+    private boolean mGentleHeaderVisible;
     @Nullable private View.OnClickListener mOnClearGentleNotifsClickListener;
 
+    private SectionHeaderView mAlertingHeader;
+    private boolean mAlertingHeaderVisible;
+
+    private PeopleHubView mPeopleHubView;
+    private boolean mPeopleHeaderVisible;
+    private boolean mPeopleHubVisible = false;
+    @Nullable private Subscription mPeopleHubSubscription;
+
     @Inject
     NotificationSectionsManager(
             ActivityStarter activityStarter,
             StatusBarStateController statusBarStateController,
             ConfigurationController configurationController,
-            PeopleHubSectionFooterViewAdapter peopleHubViewAdapter,
-            NotificationSectionsFeatureManager sectionsFeatureManager,
-            NotificationRowComponent.Builder notificationRowComponentBuilder) {
+            PeopleHubViewAdapter peopleHubViewAdapter,
+            NotificationSectionsFeatureManager sectionsFeatureManager) {
         mActivityStarter = activityStarter;
         mStatusBarStateController = statusBarStateController;
         mConfigurationController = configurationController;
         mPeopleHubViewAdapter = peopleHubViewAdapter;
         mSectionsFeatureManager = sectionsFeatureManager;
         mNumberOfSections = mSectionsFeatureManager.getNumberOfBuckets();
-        mNotificationRowComponentBuilder = notificationRowComponentBuilder;
     }
 
     NotificationSection[] createSectionsForBuckets() {
@@ -141,105 +145,81 @@
         mInitialized = true;
         mParent = parent;
         reinflateViews(layoutInflater);
-        mPeopleHubViewAdapter.bindView(mPeopleHubViewBoundary);
         mConfigurationController.addCallback(mConfigurationListener);
     }
 
+    private <T extends ExpandableView> T reinflateView(
+            T view, LayoutInflater layoutInflater, @LayoutRes int layoutResId) {
+        int oldPos = -1;
+        if (view != null) {
+            if (view.getTransientContainer() != null) {
+                view.getTransientContainer().removeView(mGentleHeader);
+            } else if (view.getParent() != null) {
+                oldPos = mParent.indexOfChild(view);
+                mParent.removeView(view);
+            }
+        }
+
+        view = (T) layoutInflater.inflate(layoutResId, mParent, false);
+
+        if (oldPos != -1) {
+            mParent.addView(view, oldPos);
+        }
+
+        return view;
+    }
+
     /**
      * Reinflates the entire notification header, including all decoration views.
      */
     void reinflateViews(LayoutInflater layoutInflater) {
-        int oldGentleHeaderPos = -1;
-        int oldPeopleHubPos = -1;
-        if (mGentleHeader != null) {
-            if (mGentleHeader.getTransientContainer() != null) {
-                mGentleHeader.getTransientContainer().removeView(mGentleHeader);
-            } else if (mGentleHeader.getParent() != null) {
-                oldGentleHeaderPos = mParent.indexOfChild(mGentleHeader);
-                mParent.removeView(mGentleHeader);
-            }
-        }
-        if (mPeopleHubView != null) {
-            if (mPeopleHubView.getTransientContainer() != null) {
-                mPeopleHubView.getTransientContainer().removeView(mPeopleHubView);
-            } else if (mPeopleHubView.getParent() != null) {
-                oldPeopleHubPos = mParent.indexOfChild(mPeopleHubView);
-                mParent.removeView(mPeopleHubView);
-            }
-        }
-
-        mGentleHeader = (SectionHeaderView) layoutInflater.inflate(
-                R.layout.status_bar_notification_section_header, mParent, false);
-        NotificationRowComponent sectionHeaderComponent = mNotificationRowComponentBuilder
-                .activatableNotificationView(mGentleHeader)
-                .build();
-        sectionHeaderComponent.getActivatableNotificationViewController().init();
-
+        mGentleHeader = reinflateView(
+                mGentleHeader, layoutInflater, R.layout.status_bar_notification_section_header);
+        mGentleHeader.setHeaderText(R.string.notification_section_header_gentle);
         mGentleHeader.setOnHeaderClickListener(this::onGentleHeaderClick);
         mGentleHeader.setOnClearAllClickListener(this::onClearGentleNotifsClick);
 
-        if (oldGentleHeaderPos != -1) {
-            mParent.addView(mGentleHeader, oldGentleHeaderPos);
+        mAlertingHeader = reinflateView(
+                mAlertingHeader, layoutInflater, R.layout.status_bar_notification_section_header);
+        mAlertingHeader.setHeaderText(R.string.notification_section_header_alerting);
+        mAlertingHeader.setOnHeaderClickListener(this::onGentleHeaderClick);
+
+        if (mPeopleHubSubscription != null) {
+            mPeopleHubSubscription.unsubscribe();
         }
-
-        mPeopleHubView = (PeopleHubView) layoutInflater.inflate(
-                R.layout.people_strip, mParent, false);
-
-        NotificationRowComponent notificationRowComponent = mNotificationRowComponentBuilder
-                .activatableNotificationView(mPeopleHubView)
-                .build();
-        notificationRowComponent.getActivatableNotificationViewController().init();
-
-        if (oldPeopleHubPos != -1) {
-            mParent.addView(mPeopleHubView, oldPeopleHubPos);
-        }
+        mPeopleHubView = reinflateView(mPeopleHubView, layoutInflater, R.layout.people_strip);
+        mPeopleHubSubscription = mPeopleHubViewAdapter.bindView(mPeopleHubViewBoundary);
     }
 
-    /** Listener for when the "clear all" buttton is clciked on the gentle notification header. */
+    /** Listener for when the "clear all" button is clicked on the gentle notification header. */
     void setOnClearGentleNotifsClickListener(View.OnClickListener listener) {
         mOnClearGentleNotifsClickListener = listener;
     }
 
-    /** Must be called whenever the UI mode changes (i.e. when we enter night mode). */
-    void onUiModeChanged() {
-        mGentleHeader.onUiModeChanged();
-    }
-
     @Override
     public boolean beginsSection(@NonNull View view, @Nullable View previous) {
-        boolean begin = false;
-        if (view instanceof ActivatableNotificationView) {
-            if (previous instanceof ActivatableNotificationView) {
-                // If we're drawing the first non-person notification, break out a section
-                ActivatableNotificationView curr = (ActivatableNotificationView) view;
-                ActivatableNotificationView prev = (ActivatableNotificationView) previous;
-
-                begin = getBucket(curr) != getBucket(prev);
-            }
-        }
-
-        if (!begin) {
-            begin = view == mGentleHeader || view == mPeopleHubView;
-        }
-
-        return begin;
+        return view == mGentleHeader
+                || view == mPeopleHubView
+                || view == mAlertingHeader
+                || !Objects.equals(getBucket(view), getBucket(previous));
     }
 
     private boolean isUsingMultipleSections() {
         return mNumberOfSections > 1;
     }
 
-    private @PriorityBucket int getBucket(ActivatableNotificationView view)
-            throws IllegalArgumentException {
-        if (view instanceof ExpandableNotificationRow) {
-            return ((ExpandableNotificationRow) view).getEntry().getBucket();
-        } else if (view == mGentleHeader) {
+    @Nullable
+    private Integer getBucket(View view) {
+        if (view == mGentleHeader) {
             return BUCKET_SILENT;
         } else if (view == mPeopleHubView) {
             return BUCKET_PEOPLE;
+        } else if (view == mAlertingHeader) {
+            return BUCKET_ALERTING;
+        } else if (view instanceof ExpandableNotificationRow) {
+            return ((ExpandableNotificationRow) view).getEntry().getBucket();
         }
-
-        throw new IllegalArgumentException("I don't know how to find a bucket for this view :(");
+        return null;
     }
 
     /**
@@ -251,118 +231,104 @@
             return;
         }
 
-        boolean peopleNotificationsPresent = false;
-        int firstNonHeadsUpIndex = -1;
-        int firstGentleIndex = -1;
-        int notifCount = 0;
+        final boolean showHeaders = mStatusBarStateController.getState() != StatusBarState.KEYGUARD;
+        final boolean usingPeopleFiltering = mSectionsFeatureManager.isFilteringEnabled();
 
-        final int n = mParent.getChildCount();
-        for (int i = 0; i < n; i++) {
-            View child = mParent.getChildAt(i);
-            if (child instanceof ExpandableNotificationRow && child.getVisibility() != View.GONE) {
-                notifCount++;
+        boolean peopleNotifsPresent = false;
+        int peopleHeaderTarget = -1;
+        int alertingHeaderTarget = -1;
+        int gentleHeaderTarget = -1;
+
+        int viewCount = 0;
+
+        if (showHeaders) {
+            final int childCount = mParent.getChildCount();
+            for (int i = 0; i < childCount; i++) {
+                View child = mParent.getChildAt(i);
+                if (child.getVisibility() == View.GONE
+                        || !(child instanceof ExpandableNotificationRow)) {
+                    continue;
+                }
                 ExpandableNotificationRow row = (ExpandableNotificationRow) child;
-                if (firstNonHeadsUpIndex == -1 && !row.isHeadsUp()) {
-                    firstNonHeadsUpIndex = i;
+                switch (row.getEntry().getBucket()) {
+                    case BUCKET_PEOPLE:
+                        if (peopleHeaderTarget == -1) {
+                            peopleNotifsPresent = true;
+                            peopleHeaderTarget = viewCount;
+                            viewCount++;
+                        }
+                        break;
+                    case BUCKET_ALERTING:
+                        if (usingPeopleFiltering && alertingHeaderTarget == -1) {
+                            alertingHeaderTarget = viewCount;
+                            viewCount++;
+                        }
+                        break;
+                    case BUCKET_SILENT:
+                        if (gentleHeaderTarget == -1) {
+                            gentleHeaderTarget = viewCount;
+                            viewCount++;
+                        }
+                        break;
                 }
-                if (row.getEntry().getBucket() == BUCKET_PEOPLE) {
-                    peopleNotificationsPresent = true;
-                }
-                if (row.getEntry().getBucket() == BUCKET_SILENT) {
-                    firstGentleIndex = i;
-                    break;
+                viewCount++;
+            }
+            if (usingPeopleFiltering && mPeopleHubVisible && peopleHeaderTarget == -1) {
+                // Insert the people header even if there are no people visible, in order to show
+                // the hub. Put it directly above the next header.
+                if (alertingHeaderTarget != -1) {
+                    peopleHeaderTarget = alertingHeaderTarget;
+                    alertingHeaderTarget++;
+                    gentleHeaderTarget++;
+                } else if (gentleHeaderTarget != -1) {
+                    peopleHeaderTarget = gentleHeaderTarget;
+                    gentleHeaderTarget++;
+                } else {
+                    // Put it at the end of the list.
+                    peopleHeaderTarget = viewCount;
                 }
             }
         }
 
-        if (firstNonHeadsUpIndex == -1) {
-            firstNonHeadsUpIndex = firstGentleIndex != -1 ? firstGentleIndex : notifCount;
-        }
+        // Allow swiping the people header if the section is empty
+        mPeopleHubView.setCanSwipe(mPeopleHubVisible && !peopleNotifsPresent);
 
-        // make room for peopleHub
-        int offset = adjustPeopleHubVisibilityAndPosition(
-                firstNonHeadsUpIndex, peopleNotificationsPresent);
-        if (firstGentleIndex != -1) {
-            firstGentleIndex += offset;
-        }
-
-        adjustGentleHeaderVisibilityAndPosition(firstGentleIndex);
-
-        mGentleHeader.setAreThereDismissableGentleNotifs(
-                mParent.hasActiveClearableNotifications(ROWS_GENTLE));
+        mPeopleHeaderVisible = adjustHeaderVisibilityAndPosition(
+                peopleHeaderTarget, mPeopleHubView, mPeopleHeaderVisible);
+        mAlertingHeaderVisible = adjustHeaderVisibilityAndPosition(
+                alertingHeaderTarget, mAlertingHeader, mAlertingHeaderVisible);
+        mGentleHeaderVisible = adjustHeaderVisibilityAndPosition(
+                gentleHeaderTarget, mGentleHeader, mGentleHeaderVisible);
     }
 
-    private void adjustGentleHeaderVisibilityAndPosition(int firstGentleNotifIndex) {
-        final boolean showGentleHeader =
-                firstGentleNotifIndex != -1
-                        && mStatusBarStateController.getState() != StatusBarState.KEYGUARD;
-        final int currentHeaderIndex = mParent.indexOfChild(mGentleHeader);
-
-        if (!showGentleHeader) {
-            if (mGentleHeaderVisible) {
-                mGentleHeaderVisible = false;
-                mParent.removeView(mGentleHeader);
+    private boolean adjustHeaderVisibilityAndPosition(
+            int targetIndex, StackScrollerDecorView header, boolean isCurrentlyVisible) {
+        if (targetIndex == -1) {
+            if (isCurrentlyVisible) {
+                mParent.removeView(header);
             }
+            return false;
         } else {
-            if (!mGentleHeaderVisible) {
-                mGentleHeaderVisible = true;
+            if (header instanceof SwipeableView) {
+                ((SwipeableView) header).resetTranslation();
+            }
+            if (!isCurrentlyVisible) {
                 // If the header is animating away, it will still have a parent, so detach it first
                 // TODO: We should really cancel the active animations here. This will happen
                 // automatically when the view's intro animation starts, but it's a fragile link.
-                if (mGentleHeader.getTransientContainer() != null) {
-                    mGentleHeader.getTransientContainer().removeTransientView(mGentleHeader);
-                    mGentleHeader.setTransientContainer(null);
+                if (header.getTransientContainer() != null) {
+                    header.getTransientContainer().removeTransientView(header);
+                    header.setTransientContainer(null);
                 }
-                mParent.addView(mGentleHeader, firstGentleNotifIndex);
-            } else if (currentHeaderIndex != firstGentleNotifIndex - 1) {
-                // Relocate the header to be immediately before the first child in the section
-                int targetIndex = firstGentleNotifIndex;
-                if (currentHeaderIndex < firstGentleNotifIndex) {
-                    // Adjust the target index to account for the header itself being temporarily
-                    // removed during the position change.
-                    targetIndex--;
-                }
-
-                mParent.changeViewPosition(mGentleHeader, targetIndex);
+                header.setContentVisible(true);
+                mParent.addView(header, targetIndex);
+            } else if (mParent.indexOfChild(header) != targetIndex) {
+                mParent.changeViewPosition(header, targetIndex);
             }
+            return true;
         }
     }
 
-    private int adjustPeopleHubVisibilityAndPosition(
-            int targetIndex, boolean peopleNotificationsPresent) {
-        final boolean showPeopleHeader = mNumberOfSections > 2
-                && mStatusBarStateController.getState() != StatusBarState.KEYGUARD
-                && (peopleNotificationsPresent || mPeopleHubVisible);
-        final int currentHubIndex = mParent.indexOfChild(mPeopleHubView);
-        final boolean currentlyVisible = currentHubIndex >= 0;
-
-        mPeopleHubView.setCanSwipe(showPeopleHeader && !peopleNotificationsPresent);
-
-        if (!showPeopleHeader) {
-            if (currentlyVisible) {
-                mParent.removeView(mPeopleHubView);
-                return -1;
-            }
-        } else {
-            mPeopleHubView.unDismiss();
-            mPeopleHubView.resetTranslation();
-            if (!currentlyVisible) {
-                if (mPeopleHubView.getTransientContainer() != null) {
-                    mPeopleHubView.getTransientContainer().removeTransientView(mPeopleHubView);
-                    mPeopleHubView.setTransientContainer(null);
-                }
-                mParent.addView(mPeopleHubView, targetIndex);
-                return 1;
-            } else if (currentHubIndex != targetIndex) {
-                if (currentHubIndex < targetIndex) {
-                    targetIndex--;
-                }
-                mParent.changeViewPosition(mPeopleHubView, targetIndex);
-            }
-        }
-        return 0;
-    }
-
     /**
      * Updates the boundaries (as tracked by their first and last views) of the priority sections.
      *
@@ -388,7 +354,12 @@
 
             //TODO: do this in a single pass, and more better
             for (ActivatableNotificationView v : children)  {
-                if (getBucket(v) == filter) {
+                Integer bucket = getBucket(v);
+                if (bucket == null) {
+                    throw new IllegalArgumentException("Cannot find section bucket for view");
+                }
+
+                if (bucket == filter) {
                     viewsInBucket.add(v);
                 }
 
@@ -463,16 +434,17 @@
     /**
      * For now, declare the available notification buckets (sections) here so that other
      * presentation code can decide what to do based on an entry's buckets
-     *
      */
     @Retention(SOURCE)
     @IntDef(prefix = { "BUCKET_" }, value = {
+            BUCKET_HEADS_UP,
             BUCKET_PEOPLE,
             BUCKET_ALERTING,
             BUCKET_SILENT
     })
     public @interface PriorityBucket {}
-    public static final int BUCKET_PEOPLE = 0;
-    public static final int BUCKET_ALERTING = 1;
-    public static final int BUCKET_SILENT = 2;
+    public static final int BUCKET_HEADS_UP = 0;
+    public static final int BUCKET_PEOPLE = 1;
+    public static final int BUCKET_ALERTING = 2;
+    public static final int BUCKET_SILENT = 3;
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 2eeda1f..1bd9bbe 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -815,7 +815,6 @@
         mBgColor = mContext.getColor(R.color.notification_shade_background_color);
         updateBackgroundDimming();
         mShelf.onUiModeChanged();
-        mSectionsManager.onUiModeChanged();
     }
 
     @ShadeViewRefactor(RefactorComponent.DECORATOR)
@@ -1632,8 +1631,8 @@
 
     @ShadeViewRefactor(RefactorComponent.COORDINATOR)
     private ExpandableView getChildAtPosition(float touchX, float touchY) {
-        return getChildAtPosition(touchX, touchY, true /* requireMinHeight */);
-
+        return getChildAtPosition(
+                touchX, touchY, true /* requireMinHeight */, true /* ignoreDecors */);
     }
 
     /**
@@ -1642,17 +1641,18 @@
      * @param touchX           the x coordinate
      * @param touchY           the y coordinate
      * @param requireMinHeight Whether a minimum height is required for a child to be returned.
+     * @param ignoreDecors     Whether decors can be returned
      * @return the child at the given location.
      */
     @ShadeViewRefactor(RefactorComponent.COORDINATOR)
     private ExpandableView getChildAtPosition(float touchX, float touchY,
-            boolean requireMinHeight) {
+            boolean requireMinHeight, boolean ignoreDecors) {
         // find the view under the pointer, accounting for GONE views
         final int count = getChildCount();
         for (int childIdx = 0; childIdx < count; childIdx++) {
             ExpandableView slidingChild = (ExpandableView) getChildAt(childIdx);
             if (slidingChild.getVisibility() != VISIBLE
-                    || slidingChild instanceof StackScrollerDecorView) {
+                    || (ignoreDecors && slidingChild instanceof StackScrollerDecorView)) {
                 continue;
             }
             float childTop = slidingChild.getTranslationY();
@@ -4166,7 +4166,9 @@
             case MotionEvent.ACTION_DOWN: {
                 final int y = (int) ev.getY();
                 mScrolledToTopOnFirstDown = isScrolledToTop();
-                if (getChildAtPosition(ev.getX(), y, false /* requireMinHeight */) == null) {
+                final ExpandableView childAtTouchPos = getChildAtPosition(
+                        ev.getX(), y, false /* requireMinHeight */, false /* ignoreDecors */);
+                if (childAtTouchPos == null) {
                     setIsBeingDragged(false);
                     recycleVelocityTracker();
                     break;
@@ -6299,8 +6301,6 @@
             }
 
             if (view instanceof PeopleHubView) {
-                PeopleHubView row = (PeopleHubView) view;
-                row.dismiss(false);
                 mSectionsManager.hidePeopleRow();
             }
 
@@ -6325,8 +6325,11 @@
 
         @Override
         public View getChildAtPosition(MotionEvent ev) {
-            View child = NotificationStackScrollLayout.this.getChildAtPosition(ev.getX(),
-                    ev.getY());
+            View child = NotificationStackScrollLayout.this.getChildAtPosition(
+                    ev.getX(),
+                    ev.getY(),
+                    true /* requireMinHeight */,
+                    false /* ignoreDecors */);
             if (child instanceof ExpandableNotificationRow) {
                 ExpandableNotificationRow row = (ExpandableNotificationRow) child;
                 ExpandableNotificationRow parent = row.getNotificationParent();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/PeopleHubView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/PeopleHubView.kt
index e5717ae..151c6b2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/PeopleHubView.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/PeopleHubView.kt
@@ -25,30 +25,32 @@
 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin
 import com.android.systemui.statusbar.notification.people.DataListener
 import com.android.systemui.statusbar.notification.people.PersonViewModel
-import com.android.systemui.statusbar.notification.row.ActivatableNotificationView
+import com.android.systemui.statusbar.notification.row.StackScrollerDecorView
 
 class PeopleHubView(context: Context, attrs: AttributeSet) :
-        ActivatableNotificationView(context, attrs), SwipeableView {
+        StackScrollerDecorView(context, attrs), SwipeableView {
 
     private lateinit var contents: ViewGroup
-    private lateinit var personControllers: List<PersonDataListenerImpl>
 
-    val personViewAdapters: Sequence<DataListener<PersonViewModel?>>
-        get() = personControllers.asSequence()
+    lateinit var personViewAdapters: Sequence<DataListener<PersonViewModel?>>
+        private set
 
     override fun onFinishInflate() {
-        super.onFinishInflate()
         contents = requireViewById(R.id.people_list)
-        personControllers = (0 until contents.childCount)
+        personViewAdapters = (0 until contents.childCount)
                 .reversed()
                 .asSequence()
                 .mapNotNull { idx ->
                     (contents.getChildAt(idx) as? ImageView)?.let(::PersonDataListenerImpl)
                 }
                 .toList()
+                .asSequence()
+        super.onFinishInflate()
+        setVisible(true /* nowVisible */, false /* animate */)
     }
 
-    override fun getContentView(): View = contents
+    override fun findContentView(): View = contents
+    override fun findSecondaryView(): View? = null
 
     override fun hasFinishedInitialization(): Boolean = true
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/SectionHeaderView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/SectionHeaderView.java
index add982d..ad3ff69 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/SectionHeaderView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/SectionHeaderView.java
@@ -17,8 +17,8 @@
 package com.android.systemui.statusbar.notification.stack;
 
 import android.annotation.Nullable;
+import android.annotation.StringRes;
 import android.content.Context;
-import android.graphics.RectF;
 import android.util.AttributeSet;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
@@ -28,7 +28,7 @@
 import android.widget.TextView;
 
 import com.android.systemui.R;
-import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
+import com.android.systemui.statusbar.notification.row.StackScrollerDecorView;
 
 import java.util.Objects;
 
@@ -36,23 +36,22 @@
  * Similar in size and appearance to the NotificationShelf, appears at the beginning of some
  * notification sections. Currently only used for gentle notifications.
  */
-public class SectionHeaderView extends ActivatableNotificationView {
+public class SectionHeaderView extends StackScrollerDecorView {
     private ViewGroup mContents;
     private TextView mLabelView;
     private ImageView mClearAllButton;
     @Nullable private View.OnClickListener mOnClearClickListener = null;
 
-    private final RectF mTmpRect = new RectF();
-
     public SectionHeaderView(Context context, AttributeSet attrs) {
         super(context, attrs);
     }
 
     @Override
     protected void onFinishInflate() {
-        super.onFinishInflate();
         mContents = Objects.requireNonNull(findViewById(R.id.content));
         bindContents();
+        super.onFinishInflate();
+        setVisible(true /* nowVisible */, false /* animate */);
     }
 
     private void bindContents() {
@@ -64,15 +63,20 @@
     }
 
     @Override
-    protected View getContentView() {
+    protected View findContentView() {
         return mContents;
     }
 
+    @Override
+    protected View findSecondaryView() {
+        return null;
+    }
+
     /**
      * Destroys and reinflates the visible contents of the section header. For use on configuration
      * changes or any other time that layout values might need to be re-evaluated.
      *
-     * Does not reinflate the base content view itself ({@link #getContentView()} or any of the
+     * Does not reinflate the base content view itself ({@link #findContentView()} or any of the
      * decorator views, such as the background view or shadow view.
      */
     void reinflateContents() {
@@ -88,35 +92,20 @@
         return true;
     }
 
-    /** Must be called whenever the UI mode changes (i.e. when we enter night mode). */
-    void onUiModeChanged() {
-        updateBackgroundColors();
-        mLabelView.setTextColor(
-                getContext().getColor(R.color.notification_section_header_label_color));
-        mClearAllButton.setImageResource(
-                R.drawable.status_bar_notification_section_header_clear_btn);
-    }
-
     void setAreThereDismissableGentleNotifs(boolean areThereDismissableGentleNotifs) {
         mClearAllButton.setVisibility(areThereDismissableGentleNotifs ? View.VISIBLE : View.GONE);
     }
 
     @Override
-    protected boolean disallowSingleClick(MotionEvent event) {
-        // Disallow single click on lockscreen if user is tapping on clear all button
-        mTmpRect.set(
-                mClearAllButton.getLeft(),
-                mClearAllButton.getTop(),
-                mClearAllButton.getLeft() + mClearAllButton.getWidth(),
-                mClearAllButton.getTop() + mClearAllButton.getHeight());
-        return mTmpRect.contains(event.getX(), event.getY());
+    public boolean onInterceptTouchEvent(MotionEvent ev) {
+        return super.onInterceptTouchEvent(ev);
     }
 
     /**
      * Fired whenever the user clicks on the body of the header (e.g. no sub-buttons or anything).
      */
     void setOnHeaderClickListener(View.OnClickListener listener) {
-        mContents.setOnClickListener(listener);
+        mLabelView.setOnClickListener(listener);
     }
 
     /** Fired when the user clicks on the "X" button on the far right of the header. */
@@ -124,4 +113,8 @@
         mOnClearClickListener = listener;
         mClearAllButton.setOnClickListener(listener);
     }
+
+    void setHeaderText(@StringRes int resId) {
+        mLabelView.setText(resId);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
index 691e1c4..1dde5c0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
@@ -150,14 +150,26 @@
     private KeyguardViewMediator mKeyguardViewMediator;
     private ScrimController mScrimController;
     private StatusBar mStatusBar;
-    private int mPendingAuthenticatedUserId = -1;
-    private BiometricSourceType mPendingAuthenticatedBioSourceType = null;
+    private PendingAuthenticated mPendingAuthenticated = null;
     private boolean mPendingShowBouncer;
     private boolean mHasScreenTurnedOnSinceAuthenticating;
     private boolean mFadedAwayAfterWakeAndUnlock;
 
     private final MetricsLogger mMetricsLogger;
 
+    private static final class PendingAuthenticated {
+        public final int userId;
+        public final BiometricSourceType biometricSourceType;
+        public final boolean isStrongBiometric;
+
+        PendingAuthenticated(int userId, BiometricSourceType biometricSourceType,
+                boolean isStrongBiometric) {
+            this.userId = userId;
+            this.biometricSourceType = biometricSourceType;
+            this.isStrongBiometric = isStrongBiometric;
+        }
+    }
+
     @Inject
     public BiometricUnlockController(Context context, DozeScrimController dozeScrimController,
             KeyguardViewMediator keyguardViewMediator, ScrimController scrimController,
@@ -251,28 +263,30 @@
     }
 
     @Override
-    public void onBiometricAuthenticated(int userId, BiometricSourceType biometricSourceType) {
+    public void onBiometricAuthenticated(int userId, BiometricSourceType biometricSourceType,
+            boolean isStrongBiometric) {
         Trace.beginSection("BiometricUnlockController#onBiometricAuthenticated");
         if (mUpdateMonitor.isGoingToSleep()) {
-            mPendingAuthenticatedUserId = userId;
-            mPendingAuthenticatedBioSourceType = biometricSourceType;
+            mPendingAuthenticated = new PendingAuthenticated(userId, biometricSourceType,
+                    isStrongBiometric);
             Trace.endSection();
             return;
         }
         mMetricsLogger.write(new LogMaker(MetricsEvent.BIOMETRIC_AUTH)
                 .setType(MetricsEvent.TYPE_SUCCESS).setSubtype(toSubtype(biometricSourceType)));
         boolean unlockAllowed = mKeyguardBypassController.onBiometricAuthenticated(
-                biometricSourceType);
+                biometricSourceType, isStrongBiometric);
         if (unlockAllowed) {
             mKeyguardViewMediator.userActivity();
-            startWakeAndUnlock(biometricSourceType);
+            startWakeAndUnlock(biometricSourceType, isStrongBiometric);
         } else {
             Log.d(TAG, "onBiometricAuthenticated aborted by bypass controller");
         }
     }
 
-    public void startWakeAndUnlock(BiometricSourceType biometricSourceType) {
-        startWakeAndUnlock(calculateMode(biometricSourceType));
+    public void startWakeAndUnlock(BiometricSourceType biometricSourceType,
+            boolean isStrongBiometric) {
+        startWakeAndUnlock(calculateMode(biometricSourceType, isStrongBiometric));
     }
 
     public void startWakeAndUnlock(@WakeAndUnlockMode int mode) {
@@ -373,45 +387,46 @@
     public void onStartedGoingToSleep(int why) {
         resetMode();
         mFadedAwayAfterWakeAndUnlock = false;
-        mPendingAuthenticatedUserId = -1;
-        mPendingAuthenticatedBioSourceType = null;
+        mPendingAuthenticated = null;
     }
 
     @Override
     public void onFinishedGoingToSleep(int why) {
         Trace.beginSection("BiometricUnlockController#onFinishedGoingToSleep");
-        BiometricSourceType pendingType = mPendingAuthenticatedBioSourceType;
-        int pendingUserId = mPendingAuthenticatedUserId;
-        if (pendingUserId != -1 && pendingType != null) {
+        if (mPendingAuthenticated != null) {
             // Post this to make sure it's executed after the device is fully locked.
-            mHandler.post(() -> onBiometricAuthenticated(pendingUserId, pendingType));
+            mHandler.post(() -> onBiometricAuthenticated(mPendingAuthenticated.userId,
+                    mPendingAuthenticated.biometricSourceType,
+                    mPendingAuthenticated.isStrongBiometric));
+            mPendingAuthenticated = null;
         }
-        mPendingAuthenticatedUserId = -1;
-        mPendingAuthenticatedBioSourceType = null;
         Trace.endSection();
     }
 
     public boolean hasPendingAuthentication() {
-        return mPendingAuthenticatedUserId != -1
-                && mUpdateMonitor.isUnlockingWithBiometricAllowed()
-                && mPendingAuthenticatedUserId == KeyguardUpdateMonitor.getCurrentUser();
+        return mPendingAuthenticated != null
+                && mUpdateMonitor
+                    .isUnlockingWithBiometricAllowed(mPendingAuthenticated.isStrongBiometric)
+                && mPendingAuthenticated.userId == KeyguardUpdateMonitor.getCurrentUser();
     }
 
     public int getMode() {
         return mMode;
     }
 
-    private @WakeAndUnlockMode int calculateMode(BiometricSourceType biometricSourceType) {
+    private @WakeAndUnlockMode int calculateMode(BiometricSourceType biometricSourceType,
+            boolean isStrongBiometric) {
         if (biometricSourceType == BiometricSourceType.FACE
                 || biometricSourceType == BiometricSourceType.IRIS) {
-            return calculateModeForPassiveAuth();
+            return calculateModeForPassiveAuth(isStrongBiometric);
         } else {
-            return calculateModeForFingerprint();
+            return calculateModeForFingerprint(isStrongBiometric);
         }
     }
 
-    private @WakeAndUnlockMode int calculateModeForFingerprint() {
-        boolean unlockingAllowed = mUpdateMonitor.isUnlockingWithBiometricAllowed();
+    private @WakeAndUnlockMode int calculateModeForFingerprint(boolean isStrongBiometric) {
+        boolean unlockingAllowed =
+                mUpdateMonitor.isUnlockingWithBiometricAllowed(isStrongBiometric);
         boolean deviceDreaming = mUpdateMonitor.isDreaming();
 
         if (!mUpdateMonitor.isDeviceInteractive()) {
@@ -440,8 +455,9 @@
         return MODE_NONE;
     }
 
-    private @WakeAndUnlockMode int calculateModeForPassiveAuth() {
-        boolean unlockingAllowed = mUpdateMonitor.isUnlockingWithBiometricAllowed();
+    private @WakeAndUnlockMode int calculateModeForPassiveAuth(boolean isStrongBiometric) {
+        boolean unlockingAllowed =
+                mUpdateMonitor.isUnlockingWithBiometricAllowed(isStrongBiometric);
         boolean deviceDreaming = mUpdateMonitor.isDreaming();
         boolean bypass = mKeyguardBypassController.getBypassEnabled();
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt
index b4d0d47..03918e0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt
@@ -38,11 +38,20 @@
     private val mKeyguardStateController: KeyguardStateController
     private val statusBarStateController: StatusBarStateController
     private var hasFaceFeature: Boolean
+    private var pendingUnlock: PendingUnlock? = null
 
     /**
+     * Pending unlock info:
+     *
      * The pending unlock type which is set if the bypass was blocked when it happened.
+     *
+     * Whether the pending unlock type is strong biometric or non-strong biometric
+     * (i.e. weak or convenience).
      */
-    private var pendingUnlockType: BiometricSourceType? = null
+    private data class PendingUnlock(
+        val pendingUnlockType: BiometricSourceType,
+        val isStrongBiometric: Boolean
+    )
 
     lateinit var unlockController: BiometricUnlockController
     var isPulseExpanding = false
@@ -86,7 +95,7 @@
         statusBarStateController.addCallback(object : StatusBarStateController.StateListener {
             override fun onStateChanged(newState: Int) {
                 if (newState != StatusBarState.KEYGUARD) {
-                    pendingUnlockType = null
+                    pendingUnlock = null
                 }
             }
         })
@@ -101,7 +110,7 @@
         lockscreenUserManager.addUserChangedListener(
                 object : NotificationLockscreenUserManager.UserChangedListener {
                     override fun onUserChanged(userId: Int) {
-                        pendingUnlockType = null
+                        pendingUnlock = null
                     }
                 })
     }
@@ -111,11 +120,14 @@
      *
      * @return false if we can not wake and unlock right now
      */
-    fun onBiometricAuthenticated(biometricSourceType: BiometricSourceType): Boolean {
+    fun onBiometricAuthenticated(
+        biometricSourceType: BiometricSourceType,
+        isStrongBiometric: Boolean
+    ): Boolean {
         if (bypassEnabled) {
             val can = canBypass()
             if (!can && (isPulseExpanding || qSExpanded)) {
-                pendingUnlockType = biometricSourceType
+                pendingUnlock = PendingUnlock(biometricSourceType, isStrongBiometric)
             }
             return can
         }
@@ -123,10 +135,12 @@
     }
 
     fun maybePerformPendingUnlock() {
-        if (pendingUnlockType != null) {
-            if (onBiometricAuthenticated(pendingUnlockType!!)) {
-                unlockController.startWakeAndUnlock(pendingUnlockType)
-                pendingUnlockType = null
+        if (pendingUnlock != null) {
+            if (onBiometricAuthenticated(pendingUnlock!!.pendingUnlockType,
+                            pendingUnlock!!.isStrongBiometric)) {
+                unlockController.startWakeAndUnlock(pendingUnlock!!.pendingUnlockType,
+                        pendingUnlock!!.isStrongBiometric)
+                pendingUnlock = null
             }
         }
     }
@@ -162,12 +176,17 @@
     }
 
     fun onStartedGoingToSleep() {
-        pendingUnlockType = null
+        pendingUnlock = null
     }
 
     override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>) {
         pw.println("KeyguardBypassController:")
-        pw.println("  pendingUnlockType: $pendingUnlockType")
+        if (pendingUnlock != null) {
+            pw.println("  mPendingUnlock.pendingUnlockType: ${pendingUnlock!!.pendingUnlockType}")
+            pw.println("  mPendingUnlock.isStrongBiometric: ${pendingUnlock!!.isStrongBiometric}")
+        } else {
+            pw.println("  mPendingUnlock: $pendingUnlock")
+        }
         pw.println("  bypassEnabled: $bypassEnabled")
         pw.println("  canBypass: ${canBypass()}")
         pw.println("  bouncerShowing: $bouncerShowing")
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
index 60589843..61cef68 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
@@ -387,7 +387,12 @@
     public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
         super.onInitializeAccessibilityNodeInfo(info);
         boolean fingerprintRunning = mKeyguardUpdateMonitor.isFingerprintDetectionRunning();
-        boolean unlockingAllowed = mKeyguardUpdateMonitor.isUnlockingWithBiometricAllowed();
+        // Only checking if unlocking with Biometric is allowed (no matter strong or non-strong
+        // as long as primary auth, i.e. PIN/pattern/password, is not required), so it's ok to
+        // pass true for isStrongBiometric to isUnlockingWithBiometricAllowed() to bypass the
+        // check of whether non-strong biometric is allowed
+        boolean unlockingAllowed = mKeyguardUpdateMonitor
+                        .isUnlockingWithBiometricAllowed(true /* isStrongBiometric */);
         if (fingerprintRunning && unlockingAllowed) {
             AccessibilityNodeInfo.AccessibilityAction unlock
                     = new AccessibilityNodeInfo.AccessibilityAction(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
index fb7976f..c61d7bb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -202,8 +202,10 @@
 
                 @Override
                 public void onBiometricAuthenticated(int userId,
-                        BiometricSourceType biometricSourceType) {
-                    if (mFirstBypassAttempt && mUpdateMonitor.isUnlockingWithBiometricAllowed()) {
+                        BiometricSourceType biometricSourceType,
+                        boolean isStrongBiometric) {
+                    if (mFirstBypassAttempt
+                            && mUpdateMonitor.isUnlockingWithBiometricAllowed(isStrongBiometric)) {
                         mDelayShowingKeyguardStatusBar = true;
                     }
                 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index 260f94c..1ab36c5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -678,6 +678,12 @@
     }
 
     @Override
+    public void onCountdownEnd() {
+        if (DEBUG) Log.d(TAG, "screenrecord: hiding icon during countdown");
+        mHandler.post(() -> mIconController.setIconVisibility(mSlotScreenRecord, false));
+    }
+
+    @Override
     public void onRecordingStart() {
         if (DEBUG) Log.d(TAG, "screenrecord: showing icon");
         mIconController.setIcon(mSlotScreenRecord,
@@ -687,7 +693,7 @@
 
     @Override
     public void onRecordingEnd() {
-        // Ensure this is on the main thread, since it could be called during countdown
+        // Ensure this is on the main thread
         if (DEBUG) Log.d(TAG, "screenrecord: hiding icon");
         mHandler.post(() -> mIconController.setIconVisibility(mSlotScreenRecord, false));
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 10821d6..945a9db 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -21,7 +21,6 @@
 import android.animation.ValueAnimator;
 import android.annotation.IntDef;
 import android.app.AlarmManager;
-import android.content.res.Resources;
 import android.graphics.Color;
 import android.graphics.drawable.Drawable;
 import android.os.Handler;
@@ -45,7 +44,6 @@
 import com.android.systemui.Dumpable;
 import com.android.systemui.R;
 import com.android.systemui.colorextraction.SysuiColorExtractor;
-import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.dock.DockManager;
 import com.android.systemui.statusbar.ScrimView;
 import com.android.systemui.statusbar.notification.stack.ViewState;
@@ -116,7 +114,7 @@
      * A scrim varies its opacity based on a busyness factor, for example
      * how many notifications are currently visible.
      */
-    public static final float BUSY_SCRIM_ALPHA = 0.54f;
+    public static final float BUSY_SCRIM_ALPHA = 0.75f;
 
     /**
      * The most common scrim, the one under the keyguard.
@@ -146,8 +144,6 @@
     private GradientColors mColors;
     private boolean mNeedsDrawableColorUpdate;
 
-    private float mScrimBehindAlpha;
-    private float mScrimBehindAlphaResValue;
     private float mScrimBehindAlphaKeyguard = SCRIM_BEHIND_ALPHA_KEYGUARD;
 
     // Assuming the shade is expanded during initialization
@@ -192,7 +188,6 @@
     @Inject
     public ScrimController(LightBarController lightBarController, DozeParameters dozeParameters,
             AlarmManager alarmManager, KeyguardStateController keyguardStateController,
-            @Main Resources resources,
             DelayedWakeLock.Builder delayedWakeLockBuilder, Handler handler,
             KeyguardUpdateMonitor keyguardUpdateMonitor, SysuiColorExtractor sysuiColorExtractor,
             DockManager dockManager) {
@@ -203,14 +198,12 @@
         mDarkenWhileDragging = !mKeyguardStateController.canDismissLockScreen();
         mKeyguardUpdateMonitor = keyguardUpdateMonitor;
         mKeyguardVisibilityCallback = new KeyguardVisibilityCallback();
-        mScrimBehindAlphaResValue = resources.getFloat(R.dimen.scrim_behind_alpha);
         mHandler = handler;
         mTimeTicker = new AlarmTimeout(alarmManager, this::onHideWallpaperTimeout,
                 "hide_aod_wallpaper", mHandler);
         mWakeLock = delayedWakeLockBuilder.setHandler(mHandler).setTag("Scrims").build();
         // Scrim alpha is initially set to the value on the resource but might be changed
         // to make sure that text on top of it is legible.
-        mScrimBehindAlpha = mScrimBehindAlphaResValue;
         mDozeParameters = dozeParameters;
         mDockManager = dockManager;
         keyguardStateController.addCallback(new KeyguardStateController.Callback() {
@@ -587,7 +580,6 @@
             int mainColor = mColors.getMainColor();
             float minOpacity = ColorUtils.calculateMinimumBackgroundAlpha(textColor, mainColor,
                     4.5f /* minimumContrast */) / 255f;
-            mScrimBehindAlpha = Math.max(mScrimBehindAlphaResValue, minOpacity);
             dispatchScrimState(mScrimBehind.getViewAlpha());
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
index 0ab08a8..a7f60d6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
@@ -293,13 +293,12 @@
         }
 
         @Override
-        public void onBiometricAuthenticated(int userId, BiometricSourceType biometricSourceType) {
+        public void onBiometricAuthenticated(int userId, BiometricSourceType biometricSourceType,
+                boolean isStrongBiometric) {
             Trace.beginSection("KeyguardUpdateMonitorCallback#onBiometricAuthenticated");
-            if (!mKeyguardUpdateMonitor.isUnlockingWithBiometricAllowed()) {
-                Trace.endSection();
-                return;
+            if (mKeyguardUpdateMonitor.isUnlockingWithBiometricAllowed(isStrongBiometric)) {
+                update(false /* updateAlways */);
             }
-            update(false /* updateAlways */);
             Trace.endSection();
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/util/animation/PhysicsAnimator.kt b/packages/SystemUI/src/com/android/systemui/util/animation/PhysicsAnimator.kt
index f4157f2..8625d63 100644
--- a/packages/SystemUI/src/com/android/systemui/util/animation/PhysicsAnimator.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/animation/PhysicsAnimator.kt
@@ -126,6 +126,13 @@
     internal var startAction: () -> Unit = ::startInternal
 
     /**
+     * Action to run when [cancel] is called. This can be changed by
+     * [PhysicsAnimatorTestUtils.prepareForTest] to cancel animations from the main thread, which
+     * is required.
+     */
+    internal var cancelAction: (Set<FloatPropertyCompat<in T>>) -> Unit = ::cancelInternal
+
+    /**
      * Springs a property to the given value, using the provided configuration settings.
      *
      * Springs are used when you know the exact value to which you want to animate. They can be
@@ -429,10 +436,13 @@
                         max = max(currentValue, this.max)
                     }
 
-                    // Apply the configuration and start the animation. Since flings can't be
-                    // redirected while in motion, cancel it first.
+                    // Flings can't be updated to a new position while maintaining velocity, because
+                    // we're using the explicitly provided start velocity. Cancel any flings (or
+                    // springs) on this property before flinging.
+                    cancel(animatedProperty)
+
+                    // Apply the configuration and start the animation.
                     getFlingAnimation(animatedProperty)
-                            .also { it.cancel() }
                             .also { flingConfig.applyToAnimation(it) }
                             .start()
                 }
@@ -707,11 +717,26 @@
         return springConfigs.keys.union(flingConfigs.keys)
     }
 
+    /**
+     * Cancels the given properties. This is typically called immediately by [cancel], unless this
+     * animator is under test.
+     */
+    internal fun cancelInternal(properties: Set<FloatPropertyCompat<in T>>) {
+        for (property in properties) {
+            flingAnimations[property]?.cancel()
+            springAnimations[property]?.cancel()
+        }
+    }
+
     /** Cancels all in progress animations on all properties. */
     fun cancel() {
-        for (dynamicAnim in flingAnimations.values.union(springAnimations.values)) {
-            dynamicAnim.cancel()
-        }
+        cancelAction(flingAnimations.keys)
+        cancelAction(springAnimations.keys)
+    }
+
+    /** Cancels in progress animations on the provided properties only. */
+    fun cancel(vararg properties: FloatPropertyCompat<in T>) {
+        cancelAction(properties.toSet())
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/util/animation/PhysicsAnimatorTestUtils.kt b/packages/SystemUI/src/com/android/systemui/util/animation/PhysicsAnimatorTestUtils.kt
index 965decd..c50eeac 100644
--- a/packages/SystemUI/src/com/android/systemui/util/animation/PhysicsAnimatorTestUtils.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/animation/PhysicsAnimatorTestUtils.kt
@@ -363,8 +363,12 @@
         private val testEndListeners = ArrayList<PhysicsAnimator.EndListener<T>>()
         private val testUpdateListeners = ArrayList<PhysicsAnimator.UpdateListener<T>>()
 
+        /** Whether we're currently in the middle of executing startInternal(). */
+        private var currentlyRunningStartInternal = false
+
         init {
             animator.startAction = ::startForTest
+            animator.cancelAction = ::cancelForTest
         }
 
         internal fun addTestEndListener(listener: PhysicsAnimator.EndListener<T>) {
@@ -437,7 +441,29 @@
                     }
                 })
 
+                currentlyRunningStartInternal = true
                 animator.startInternal()
+                currentlyRunningStartInternal = false
+                unblockLatch.countDown()
+            }
+
+            unblockLatch.await(timeoutMs, TimeUnit.MILLISECONDS)
+        }
+
+        private fun cancelForTest(properties: Set<FloatPropertyCompat<in T>>) {
+            // If this was called from startInternal, we are already on the animation thread, and
+            // should just call cancelInternal rather than posting it. If we post it, the
+            // cancellation will occur after the rest of startInternal() and we'll immediately
+            // cancel the animation we worked so hard to start!
+            if (currentlyRunningStartInternal) {
+                animator.cancelInternal(properties)
+                return
+            }
+
+            val unblockLatch = CountDownLatch(1)
+
+            animationThreadHandler.post {
+                animator.cancelInternal(properties)
                 unblockLatch.countDown()
             }
 
diff --git a/packages/SystemUI/src/com/android/systemui/util/magnetictarget/MagnetizedObject.kt b/packages/SystemUI/src/com/android/systemui/util/magnetictarget/MagnetizedObject.kt
new file mode 100644
index 0000000..2276ba1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/magnetictarget/MagnetizedObject.kt
@@ -0,0 +1,618 @@
+/*
+ * 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.systemui.util.magnetictarget
+
+import android.annotation.SuppressLint
+import android.content.Context
+import android.database.ContentObserver
+import android.graphics.PointF
+import android.os.Handler
+import android.os.UserHandle
+import android.os.VibrationEffect
+import android.os.Vibrator
+import android.provider.Settings
+import android.view.MotionEvent
+import android.view.VelocityTracker
+import android.view.View
+import androidx.dynamicanimation.animation.DynamicAnimation
+import androidx.dynamicanimation.animation.FloatPropertyCompat
+import androidx.dynamicanimation.animation.SpringForce
+import com.android.systemui.util.animation.PhysicsAnimator
+import kotlin.math.hypot
+
+/**
+ * Utility class for creating 'magnetized' objects that are attracted to one or more magnetic
+ * targets. Magnetic targets attract objects that are dragged near them, and hold them there unless
+ * they're moved away or released. Releasing objects inside a magnetic target typically performs an
+ * action on the object.
+ *
+ * MagnetizedObject also supports flinging to targets, which will result in the object being pulled
+ * into the target and released as if it was dragged into it.
+ *
+ * To use this class, either construct an instance with an object of arbitrary type, or use the
+ * [MagnetizedObject.magnetizeView] shortcut method if you're magnetizing a view. Then, set
+ * [magnetListener] to receive event callbacks. In your touch handler, pass all MotionEvents
+ * that move this object to [maybeConsumeMotionEvent]. If that method returns true, consider the
+ * event consumed by the MagnetizedObject and don't move the object unless it begins returning false
+ * again.
+ *
+ * @param context Context, used to retrieve a Vibrator instance for vibration effects.
+ * @param underlyingObject The actual object that we're magnetizing.
+ * @param xProperty Property that sets the x value of the object's position.
+ * @param yProperty Property that sets the y value of the object's position.
+ */
+abstract class MagnetizedObject<T : Any>(
+    val context: Context,
+
+    /** The actual object that is animated. */
+    val underlyingObject: T,
+
+    /** Property that gets/sets the object's X value. */
+    val xProperty: FloatPropertyCompat<in T>,
+
+    /** Property that gets/sets the object's Y value. */
+    val yProperty: FloatPropertyCompat<in T>
+) {
+
+    /** Return the width of the object. */
+    abstract fun getWidth(underlyingObject: T): Float
+
+    /** Return the height of the object. */
+    abstract fun getHeight(underlyingObject: T): Float
+
+    /**
+     * Fill the provided array with the location of the top-left of the object, relative to the
+     * entire screen. Compare to [View.getLocationOnScreen].
+     */
+    abstract fun getLocationOnScreen(underlyingObject: T, loc: IntArray)
+
+    /** Methods for listening to events involving a magnetized object.  */
+    interface MagnetListener {
+
+        /**
+         * Called when touch events move within the magnetic field of a target, causing the
+         * object to animate to the target and become 'stuck' there. The animation happens
+         * automatically here - you should not move the object. You can, however, change its state
+         * to indicate to the user that it's inside the target and releasing it will have an effect.
+         *
+         * [maybeConsumeMotionEvent] is now returning true and will continue to do so until a call
+         * to [onUnstuckFromTarget] or [onReleasedInTarget].
+         *
+         * @param target The target that the object is now stuck to.
+         */
+        fun onStuckToTarget(target: MagneticTarget)
+
+        /**
+         * Called when the object is no longer stuck to a target. This means that either touch
+         * events moved outside of the magnetic field radius, or that a forceful fling out of the
+         * target was detected.
+         *
+         * The object won't be automatically animated out of the target, since you're responsible
+         * for moving the object again. You should move it (or animate it) using your own
+         * movement/animation logic.
+         *
+         * Reverse any effects applied in [onStuckToTarget] here.
+         *
+         * If [wasFlungOut] is true, [maybeConsumeMotionEvent] returned true for the ACTION_UP event
+         * that concluded the fling. If [wasFlungOut] is false, that means a drag gesture is ongoing
+         * and [maybeConsumeMotionEvent] is now returning false.
+         *
+         * @param target The target that this object was just unstuck from.
+         * @param velX The X velocity of the touch gesture when it exited the magnetic field.
+         * @param velY The Y velocity of the touch gesture when it exited the magnetic field.
+         * @param wasFlungOut Whether the object was unstuck via a fling gesture. This means that
+         * an ACTION_UP event was received, and that the gesture velocity was sufficient to conclude
+         * that the user wants to un-stick the object despite no touch events occurring outside of
+         * the magnetic field radius.
+         */
+        fun onUnstuckFromTarget(
+            target: MagneticTarget,
+            velX: Float,
+            velY: Float,
+            wasFlungOut: Boolean
+        )
+
+        /**
+         * Called when the object is released inside a target, or flung towards it with enough
+         * velocity to reach it.
+         *
+         * @param target The target that the object was released in.
+         */
+        fun onReleasedInTarget(target: MagneticTarget)
+    }
+
+    private val animator: PhysicsAnimator<T> = PhysicsAnimator.getInstance(underlyingObject)
+    private val objectLocationOnScreen = IntArray(2)
+
+    /**
+     * Targets that have been added to this object. These will all be considered when determining
+     * magnetic fields and fling trajectories.
+     */
+    private val associatedTargets = ArrayList<MagneticTarget>()
+
+    private val velocityTracker: VelocityTracker = VelocityTracker.obtain()
+    private val vibrator: Vibrator = context.getSystemService(Context.VIBRATOR_SERVICE) as Vibrator
+
+    /** Whether touch events are presently occurring within the magnetic field area of a target. */
+    val objectStuckToTarget: Boolean
+        get() = targetObjectIsStuckTo != null
+
+    /** The target the object is stuck to, or null if the object is not stuck to any target. */
+    private var targetObjectIsStuckTo: MagneticTarget? = null
+
+    /**
+     * Sets the listener to receive events. This must be set, or [maybeConsumeMotionEvent]
+     * will always return false and no magnetic effects will occur.
+     */
+    lateinit var magnetListener: MagnetizedObject.MagnetListener
+
+    /**
+     * Sets whether forcefully flinging the object vertically towards a target causes it to be
+     * attracted to the target and then released immediately, despite never being dragged within the
+     * magnetic field.
+     */
+    var flingToTargetEnabled = true
+
+    /**
+     * If fling to target is enabled, forcefully flinging the object towards a target will cause
+     * it to be attracted to the target and then released immediately, despite never being dragged
+     * within the magnetic field.
+     *
+     * This sets the width of the area considered 'near' enough a target to be considered a fling,
+     * in terms of percent of the target view's width. For example, setting this to 3f means that
+     * flings towards a 100px-wide target will be considered 'near' enough if they're towards the
+     * 300px-wide area around the target.
+     *
+     * Flings whose trajectory intersects the area will be attracted and released - even if the
+     * target view itself isn't intersected:
+     *
+     * |             |
+     * |           0 |
+     * |          /  |
+     * |         /   |
+     * |      X /    |
+     * |.....###.....|
+     *
+     *
+     * Flings towards the target whose trajectories do not intersect the area will be treated as
+     * normal flings and the magnet will leave the object alone:
+     *
+     * |             |
+     * |             |
+     * |   0         |
+     * |  /          |
+     * | /    X      |
+     * |.....###.....|
+     *
+     */
+    var flingToTargetWidthPercent = 3f
+
+    /**
+     * Sets the minimum velocity (in pixels per second) required to fling an object to the target
+     * without dragging it into the magnetic field.
+     */
+    var flingToTargetMinVelocity = 4000f
+
+    /**
+     * Sets the minimum velocity (in pixels per second) required to fling un-stuck an object stuck
+     * to the target. If this velocity is reached, the object will be freed even if it wasn't moved
+     * outside the magnetic field radius.
+     */
+    var flingUnstuckFromTargetMinVelocity = 1000f
+
+    /**
+     * Sets the maximum velocity above which the object will not stick to the target. Even if the
+     * object is dragged through the magnetic field, it will not stick to the target until the
+     * velocity is below this value.
+     */
+    var stickToTargetMaxVelocity = 2000f
+
+    /**
+     * Enable or disable haptic vibration effects when the object interacts with the magnetic field.
+     *
+     * If you're experiencing crashes when the object enters targets, ensure that you have the
+     * android.permission.VIBRATE permission!
+     */
+    var hapticsEnabled = true
+
+    /** Whether the HAPTIC_FEEDBACK_ENABLED setting is true. */
+    private var systemHapticsEnabled = false
+
+    /** Default spring configuration to use for animating the object into a target. */
+    var springConfig = PhysicsAnimator.SpringConfig(
+            SpringForce.STIFFNESS_MEDIUM, SpringForce.DAMPING_RATIO_NO_BOUNCY)
+
+    /**
+     * Spring configuration to use to spring the object into a target specifically when it's flung
+     * towards (rather than dragged near) it.
+     */
+    var flungIntoTargetSpringConfig = springConfig
+
+    init {
+        val hapticSettingObserver =
+                object : ContentObserver(Handler.getMain()) {
+            override fun onChange(selfChange: Boolean) {
+                systemHapticsEnabled =
+                        Settings.System.getIntForUser(
+                                context.contentResolver,
+                                Settings.System.HAPTIC_FEEDBACK_ENABLED,
+                                0,
+                                UserHandle.USER_CURRENT) != 0
+            }
+        }
+
+        context.contentResolver.registerContentObserver(
+                Settings.System.getUriFor(Settings.System.HAPTIC_FEEDBACK_ENABLED),
+                true /* notifyForDescendants */, hapticSettingObserver)
+
+        // Trigger the observer once to initialize systemHapticsEnabled.
+        hapticSettingObserver.onChange(false /* selfChange */)
+    }
+
+    /**
+     * Adds the provided MagneticTarget to this object. The object will now be attracted to the
+     * target if it strays within its magnetic field or is flung towards it.
+     *
+     * If this target (or its magnetic field) overlaps another target added to this object, the
+     * prior target will take priority.
+     */
+    fun addTarget(target: MagneticTarget) {
+        associatedTargets.add(target)
+        target.updateLocationOnScreen()
+    }
+
+    /**
+     * Shortcut that accepts a View and a magnetic field radius and adds it as a magnetic target.
+     *
+     * @return The MagneticTarget instance for the given View. This can be used to change the
+     * target's magnetic field radius after it's been added. It can also be added to other
+     * magnetized objects.
+     */
+    fun addTarget(target: View, magneticFieldRadiusPx: Int): MagneticTarget {
+        return MagneticTarget(target, magneticFieldRadiusPx).also { addTarget(it) }
+    }
+
+    /**
+     * Removes the given target from this object. The target will no longer attract the object.
+     */
+    fun removeTarget(target: MagneticTarget) {
+        associatedTargets.remove(target)
+    }
+
+    /**
+     * Provide this method with all motion events that move the magnetized object. If the
+     * location of the motion events moves within the magnetic field of a target, or indicate a
+     * fling-to-target gesture, this method will return true and you should not move the object
+     * yourself until it returns false again.
+     *
+     * Note that even when this method returns true, you should continue to pass along new motion
+     * events so that we know when the events move back outside the magnetic field area.
+     *
+     * This method will always return false if you haven't set a [magnetListener].
+     */
+    fun maybeConsumeMotionEvent(ev: MotionEvent): Boolean {
+        // Short-circuit if we don't have a listener or any targets, since those are required.
+        if (associatedTargets.size == 0) {
+            return false
+        }
+
+        // When a gesture begins, recalculate target views' positions on the screen in case they
+        // have changed. Also, clear state.
+        if (ev.action == MotionEvent.ACTION_DOWN) {
+            updateTargetViewLocations()
+
+            // Clear the velocity tracker and assume we're not stuck to a target yet.
+            velocityTracker.clear()
+            targetObjectIsStuckTo = null
+        }
+
+        addMovement(ev)
+
+        val targetObjectIsInMagneticFieldOf = associatedTargets.firstOrNull { target ->
+            val distanceFromTargetCenter = hypot(
+                    ev.rawX - target.centerOnScreen.x,
+                    ev.rawY - target.centerOnScreen.y)
+            distanceFromTargetCenter < target.magneticFieldRadiusPx
+        }
+
+        // If we aren't currently stuck to a target, and we're in the magnetic field of a target,
+        // we're newly stuck.
+        val objectNewlyStuckToTarget =
+                !objectStuckToTarget && targetObjectIsInMagneticFieldOf != null
+
+        // If we are currently stuck to a target, we're in the magnetic field of a target, and that
+        // target isn't the one we're currently stuck to, then touch events have moved into a
+        // adjacent target's magnetic field.
+        val objectMovedIntoDifferentTarget =
+                objectStuckToTarget &&
+                        targetObjectIsInMagneticFieldOf != null &&
+                        targetObjectIsStuckTo != targetObjectIsInMagneticFieldOf
+
+        if (objectNewlyStuckToTarget || objectMovedIntoDifferentTarget) {
+            velocityTracker.computeCurrentVelocity(1000)
+            val velX = velocityTracker.xVelocity
+            val velY = velocityTracker.yVelocity
+
+            // If the object is moving too quickly within the magnetic field, do not stick it. This
+            // only applies to objects newly stuck to a target. If the object is moved into a new
+            // target, it wasn't moving at all (since it was stuck to the previous one).
+            if (objectNewlyStuckToTarget && hypot(velX, velY) > stickToTargetMaxVelocity) {
+                return false
+            }
+
+            // This touch event is newly within the magnetic field - let the listener know, and
+            // animate sticking to the magnet.
+            targetObjectIsStuckTo = targetObjectIsInMagneticFieldOf
+            cancelAnimations()
+            magnetListener.onStuckToTarget(targetObjectIsInMagneticFieldOf!!)
+            animateStuckToTarget(targetObjectIsInMagneticFieldOf!!, velX, velY, false)
+
+            vibrateIfEnabled(VibrationEffect.EFFECT_HEAVY_CLICK)
+        } else if (targetObjectIsInMagneticFieldOf == null && objectStuckToTarget) {
+            velocityTracker.computeCurrentVelocity(1000)
+
+            // This touch event is newly outside the magnetic field - let the listener know. It will
+            // move the object out of the target using its own movement logic.
+            cancelAnimations()
+            magnetListener.onUnstuckFromTarget(
+                    targetObjectIsStuckTo!!, velocityTracker.xVelocity, velocityTracker.yVelocity,
+                    wasFlungOut = false)
+            targetObjectIsStuckTo = null
+
+            vibrateIfEnabled(VibrationEffect.EFFECT_TICK)
+        }
+
+        // First, check for relevant gestures concluding with an ACTION_UP.
+        if (ev.action == MotionEvent.ACTION_UP) {
+
+            velocityTracker.computeCurrentVelocity(1000 /* units */)
+            val velX = velocityTracker.xVelocity
+            val velY = velocityTracker.yVelocity
+
+            // Cancel the magnetic animation since we might still be springing into the magnetic
+            // target, but we're about to fling away or release.
+            cancelAnimations()
+
+            if (objectStuckToTarget) {
+                if (hypot(velX, velY) > flingUnstuckFromTargetMinVelocity) {
+                    // If the object is stuck, but it was forcefully flung away from the target,
+                    // tell the listener so the object can be animated out of the target.
+                    magnetListener.onUnstuckFromTarget(
+                            targetObjectIsStuckTo!!, velX, velY, wasFlungOut = true)
+                } else {
+                    // If the object is stuck and not flung away, it was released inside the target.
+                    magnetListener.onReleasedInTarget(targetObjectIsStuckTo!!)
+                    vibrateIfEnabled(VibrationEffect.EFFECT_HEAVY_CLICK)
+                }
+
+                // Either way, we're no longer stuck.
+                targetObjectIsStuckTo = null
+                return true
+            }
+
+            // The target we're flinging towards, or null if we're not flinging towards any target.
+            val flungToTarget = associatedTargets.firstOrNull { target ->
+                isForcefulFlingTowardsTarget(target, ev.rawX, ev.rawY, velX, velY)
+            }
+
+            if (flungToTarget != null) {
+                // If this is a fling-to-target, animate the object to the magnet and then release
+                // it.
+                magnetListener.onStuckToTarget(flungToTarget)
+                targetObjectIsStuckTo = flungToTarget
+
+                animateStuckToTarget(flungToTarget, velX, velY, true) {
+                    targetObjectIsStuckTo = null
+                    magnetListener.onReleasedInTarget(flungToTarget)
+                    vibrateIfEnabled(VibrationEffect.EFFECT_HEAVY_CLICK)
+                }
+
+                return true
+            }
+
+            // If it's not either of those things, we are not interested.
+            return false
+        }
+
+        return objectStuckToTarget // Always consume touch events if the object is stuck.
+    }
+
+    /** Plays the given vibration effect if haptics are enabled. */
+    @SuppressLint("MissingPermission")
+    private fun vibrateIfEnabled(effect: Int) {
+        if (hapticsEnabled && systemHapticsEnabled) {
+            vibrator.vibrate(effect.toLong())
+        }
+    }
+
+    /** Adds the movement to the velocity tracker using raw coordinates. */
+    private fun addMovement(event: MotionEvent) {
+        // Add movement to velocity tracker using raw screen X and Y coordinates instead
+        // of window coordinates because the window frame may be moving at the same time.
+        val deltaX = event.rawX - event.x
+        val deltaY = event.rawY - event.y
+        event.offsetLocation(deltaX, deltaY)
+        velocityTracker.addMovement(event)
+        event.offsetLocation(-deltaX, -deltaY)
+    }
+
+    /** Animates sticking the object to the provided target with the given start velocities.  */
+    private fun animateStuckToTarget(
+        target: MagneticTarget,
+        velX: Float,
+        velY: Float,
+        flung: Boolean,
+        after: (() -> Unit)? = null
+    ) {
+        target.updateLocationOnScreen()
+        getLocationOnScreen(underlyingObject, objectLocationOnScreen)
+
+        // Calculate the difference between the target's center coordinates and the object's.
+        // Animating the object's x/y properties by these values will center the object on top
+        // of the magnetic target.
+        val xDiff = target.centerOnScreen.x -
+                getWidth(underlyingObject) / 2f - objectLocationOnScreen[0]
+        val yDiff = target.centerOnScreen.y -
+                getHeight(underlyingObject) / 2f - objectLocationOnScreen[1]
+
+        val springConfig = if (flung) flungIntoTargetSpringConfig else springConfig
+
+        cancelAnimations()
+
+        // Animate to the center of the target.
+        animator
+                .spring(xProperty, xProperty.getValue(underlyingObject) + xDiff, velX,
+                        springConfig)
+                .spring(yProperty, yProperty.getValue(underlyingObject) + yDiff, velY,
+                        springConfig)
+
+        if (after != null) {
+            animator.withEndActions(after)
+        }
+
+        animator.start()
+    }
+
+    /**
+     * Whether or not the provided values match a 'fast fling' towards the provided target. If it
+     * does, we consider it a fling-to-target gesture.
+     */
+    private fun isForcefulFlingTowardsTarget(
+        target: MagneticTarget,
+        rawX: Float,
+        rawY: Float,
+        velX: Float,
+        velY: Float
+    ): Boolean {
+        if (!flingToTargetEnabled) {
+            return false
+        }
+
+        // Whether velocity is sufficient, depending on whether we're flinging into a target at the
+        // top or the bottom of the screen.
+        val velocitySufficient =
+                if (rawY < target.centerOnScreen.y) velY > flingToTargetMinVelocity
+                else velY < flingToTargetMinVelocity
+
+        if (!velocitySufficient) {
+            return false
+        }
+
+        // Whether the trajectory of the fling intersects the target area.
+        var targetCenterXIntercept = rawX
+
+        // Only do math if the X velocity is non-zero, otherwise X won't change.
+        if (velX != 0f) {
+            // Rise over run...
+            val slope = velY / velX
+            // ...y = mx + b, b = y / mx...
+            val yIntercept = rawY - slope * rawX
+
+            // ...calculate the x value when y = the target's y-coordinate.
+            targetCenterXIntercept = (target.centerOnScreen.y - yIntercept) / slope
+        }
+
+        // The width of the area we're looking for a fling towards.
+        val targetAreaWidth = target.targetView.width * flingToTargetWidthPercent
+
+        // Velocity was sufficient, so return true if the intercept is within the target area.
+        return targetCenterXIntercept > target.centerOnScreen.x - targetAreaWidth / 2 &&
+                targetCenterXIntercept < target.centerOnScreen.x + targetAreaWidth / 2
+    }
+
+    /** Cancel animations on this object's x/y properties. */
+    internal fun cancelAnimations() {
+        animator.cancel(xProperty, yProperty)
+    }
+
+    /** Updates the locations on screen of all of the [associatedTargets]. */
+    internal fun updateTargetViewLocations() {
+        associatedTargets.forEach { it.updateLocationOnScreen() }
+    }
+
+    /**
+     * Represents a target view with a magnetic field radius and cached center-on-screen
+     * coordinates.
+     *
+     * Instances of MagneticTarget are passed to a MagnetizedObject's [addTarget], and can then
+     * attract the object if it's dragged near or flung towards it. MagneticTargets can be added to
+     * multiple objects.
+     */
+    class MagneticTarget(
+        internal val targetView: View,
+        var magneticFieldRadiusPx: Int
+    ) {
+        internal val centerOnScreen = PointF()
+
+        private val tempLoc = IntArray(2)
+
+        fun updateLocationOnScreen() {
+            targetView.getLocationOnScreen(tempLoc)
+
+            // Add half of the target size to get the center, and subtract translation since the
+            // target could be animating in while we're doing this calculation.
+            centerOnScreen.set(
+                    tempLoc[0] + targetView.width / 2f - targetView.translationX,
+                    tempLoc[1] + targetView.height / 2f - targetView.translationY)
+        }
+    }
+
+    companion object {
+
+        /**
+         * Magnetizes the given view. Magnetized views are attracted to one or more magnetic
+         * targets. Magnetic targets attract objects that are dragged near them, and hold them there
+         * unless they're moved away or released. Releasing objects inside a magnetic target
+         * typically performs an action on the object.
+         *
+         * Magnetized views can also be flung to targets, which will result in the view being pulled
+         * into the target and released as if it was dragged into it.
+         *
+         * To use the returned MagnetizedObject<View> instance, first set [magnetListener] to
+         * receive event callbacks. In your touch handler, pass all MotionEvents that move this view
+         * to [maybeConsumeMotionEvent]. If that method returns true, consider the event consumed by
+         * MagnetizedObject and don't move the view unless it begins returning false again.
+         *
+         * The view will be moved via translationX/Y properties, and its
+         * width/height will be determined via getWidth()/getHeight(). If you are animating
+         * something other than a view, or want to position your view using properties other than
+         * translationX/Y, implement an instance of [MagnetizedObject].
+         *
+         * Note that the magnetic library can't re-order your view automatically. If the view
+         * renders on top of the target views, it will obscure the target when it sticks to it.
+         * You'll want to bring the view to the front in [MagnetListener.onStuckToTarget].
+         */
+        @JvmStatic
+        fun <T : View> magnetizeView(view: T): MagnetizedObject<T> {
+            return object : MagnetizedObject<T>(
+                    view.context,
+                    view,
+                    DynamicAnimation.TRANSLATION_X,
+                    DynamicAnimation.TRANSLATION_Y) {
+                override fun getWidth(underlyingObject: T): Float {
+                    return underlyingObject.width.toFloat()
+                }
+
+                override fun getHeight(underlyingObject: T): Float {
+                    return underlyingObject.height.toFloat() }
+
+                override fun getLocationOnScreen(underlyingObject: T, loc: IntArray) {
+                    underlyingObject.getLocationOnScreen(loc)
+                }
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/wifi/WifiDebuggingActivity.java b/packages/SystemUI/src/com/android/systemui/wifi/WifiDebuggingActivity.java
new file mode 100644
index 0000000..a94af24
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/wifi/WifiDebuggingActivity.java
@@ -0,0 +1,223 @@
+/*
+ * Copyright (C) 2012 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.systemui.wifi;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.debug.IAdbManager;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
+import android.net.wifi.WifiInfo;
+import android.net.wifi.WifiManager;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.ServiceManager;
+import android.util.EventLog;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.Window;
+import android.view.WindowManager;
+import android.widget.CheckBox;
+import android.widget.Toast;
+
+import com.android.internal.app.AlertActivity;
+import com.android.internal.app.AlertController;
+import com.android.systemui.R;
+
+/**
+ * Alerts the user of an untrusted network when enabling wireless debugging.
+ * The user can either deny, allow, or allow with the "always allow on this
+ * network" checked.
+ */
+public class WifiDebuggingActivity extends AlertActivity
+                                  implements DialogInterface.OnClickListener {
+    private static final String TAG = "WifiDebuggingActivity";
+
+    private CheckBox mAlwaysAllow;
+    // Notifies when wifi is disabled, or the network changed
+    private WifiChangeReceiver mWifiChangeReceiver;
+    private WifiManager mWifiManager;
+    private String mBssid;
+    private boolean mClicked = false;
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        Window window = getWindow();
+        window.addSystemFlags(
+                WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
+        window.setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);
+
+        super.onCreate(icicle);
+
+
+        mWifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
+        mWifiChangeReceiver = new WifiChangeReceiver(this);
+
+        Intent intent = getIntent();
+        String ssid = intent.getStringExtra("ssid");
+        mBssid = intent.getStringExtra("bssid");
+
+        if (ssid == null || mBssid == null) {
+            finish();
+            return;
+        }
+
+        final AlertController.AlertParams ap = mAlertParams;
+        ap.mTitle = getString(R.string.wifi_debugging_title);
+        ap.mMessage = getString(R.string.wifi_debugging_message, ssid, mBssid);
+        ap.mPositiveButtonText = getString(R.string.wifi_debugging_allow);
+        ap.mNegativeButtonText = getString(android.R.string.cancel);
+        ap.mPositiveButtonListener = this;
+        ap.mNegativeButtonListener = this;
+
+        // add "always allow" checkbox
+        LayoutInflater inflater = LayoutInflater.from(ap.mContext);
+        View checkbox = inflater.inflate(com.android.internal.R.layout.always_use_checkbox, null);
+        mAlwaysAllow = (CheckBox) checkbox.findViewById(com.android.internal.R.id.alwaysUse);
+        mAlwaysAllow.setText(getString(R.string.wifi_debugging_always));
+        ap.mView = checkbox;
+        window.setCloseOnTouchOutside(false);
+
+        setupAlert();
+
+        // adding touch listener on affirmative button - checks if window is obscured
+        // if obscured, do not let user give permissions (could be tapjacking involved)
+        final View.OnTouchListener filterTouchListener = (View v, MotionEvent event) -> {
+            // Filter obscured touches by consuming them.
+            if (((event.getFlags() & MotionEvent.FLAG_WINDOW_IS_OBSCURED) != 0)
+                    || ((event.getFlags() & MotionEvent.FLAG_WINDOW_IS_PARTIALLY_OBSCURED) != 0)) {
+                if (event.getAction() == MotionEvent.ACTION_UP) {
+                    // TODO: need a different value for safety net?
+                    EventLog.writeEvent(0x534e4554, "62187985"); // safety net logging
+                    Toast.makeText(v.getContext(),
+                            R.string.touch_filtered_warning,
+                            Toast.LENGTH_SHORT).show();
+                }
+                return true;
+            }
+            return false;
+        };
+        mAlert.getButton(BUTTON_POSITIVE).setOnTouchListener(filterTouchListener);
+
+    }
+
+    @Override
+    public void onWindowAttributesChanged(WindowManager.LayoutParams params) {
+        super.onWindowAttributesChanged(params);
+    }
+
+    private class WifiChangeReceiver extends BroadcastReceiver {
+        private final Activity mActivity;
+        WifiChangeReceiver(Activity activity) {
+            mActivity = activity;
+        }
+
+        @Override
+        public void onReceive(Context content, Intent intent) {
+            String action = intent.getAction();
+            if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(action)) {
+                int state = intent.getIntExtra(
+                        WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_DISABLED);
+                if (state == WifiManager.WIFI_STATE_DISABLED) {
+                    mActivity.finish();
+                }
+            } else if (WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(action)) {
+                NetworkInfo networkInfo = (NetworkInfo) intent.getParcelableExtra(
+                        WifiManager.EXTRA_NETWORK_INFO);
+                if (networkInfo.getType() == ConnectivityManager.TYPE_WIFI) {
+                    if (!networkInfo.isConnected()) {
+                        mActivity.finish();
+                        return;
+                    }
+                    WifiInfo wifiInfo = mWifiManager.getConnectionInfo();
+                    if (wifiInfo == null || wifiInfo.getNetworkId() == -1) {
+                        mActivity.finish();
+                        return;
+                    }
+                    String bssid = wifiInfo.getBSSID();
+                    if (bssid == null || bssid.isEmpty()) {
+                        mActivity.finish();
+                        return;
+                    }
+                    if (!bssid.equals(mBssid)) {
+                        mActivity.finish();
+                        return;
+                    }
+                }
+            }
+        }
+    }
+
+    @Override
+    public void onStart() {
+        super.onStart();
+        IntentFilter filter = new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION);
+        filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
+        registerReceiver(mWifiChangeReceiver, filter);
+    }
+
+    @Override
+    protected void onStop() {
+        if (mWifiChangeReceiver != null) {
+            unregisterReceiver(mWifiChangeReceiver);
+        }
+        super.onStop();
+    }
+
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+
+        // In the case where user dismissed the dialog, we don't get an onClick event.
+        // In that case, tell adb to deny the network connection.
+        if (!mClicked) {
+            try {
+                IBinder b = ServiceManager.getService(ADB_SERVICE);
+                IAdbManager service = IAdbManager.Stub.asInterface(b);
+                service.denyWirelessDebugging();
+            } catch (Exception e) {
+                Log.e(TAG, "Unable to notify Adb service", e);
+            }
+        }
+    }
+
+    @Override
+    public void onClick(DialogInterface dialog, int which) {
+        mClicked = true;
+        boolean allow = (which == AlertDialog.BUTTON_POSITIVE);
+        boolean alwaysAllow = allow && mAlwaysAllow.isChecked();
+        try {
+            IBinder b = ServiceManager.getService(ADB_SERVICE);
+            IAdbManager service = IAdbManager.Stub.asInterface(b);
+            if (allow) {
+                service.allowWirelessDebugging(alwaysAllow, mBssid);
+            } else {
+                service.denyWirelessDebugging();
+            }
+        } catch (Exception e) {
+            Log.e(TAG, "Unable to notify Adb service", e);
+        }
+        finish();
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/wifi/WifiDebuggingSecondaryUserActivity.java b/packages/SystemUI/src/com/android/systemui/wifi/WifiDebuggingSecondaryUserActivity.java
new file mode 100644
index 0000000..0266a84
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/wifi/WifiDebuggingSecondaryUserActivity.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2015 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.systemui.wifi;
+
+import android.app.Activity;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
+import android.net.wifi.WifiInfo;
+import android.net.wifi.WifiManager;
+import android.os.Bundle;
+
+import com.android.internal.app.AlertActivity;
+import com.android.internal.app.AlertController;
+import com.android.systemui.R;
+
+/**
+ * Alerts the user that wireless debugging cannot be enabled by a secondary user.
+ */
+public class WifiDebuggingSecondaryUserActivity extends AlertActivity
+        implements DialogInterface.OnClickListener {
+    private WifiChangeReceiver mWifiChangeReceiver;
+    private WifiManager mWifiManager;
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        mWifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
+        mWifiChangeReceiver = new WifiChangeReceiver(this);
+
+        final AlertController.AlertParams ap = mAlertParams;
+        ap.mTitle = getString(R.string.wifi_debugging_secondary_user_title);
+        ap.mMessage = getString(R.string.wifi_debugging_secondary_user_message);
+        ap.mPositiveButtonText = getString(android.R.string.ok);
+        ap.mPositiveButtonListener = this;
+
+        setupAlert();
+    }
+
+    private class WifiChangeReceiver extends BroadcastReceiver {
+        private final Activity mActivity;
+        WifiChangeReceiver(Activity activity) {
+            mActivity = activity;
+        }
+
+        @Override
+        public void onReceive(Context content, Intent intent) {
+            String action = intent.getAction();
+            if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(action)) {
+                int state = intent.getIntExtra(
+                        WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_DISABLED);
+                if (state == WifiManager.WIFI_STATE_DISABLED) {
+                    mActivity.finish();
+                }
+            } else if (WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(action)) {
+                NetworkInfo networkInfo = (NetworkInfo) intent.getParcelableExtra(
+                        WifiManager.EXTRA_NETWORK_INFO);
+                if (networkInfo.getType() == ConnectivityManager.TYPE_WIFI) {
+                    if (!networkInfo.isConnected()) {
+                        mActivity.finish();
+                        return;
+                    }
+                    WifiInfo wifiInfo = mWifiManager.getConnectionInfo();
+                    if (wifiInfo == null || wifiInfo.getNetworkId() == -1) {
+                        mActivity.finish();
+                        return;
+                    }
+                }
+            }
+        }
+    }
+
+    @Override
+    public void onStart() {
+        super.onStart();
+
+        IntentFilter filter = new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION);
+        filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
+        registerReceiver(mWifiChangeReceiver, filter);
+    }
+
+    @Override
+    protected void onStop() {
+        if (mWifiChangeReceiver != null) {
+            unregisterReceiver(mWifiChangeReceiver);
+        }
+        super.onStop();
+    }
+
+    @Override
+    public void onClick(DialogInterface dialog, int which) {
+        finish();
+    }
+}
diff --git a/packages/SystemUI/tests/Android.mk b/packages/SystemUI/tests/Android.mk
index e5f56d4..38da21e 100644
--- a/packages/SystemUI/tests/Android.mk
+++ b/packages/SystemUI/tests/Android.mk
@@ -46,6 +46,9 @@
 # UI it doesn't own. This is necessary to allow screenshots to be taken
 LOCAL_CERTIFICATE := platform
 
+LOCAL_FULL_LIBS_MANIFEST_FILES := $(LOCAL_PATH)/AndroidManifest.xml
+LOCAL_MANIFEST_FILE := AndroidManifest-base.xml
+
 # Provide jack a list of classes to exclude from code coverage.
 # This is needed because the SystemUITests compile SystemUI source directly, rather than using
 # LOCAL_INSTRUMENTATION_FOR := SystemUI.
diff --git a/packages/SystemUI/tests/AndroidManifest-base.xml b/packages/SystemUI/tests/AndroidManifest-base.xml
new file mode 100644
index 0000000..f08d3d2
--- /dev/null
+++ b/packages/SystemUI/tests/AndroidManifest-base.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:sharedUserId="android.uid.system"
+    package="com.android.systemui.tests" />
diff --git a/packages/SystemUI/tests/AndroidManifest.xml b/packages/SystemUI/tests/AndroidManifest.xml
index c51624b..12c7048 100644
--- a/packages/SystemUI/tests/AndroidManifest.xml
+++ b/packages/SystemUI/tests/AndroidManifest.xml
@@ -18,7 +18,7 @@
     xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
     xmlns:tools="http://schemas.android.com/tools"
     android:sharedUserId="android.uid.system"
-    package="com.android.systemui.tests">
+    package="com.android.systemui" >
 
     <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
     <uses-permission android:name="android.permission.ACCESS_VOICE_INTERACTION_SERVICE" />
@@ -55,11 +55,6 @@
 
     <application android:debuggable="true" android:largeHeap="true">
         <uses-library android:name="android.test.runner" />
-        <activity android:name="com.android.systemui.screenshot.ScreenshotStubActivity" />
-
-        <service
-            android:name="com.android.systemui.qs.external.TileLifecycleManagerTests$FakeTileService"
-            android:process=":killable" />
 
         <receiver android:name="com.android.systemui.SliceBroadcastRelayHandlerTest$Receiver">
             <intent-filter>
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPresentationTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPresentationTest.java
index b6ca8d8e..7231b8a 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPresentationTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPresentationTest.java
@@ -41,8 +41,8 @@
         InjectionInflationController inflationController = new InjectionInflationController(
                 SystemUIFactory.getInstance().getRootComponent());
         Context context = getContext();
-        KeyguardPresentation keyguardPresentation =
-                new KeyguardPresentation(context, context.getDisplay(), inflationController);
+        KeyguardPresentation keyguardPresentation = new KeyguardPresentation(context,
+                context.getDisplayNoVerify(), inflationController);
         keyguardPresentation.onCreate(null /*savedInstanceState */);
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index befe3e1..6a093963 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -22,6 +22,7 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
@@ -75,6 +76,7 @@
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.concurrent.Executor;
 import java.util.concurrent.atomic.AtomicBoolean;
 
 @SmallTest
@@ -117,6 +119,8 @@
     private SubscriptionManager mSubscriptionManager;
     @Mock
     private BroadcastDispatcher mBroadcastDispatcher;
+    @Mock
+    private Executor mBackgroundExecutor;
     private TestableLooper mTestableLooper;
     private TestableKeyguardUpdateMonitor mKeyguardUpdateMonitor;
 
@@ -137,7 +141,9 @@
         when(mFaceManager.hasEnrolledTemplates(anyInt())).thenReturn(true);
         when(mUserManager.isUserUnlocked(anyInt())).thenReturn(true);
         when(mUserManager.isPrimaryUser()).thenReturn(true);
-        when(mStrongAuthTracker.isUnlockingWithBiometricAllowed()).thenReturn(true);
+        when(mStrongAuthTracker
+                .isUnlockingWithBiometricAllowed(anyBoolean() /* isStrongBiometric */))
+                .thenReturn(true);
         context.addMockSystemService(TrustManager.class, mTrustManager);
         context.addMockSystemService(FingerprintManager.class, mFingerprintManager);
         context.addMockSystemService(BiometricManager.class, mBiometricManager);
@@ -450,7 +456,10 @@
 
     @Test
     public void testOnFaceAuthenticated_skipsFaceWhenAuthenticated() {
-        mKeyguardUpdateMonitor.onFaceAuthenticated(KeyguardUpdateMonitor.getCurrentUser());
+        // test whether face will be skipped if authenticated, so the value of isStrongBiometric
+        // doesn't matter here
+        mKeyguardUpdateMonitor.onFaceAuthenticated(KeyguardUpdateMonitor.getCurrentUser(),
+                true /* isStrongBiometric */);
         mKeyguardUpdateMonitor.sendKeyguardBouncerChanged(true);
         mTestableLooper.processAllMessages();
 
@@ -460,18 +469,36 @@
     @Test
     public void testGetUserCanSkipBouncer_whenFace() {
         int user = KeyguardUpdateMonitor.getCurrentUser();
-        mKeyguardUpdateMonitor.onFaceAuthenticated(user);
+        mKeyguardUpdateMonitor.onFaceAuthenticated(user, true /* isStrongBiometric */);
         assertThat(mKeyguardUpdateMonitor.getUserCanSkipBouncer(user)).isTrue();
     }
 
     @Test
+    public void testGetUserCanSkipBouncer_whenFace_nonStrongAndDisallowed() {
+        when(mStrongAuthTracker.isUnlockingWithBiometricAllowed(false /* isStrongBiometric */))
+                .thenReturn(false);
+        int user = KeyguardUpdateMonitor.getCurrentUser();
+        mKeyguardUpdateMonitor.onFaceAuthenticated(user, false /* isStrongBiometric */);
+        assertThat(mKeyguardUpdateMonitor.getUserCanSkipBouncer(user)).isFalse();
+    }
+
+    @Test
     public void testGetUserCanSkipBouncer_whenFingerprint() {
         int user = KeyguardUpdateMonitor.getCurrentUser();
-        mKeyguardUpdateMonitor.onFingerprintAuthenticated(user);
+        mKeyguardUpdateMonitor.onFingerprintAuthenticated(user, true /* isStrongBiometric */);
         assertThat(mKeyguardUpdateMonitor.getUserCanSkipBouncer(user)).isTrue();
     }
 
     @Test
+    public void testGetUserCanSkipBouncer_whenFingerprint_nonStrongAndDisallowed() {
+        when(mStrongAuthTracker.isUnlockingWithBiometricAllowed(false /* isStrongBiometric */))
+                .thenReturn(false);
+        int user = KeyguardUpdateMonitor.getCurrentUser();
+        mKeyguardUpdateMonitor.onFingerprintAuthenticated(user, false /* isStrongBiometric */);
+        assertThat(mKeyguardUpdateMonitor.getUserCanSkipBouncer(user)).isFalse();
+    }
+
+    @Test
     public void testGetUserCanSkipBouncer_whenTrust() {
         int user = KeyguardUpdateMonitor.getCurrentUser();
         mKeyguardUpdateMonitor.onTrustChanged(true /* enabled */, user, 0 /* flags */);
@@ -585,7 +612,7 @@
         protected TestableKeyguardUpdateMonitor(Context context) {
             super(context,
                     TestableLooper.get(KeyguardUpdateMonitorTest.this).getLooper(),
-                    mBroadcastDispatcher, mDumpController);
+                    mBroadcastDispatcher, mDumpController, mBackgroundExecutor);
             mStrongAuthTracker = KeyguardUpdateMonitorTest.this.mStrongAuthTracker;
         }
 
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/clock/ClockManagerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/clock/ClockManagerTest.java
index 3330d1e..6199181 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/clock/ClockManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/clock/ClockManagerTest.java
@@ -93,6 +93,8 @@
                 mMockPluginManager, mMockColorExtractor, mMockContentResolver,
                 mMockCurrentUserObserable, mMockSettingsWrapper, mFakeDockManager);
 
+        mClockManager.addBuiltinClock(() -> new BubbleClockController(
+                getContext().getResources(), inflater, mMockColorExtractor));
         mClockManager.addOnClockChangedListener(mMockListener1);
         mClockManager.addOnClockChangedListener(mMockListener2);
         reset(mMockListener1, mMockListener2);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java
new file mode 100644
index 0000000..e8e98b4
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java
@@ -0,0 +1,136 @@
+/*
+ * 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.systemui.qs.tiles;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertTrue;
+
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.service.quicksettings.Tile;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.Dependency;
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.qs.QSTileHost;
+import com.android.systemui.screenrecord.RecordingController;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+@SmallTest
+public class ScreenRecordTileTest extends SysuiTestCase {
+
+    @Mock
+    private RecordingController mController;
+    @Mock
+    private QSTileHost mHost;
+
+    private TestableLooper mTestableLooper;
+    private ScreenRecordTile mTile;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+
+        mTestableLooper = TestableLooper.get(this);
+        mDependency.injectTestDependency(Dependency.BG_LOOPER, mTestableLooper.getLooper());
+        mController = mDependency.injectMockDependency(RecordingController.class);
+
+        when(mHost.getContext()).thenReturn(mContext);
+
+        mTile = new ScreenRecordTile(mHost, mController);
+    }
+
+    // Test that the tile is inactive and labeled correctly when the controller is neither starting
+    // or recording, and that clicking on the tile in this state brings up the record prompt
+    @Test
+    public void testNotActive() {
+        when(mController.isStarting()).thenReturn(false);
+        when(mController.isRecording()).thenReturn(false);
+
+        mTile.refreshState();
+        mTestableLooper.processAllMessages();
+
+        assertEquals(Tile.STATE_INACTIVE, mTile.getState().state);
+        assertTrue(mTile.getState().secondaryLabel.toString().equals(
+                mContext.getString(R.string.quick_settings_screen_record_start)));
+
+        mTile.handleClick();
+        verify(mController, times(1)).launchRecordPrompt();
+    }
+
+    // Test that the tile is active and labeled correctly when the controller is starting
+    @Test
+    public void testIsStarting() {
+        when(mController.isStarting()).thenReturn(true);
+        when(mController.isRecording()).thenReturn(false);
+
+        mTile.refreshState();
+        mTestableLooper.processAllMessages();
+
+        assertEquals(Tile.STATE_ACTIVE, mTile.getState().state);
+        assertTrue(mTile.getState().secondaryLabel.toString().endsWith("..."));
+    }
+
+    // Test that the tile cancels countdown if it is clicked when the controller is starting
+    @Test
+    public void testCancelRecording() {
+        when(mController.isStarting()).thenReturn(true);
+        when(mController.isRecording()).thenReturn(false);
+
+        mTile.handleClick();
+
+        verify(mController, times(1)).cancelCountdown();
+    }
+
+    // Test that the tile is active and labeled correctly when the controller is recording
+    @Test
+    public void testIsRecording() {
+        when(mController.isStarting()).thenReturn(false);
+        when(mController.isRecording()).thenReturn(true);
+
+        mTile.refreshState();
+        mTestableLooper.processAllMessages();
+
+        assertEquals(Tile.STATE_ACTIVE, mTile.getState().state);
+        assertTrue(mTile.getState().secondaryLabel.toString().equals(
+                mContext.getString(R.string.quick_settings_screen_record_stop)));
+    }
+
+    // Test that the tile stops the recording if it is clicked when the controller is recording
+    @Test
+    public void testStopRecording() {
+        when(mController.isStarting()).thenReturn(false);
+        when(mController.isRecording()).thenReturn(true);
+
+        mTile.handleClick();
+
+        verify(mController, times(1)).stopRecording();
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingControllerTest.java
new file mode 100644
index 0000000..b877c7f
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingControllerTest.java
@@ -0,0 +1,124 @@
+/*
+ * 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.systemui.screenrecord;
+
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+import static org.mockito.Mockito.verify;
+
+import android.app.PendingIntent;
+import android.os.Looper;
+import android.testing.AndroidTestingRunner;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+/**
+ * Tests for exception handling and  bitmap configuration in adding smart actions to Screenshot
+ * Notification.
+ */
+public class RecordingControllerTest extends SysuiTestCase {
+
+    @Mock
+    RecordingController.RecordingStateChangeCallback mCallback;
+
+    RecordingController mController;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mController = new RecordingController(mContext);
+        mController.addCallback(mCallback);
+    }
+
+    // Test that when a countdown in progress is cancelled, the controller goes from starting to not
+    // starting, and notifies listeners.
+    @Test
+    public void testCancelCountdown() {
+        if (Looper.myLooper() == null) {
+            Looper.prepare();
+        }
+
+        mController.startCountdown(100, 10, null, null);
+
+        assertTrue(mController.isStarting());
+        assertFalse(mController.isRecording());
+
+        mController.cancelCountdown();
+
+        assertFalse(mController.isStarting());
+        assertFalse(mController.isRecording());
+
+        verify(mCallback).onCountdownEnd();
+    }
+
+    // Test that when recording is started, the start intent is sent and listeners are notified.
+    @Test
+    public void testStartRecording() throws PendingIntent.CanceledException {
+        if (Looper.myLooper() == null) {
+            Looper.prepare();
+        }
+
+        PendingIntent startIntent = Mockito.mock(PendingIntent.class);
+        mController.startCountdown(0, 0, startIntent, null);
+
+        verify(mCallback).onCountdownEnd();
+        verify(startIntent).send();
+    }
+
+    // Test that when recording is stopped, the stop intent is sent and listeners are notified.
+    @Test
+    public void testStopRecording() throws PendingIntent.CanceledException {
+        if (Looper.myLooper() == null) {
+            Looper.prepare();
+        }
+
+        PendingIntent startIntent = Mockito.mock(PendingIntent.class);
+        PendingIntent stopIntent = Mockito.mock(PendingIntent.class);
+
+        mController.startCountdown(0, 0, startIntent, stopIntent);
+        mController.stopRecording();
+
+        assertFalse(mController.isStarting());
+        assertFalse(mController.isRecording());
+        verify(stopIntent).send();
+        verify(mCallback).onRecordingEnd();
+    }
+
+    // Test that updating the controller state works and notifies listeners.
+    @Test
+    public void testUpdateState() {
+        mController.updateState(true);
+        assertTrue(mController.isRecording());
+        verify(mCallback).onRecordingStart();
+
+        mController.updateState(false);
+        assertFalse(mController.isRecording());
+        verify(mCallback).onRecordingEnd();
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotStubActivity.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotStubActivity.java
deleted file mode 100644
index 0b871e4..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotStubActivity.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.systemui.screenshot;
-
-import android.app.Activity;
-import android.os.Bundle;
-
-import com.android.systemui.tests.R;
-
-/**
- * A stub activity used in {@link ScreenshotTest}.
- */
-public class ScreenshotStubActivity extends Activity {
-
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.main);
-    }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
index 1d4b4be..581d795 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
@@ -21,6 +21,7 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.clearInvocations;
@@ -124,7 +125,7 @@
         mContext.addMockSystemService(Context.TRUST_SERVICE, mock(TrustManager.class));
         mContext.addMockSystemService(Context.FINGERPRINT_SERVICE, mock(FingerprintManager.class));
 
-        when(mKeyguardUpdateMonitor.isUnlockingWithBiometricAllowed()).thenReturn(true);
+        when(mKeyguardUpdateMonitor.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(true);
         when(mKeyguardUpdateMonitor.isScreenOn()).thenReturn(true);
         when(mKeyguardUpdateMonitor.isUserUnlocked(anyInt())).thenReturn(true);
         when(mIndicationArea.findViewById(R.id.keyguard_indication_text)).thenReturn(mTextView);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManagerTest.kt
index b3d0d22..6388fe1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManagerTest.kt
@@ -63,7 +63,7 @@
                 DeviceConfig.NAMESPACE_SYSTEMUI, NOTIFICATIONS_USE_PEOPLE_FILTERING, "true", false)
 
         assertTrue("People filtering should be enabled", manager!!.isFilteringEnabled())
-        assertTrue("Expecting 3 buckets when people filtering is enabled",
-                manager!!.getNumberOfBuckets() == 3)
+        assertTrue("Expecting 4 buckets when people filtering is enabled",
+                manager!!.getNumberOfBuckets() == 4)
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt
index 8e330c6..f11c42b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt
@@ -32,6 +32,7 @@
 import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager
 import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider
 import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
 import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_ALERTING
 import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_SILENT
 import com.android.systemui.statusbar.phone.NotificationGroupManager
@@ -42,6 +43,7 @@
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.Mockito.mock
+import org.mockito.Mockito.`when` as whenever
 
 @SmallTest
 @RunWith(AndroidTestingRunner::class)
@@ -52,18 +54,20 @@
     }
     private lateinit var personNotificationIdentifier: PeopleNotificationIdentifier
     private lateinit var rankingManager: TestableNotificationRankingManager
+    private lateinit var sectionsManager: NotificationSectionsFeatureManager
 
     @Before
     fun setup() {
         personNotificationIdentifier =
                 mock(PeopleNotificationIdentifier::class.java)
+        sectionsManager = mock(NotificationSectionsFeatureManager::class.java)
         rankingManager = TestableNotificationRankingManager(
                 lazyMedia,
                 mock(NotificationGroupManager::class.java),
                 mock(HeadsUpManager::class.java),
                 mock(NotificationFilter::class.java),
                 mock(NotificationEntryManagerLogger::class.java),
-                mock(NotificationSectionsFeatureManager::class.java),
+                sectionsManager,
                 personNotificationIdentifier,
                 HighPriorityProvider(personNotificationIdentifier)
         )
@@ -145,40 +149,90 @@
     }
 
     @Test
-    fun testSort_importantPeople() {
+    fun testSort_headsUp_trumpsPeople() {
+        whenever(sectionsManager.isFilteringEnabled()).thenReturn(true)
         val aN = Notification.Builder(mContext, "test")
                 .setStyle(Notification.MessagingStyle(""))
                 .build()
-        val aC = NotificationChannel("test", "", IMPORTANCE_DEFAULT)
-        aC.setConversationId("parent", "convo")
         val a = NotificationEntryBuilder()
                 .setImportance(IMPORTANCE_HIGH)
                 .setPkg("pkg")
                 .setOpPkg("pkg")
                 .setTag("tag")
                 .setNotification(aN)
-                .setChannel(aC)
+                .setChannel(NotificationChannel("test", "", IMPORTANCE_DEFAULT))
                 .setUser(mContext.getUser())
                 .setOverrideGroupKey("")
                 .build()
 
+        whenever(personNotificationIdentifier.isImportantPeopleNotification(a.sbn, a.ranking))
+                .thenReturn(true)
+        whenever(personNotificationIdentifier.isPeopleNotification(a.sbn, a.ranking))
+                .thenReturn(true)
+
         val bN = Notification.Builder(mContext, "test")
                 .setStyle(Notification.MessagingStyle(""))
                 .build()
-        val bC = NotificationChannel("test", "", IMPORTANCE_DEFAULT)
-        bC.setConversationId("parent", "convo")
-        bC.setImportantConversation(true)
         val b = NotificationEntryBuilder()
                 .setImportance(IMPORTANCE_HIGH)
                 .setPkg("pkg2")
                 .setOpPkg("pkg2")
                 .setTag("tag")
                 .setNotification(bN)
-                .setChannel(bC)
+                .setChannel(NotificationChannel("test", "", IMPORTANCE_DEFAULT))
                 .setUser(mContext.getUser())
                 .setOverrideGroupKey("")
                 .build()
+        b.row = mock(ExpandableNotificationRow::class.java).also {
+            whenever(it.isHeadsUp).thenReturn(true)
+        }
 
+        whenever(personNotificationIdentifier.isImportantPeopleNotification(a.sbn, a.ranking))
+                .thenReturn(false)
+        whenever(personNotificationIdentifier.isPeopleNotification(a.sbn, a.ranking))
+                .thenReturn(false)
+
+        assertEquals(listOf(b, a), rankingManager.updateRanking(null, listOf(a, b), "test"))
+    }
+
+    @Test
+    fun testSort_importantPeople() {
+        whenever(sectionsManager.isFilteringEnabled()).thenReturn(true)
+        val aN = Notification.Builder(mContext, "test")
+                .setStyle(Notification.MessagingStyle(""))
+                .build()
+        val a = NotificationEntryBuilder()
+                .setImportance(IMPORTANCE_HIGH)
+                .setPkg("pkg")
+                .setOpPkg("pkg")
+                .setTag("tag")
+                .setNotification(aN)
+                .setChannel(NotificationChannel("test", "", IMPORTANCE_DEFAULT))
+                .setUser(mContext.getUser())
+                .setOverrideGroupKey("")
+                .build()
+        whenever(personNotificationIdentifier.isImportantPeopleNotification(a.sbn, a.ranking))
+                .thenReturn(false)
+        whenever(personNotificationIdentifier.isPeopleNotification(a.sbn, a.ranking))
+                .thenReturn(true)
+
+        val bN = Notification.Builder(mContext, "test")
+                .setStyle(Notification.MessagingStyle(""))
+                .build()
+        val b = NotificationEntryBuilder()
+                .setImportance(IMPORTANCE_HIGH)
+                .setPkg("pkg2")
+                .setOpPkg("pkg2")
+                .setTag("tag")
+                .setNotification(bN)
+                .setChannel(NotificationChannel("test", "", IMPORTANCE_DEFAULT))
+                .setUser(mContext.getUser())
+                .setOverrideGroupKey("")
+                .build()
+        whenever(personNotificationIdentifier.isImportantPeopleNotification(a.sbn, a.ranking))
+                .thenReturn(false)
+        whenever(personNotificationIdentifier.isPeopleNotification(a.sbn, a.ranking))
+                .thenReturn(true)
 
         assertEquals(
                 listOf(b, a),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/people/PeopleHubViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/people/PeopleHubViewControllerTest.kt
index 867a9b9..abce8b5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/people/PeopleHubViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/people/PeopleHubViewControllerTest.kt
@@ -43,7 +43,7 @@
 
     @JvmField @Rule val mockito: MockitoRule = MockitoJUnit.rule()
 
-    @Mock private lateinit var mockViewBoundary: PeopleHubSectionFooterViewBoundary
+    @Mock private lateinit var mockViewBoundary: PeopleHubViewBoundary
     @Mock private lateinit var mockActivityStarter: ActivityStarter
 
     @Test
@@ -67,7 +67,7 @@
                 return mockSubscription
             }
         }
-        val adapter = PeopleHubSectionFooterViewAdapterImpl(fakeFactoryDataSource)
+        val adapter = PeopleHubViewAdapterImpl(fakeFactoryDataSource)
 
         adapter.bindView(mockViewBoundary)
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
index 51f214d..abfbcd9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
@@ -45,8 +45,7 @@
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager;
-import com.android.systemui.statusbar.notification.people.PeopleHubSectionFooterViewAdapter;
-import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
+import com.android.systemui.statusbar.notification.people.PeopleHubViewAdapter;
 import com.android.systemui.statusbar.notification.row.ActivatableNotificationViewController;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.dagger.NotificationRowComponent;
@@ -71,7 +70,7 @@
     @Mock private ActivityStarterDelegate mActivityStarterDelegate;
     @Mock private StatusBarStateController mStatusBarStateController;
     @Mock private ConfigurationController mConfigurationController;
-    @Mock private PeopleHubSectionFooterViewAdapter mPeopleHubAdapter;
+    @Mock private PeopleHubViewAdapter mPeopleHubAdapter;
     @Mock private NotificationSectionsFeatureManager mSectionsFeatureManager;
     @Mock private NotificationRowComponent mNotificationRowComponent;
     @Mock private ActivatableNotificationViewController mActivatableNotificationViewController;
@@ -90,18 +89,8 @@
                         mStatusBarStateController,
                         mConfigurationController,
                         mPeopleHubAdapter,
-                        mSectionsFeatureManager,
-                        new NotificationRowComponent.Builder() {
-                    @Override
-                    public NotificationRowComponent.Builder activatableNotificationView(
-                            ActivatableNotificationView view) {
-                        return this;
-                    }
-
-                    @Override
-                    public NotificationRowComponent build() {
-                        return mNotificationRowComponent;
-                    }});
+                        mSectionsFeatureManager
+                );
         // Required in order for the header inflation to work properly
         when(mNssl.generateLayoutParams(any(AttributeSet.class)))
                 .thenReturn(new ViewGroup.LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
index 769b774..813923d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
@@ -97,7 +97,8 @@
         when(mStatusBarKeyguardViewManager.isShowing()).thenReturn(true);
         when(mUpdateMonitor.isDeviceInteractive()).thenReturn(true);
         when(mKeyguardStateController.isFaceAuthEnabled()).thenReturn(true);
-        when(mKeyguardBypassController.onBiometricAuthenticated(any())).thenReturn(true);
+        when(mKeyguardBypassController.onBiometricAuthenticated(any(), anyBoolean()))
+                .thenReturn(true);
         when(mKeyguardBypassController.canPlaySubtleWindowAnimations()).thenReturn(true);
         mContext.addMockSystemService(PowerManager.class, mPowerManager);
         mDependency.injectTestDependency(NotificationMediaManager.class, mMediaManager);
@@ -112,11 +113,28 @@
 
     @Test
     public void onBiometricAuthenticated_whenFingerprintAndBiometricsDisallowed_showBouncer() {
+        when(mUpdateMonitor.isUnlockingWithBiometricAllowed(true /* isStrongBiometric */))
+                .thenReturn(false);
         mBiometricUnlockController.onBiometricAuthenticated(UserHandle.USER_CURRENT,
-                BiometricSourceType.FINGERPRINT);
+                BiometricSourceType.FINGERPRINT, true /* isStrongBiometric */);
         verify(mStatusBarKeyguardViewManager).showBouncer(eq(false));
         verify(mShadeController).animateCollapsePanels(anyInt(), anyBoolean(), anyBoolean(),
                 anyFloat());
+        assertThat(mBiometricUnlockController.getMode())
+                .isEqualTo(BiometricUnlockController.MODE_SHOW_BOUNCER);
+    }
+
+    @Test
+    public void onBiometricAuthenticated_whenFingerprint_nonStrongBioDisallowed_showBouncer() {
+        when(mUpdateMonitor.isUnlockingWithBiometricAllowed(false /* isStrongBiometric */))
+                .thenReturn(false);
+        mBiometricUnlockController.onBiometricAuthenticated(UserHandle.USER_CURRENT,
+                BiometricSourceType.FINGERPRINT, false /* isStrongBiometric */);
+        verify(mStatusBarKeyguardViewManager).showBouncer(eq(false));
+        verify(mShadeController).animateCollapsePanels(anyInt(), anyBoolean(), anyBoolean(),
+                anyFloat());
+        assertThat(mBiometricUnlockController.getMode())
+                .isEqualTo(BiometricUnlockController.MODE_SHOW_BOUNCER);
     }
 
     @Test
@@ -124,44 +142,60 @@
         reset(mUpdateMonitor);
         reset(mStatusBarKeyguardViewManager);
         when(mStatusBarKeyguardViewManager.isShowing()).thenReturn(true);
-        when(mUpdateMonitor.isUnlockingWithBiometricAllowed()).thenReturn(true);
+        when(mUpdateMonitor.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(true);
         when(mDozeScrimController.isPulsing()).thenReturn(true);
+        // the value of isStrongBiometric doesn't matter here since we only care about the returned
+        // value of isUnlockingWithBiometricAllowed()
         mBiometricUnlockController.onBiometricAuthenticated(UserHandle.USER_CURRENT,
-                BiometricSourceType.FINGERPRINT);
+                BiometricSourceType.FINGERPRINT, true /* isStrongBiometric */);
 
         verify(mKeyguardViewMediator).onWakeAndUnlocking();
+        assertThat(mBiometricUnlockController.getMode())
+                .isEqualTo(BiometricUnlockController.MODE_WAKE_AND_UNLOCK_PULSING);
     }
 
     @Test
     public void onBiometricAuthenticated_whenFingerprint_dismissKeyguard() {
-        when(mUpdateMonitor.isUnlockingWithBiometricAllowed()).thenReturn(true);
+        when(mUpdateMonitor.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(true);
+        // the value of isStrongBiometric doesn't matter here since we only care about the returned
+        // value of isUnlockingWithBiometricAllowed()
         mBiometricUnlockController.onBiometricAuthenticated(UserHandle.USER_CURRENT,
-                BiometricSourceType.FINGERPRINT);
+                BiometricSourceType.FINGERPRINT, true /* isStrongBiometric */);
 
         verify(mStatusBarKeyguardViewManager, never()).showBouncer(anyBoolean());
         verify(mShadeController).animateCollapsePanels(anyInt(), anyBoolean(), anyBoolean(),
                 anyFloat());
+        assertThat(mBiometricUnlockController.getMode())
+                .isEqualTo(BiometricUnlockController.MODE_UNLOCK_COLLAPSING);
     }
 
     @Test
     public void onBiometricAuthenticated_whenFingerprintOnBouncer_dismissBouncer() {
-        when(mUpdateMonitor.isUnlockingWithBiometricAllowed()).thenReturn(true);
+        when(mUpdateMonitor.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(true);
         when(mStatusBarKeyguardViewManager.bouncerIsOrWillBeShowing()).thenReturn(true);
+        // the value of isStrongBiometric doesn't matter here since we only care about the returned
+        // value of isUnlockingWithBiometricAllowed()
         mBiometricUnlockController.onBiometricAuthenticated(UserHandle.USER_CURRENT,
-                BiometricSourceType.FINGERPRINT);
+                BiometricSourceType.FINGERPRINT, true /* isStrongBiometric */);
 
         verify(mStatusBarKeyguardViewManager).notifyKeyguardAuthenticated(eq(false));
+        assertThat(mBiometricUnlockController.getMode())
+                .isEqualTo(BiometricUnlockController.MODE_DISMISS_BOUNCER);
     }
 
     @Test
     public void onBiometricAuthenticated_whenFace_dontDismissKeyguard() {
-        when(mUpdateMonitor.isUnlockingWithBiometricAllowed()).thenReturn(true);
+        when(mUpdateMonitor.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(true);
+        // the value of isStrongBiometric doesn't matter here since we only care about the returned
+        // value of isUnlockingWithBiometricAllowed()
         mBiometricUnlockController.onBiometricAuthenticated(UserHandle.USER_CURRENT,
-                BiometricSourceType.FACE);
+                BiometricSourceType.FACE, true /* isStrongBiometric */);
 
         verify(mShadeController, never()).animateCollapsePanels(anyInt(), anyBoolean(),
                 anyBoolean(), anyFloat());
         verify(mStatusBarKeyguardViewManager, never()).notifyKeyguardAuthenticated(anyBoolean());
+        assertThat(mBiometricUnlockController.getMode())
+                .isEqualTo(BiometricUnlockController.MODE_NONE);
     }
 
     @Test
@@ -169,13 +203,17 @@
         when(mKeyguardBypassController.getBypassEnabled()).thenReturn(true);
         mBiometricUnlockController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
 
-        when(mUpdateMonitor.isUnlockingWithBiometricAllowed()).thenReturn(true);
+        when(mUpdateMonitor.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(true);
+        // the value of isStrongBiometric doesn't matter here since we only care about the returned
+        // value of isUnlockingWithBiometricAllowed()
         mBiometricUnlockController.onBiometricAuthenticated(UserHandle.USER_CURRENT,
-                BiometricSourceType.FACE);
+                BiometricSourceType.FACE, true /* isStrongBiometric */);
 
         verify(mShadeController, never()).animateCollapsePanels(anyInt(), anyBoolean(),
                 anyBoolean(), anyFloat());
         verify(mStatusBarKeyguardViewManager).notifyKeyguardAuthenticated(eq(false));
+        assertThat(mBiometricUnlockController.getMode())
+                .isEqualTo(BiometricUnlockController.MODE_UNLOCK_FADING);
     }
 
     @Test
@@ -184,9 +222,11 @@
         when(mKeyguardBypassController.getBypassEnabled()).thenReturn(true);
         mBiometricUnlockController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
 
-        when(mUpdateMonitor.isUnlockingWithBiometricAllowed()).thenReturn(false);
+        when(mUpdateMonitor.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(false);
+        // the value of isStrongBiometric doesn't matter here since we only care about the returned
+        // value of isUnlockingWithBiometricAllowed()
         mBiometricUnlockController.onBiometricAuthenticated(UserHandle.USER_CURRENT,
-                BiometricSourceType.FACE);
+                BiometricSourceType.FACE, true /* isStrongBiometric */);
 
         // Wake up before showing the bouncer
         verify(mStatusBarKeyguardViewManager, never()).showBouncer(eq(false));
@@ -202,9 +242,11 @@
         reset(mUpdateMonitor);
         mBiometricUnlockController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
 
-        when(mUpdateMonitor.isUnlockingWithBiometricAllowed()).thenReturn(false);
+        when(mUpdateMonitor.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(false);
+        // the value of isStrongBiometric doesn't matter here since we only care about the returned
+        // value of isUnlockingWithBiometricAllowed()
         mBiometricUnlockController.onBiometricAuthenticated(UserHandle.USER_CURRENT,
-                BiometricSourceType.FACE);
+                BiometricSourceType.FACE, true /* isStrongBiometric */);
 
         verify(mStatusBarKeyguardViewManager, never()).showBouncer(anyBoolean());
         verify(mShadeController, never()).animateCollapsePanels(anyInt(), anyBoolean(),
@@ -215,23 +257,30 @@
 
     @Test
     public void onBiometricAuthenticated_whenFaceOnBouncer_dismissBouncer() {
-        when(mUpdateMonitor.isUnlockingWithBiometricAllowed()).thenReturn(true);
+        when(mUpdateMonitor.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(true);
         when(mStatusBarKeyguardViewManager.bouncerIsOrWillBeShowing()).thenReturn(true);
+        // the value of isStrongBiometric doesn't matter here since we only care about the returned
+        // value of isUnlockingWithBiometricAllowed()
         mBiometricUnlockController.onBiometricAuthenticated(UserHandle.USER_CURRENT,
-                BiometricSourceType.FACE);
+                BiometricSourceType.FACE, true /* isStrongBiometric */);
 
         verify(mStatusBarKeyguardViewManager).notifyKeyguardAuthenticated(eq(false));
+        assertThat(mBiometricUnlockController.getMode())
+                .isEqualTo(BiometricUnlockController.MODE_DISMISS_BOUNCER);
     }
 
     @Test
     public void onBiometricAuthenticated_whenBypassOnBouncer_dismissBouncer() {
         reset(mKeyguardBypassController);
-        when(mUpdateMonitor.isUnlockingWithBiometricAllowed()).thenReturn(true);
+        when(mUpdateMonitor.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(true);
         when(mKeyguardBypassController.getBypassEnabled()).thenReturn(true);
-        when(mKeyguardBypassController.onBiometricAuthenticated(any())).thenReturn(true);
+        when(mKeyguardBypassController.onBiometricAuthenticated(any(), anyBoolean()))
+                .thenReturn(true);
         when(mStatusBarKeyguardViewManager.bouncerIsOrWillBeShowing()).thenReturn(true);
+        // the value of isStrongBiometric doesn't matter here since we only care about the returned
+        // value of isUnlockingWithBiometricAllowed()
         mBiometricUnlockController.onBiometricAuthenticated(UserHandle.USER_CURRENT,
-                BiometricSourceType.FACE);
+                BiometricSourceType.FACE, true /* isStrongBiometric */);
 
         verify(mStatusBarKeyguardViewManager).notifyKeyguardAuthenticated(eq(false));
         assertThat(mBiometricUnlockController.getMode())
@@ -240,11 +289,13 @@
 
     @Test
     public void onBiometricAuthenticated_whenBypassOnBouncer_respectsCanPlaySubtleAnim() {
-        when(mUpdateMonitor.isUnlockingWithBiometricAllowed()).thenReturn(true);
+        when(mUpdateMonitor.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(true);
         when(mKeyguardBypassController.getBypassEnabled()).thenReturn(true);
         when(mStatusBarKeyguardViewManager.bouncerIsOrWillBeShowing()).thenReturn(true);
+        // the value of isStrongBiometric doesn't matter here since we only care about the returned
+        // value of isUnlockingWithBiometricAllowed()
         mBiometricUnlockController.onBiometricAuthenticated(UserHandle.USER_CURRENT,
-                BiometricSourceType.FACE);
+                BiometricSourceType.FACE, true /* isStrongBiometric */);
 
         verify(mStatusBarKeyguardViewManager).notifyKeyguardAuthenticated(eq(false));
         assertThat(mBiometricUnlockController.getMode())
@@ -255,13 +306,17 @@
     public void onBiometricAuthenticated_whenFaceAndPulsing_dontDismissKeyguard() {
         reset(mUpdateMonitor);
         reset(mStatusBarKeyguardViewManager);
-        when(mUpdateMonitor.isUnlockingWithBiometricAllowed()).thenReturn(true);
+        when(mUpdateMonitor.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(true);
         when(mDozeScrimController.isPulsing()).thenReturn(true);
+        // the value of isStrongBiometric doesn't matter here since we only care about the returned
+        // value of isUnlockingWithBiometricAllowed()
         mBiometricUnlockController.onBiometricAuthenticated(UserHandle.USER_CURRENT,
-                BiometricSourceType.FACE);
+                BiometricSourceType.FACE, true /* isStrongBiometric */);
 
         verify(mShadeController, never()).animateCollapsePanels(anyInt(), anyBoolean(),
                 anyBoolean(), anyFloat());
+        assertThat(mBiometricUnlockController.getMode())
+                .isEqualTo(BiometricUnlockController.MODE_ONLY_WAKE);
     }
 
     @Test
@@ -270,8 +325,10 @@
         mBiometricUnlockController.onFinishedGoingToSleep(-1);
         verify(mHandler, never()).post(any());
 
+        // the value of isStrongBiometric doesn't matter here since we only care about the returned
+        // value of isUnlockingWithBiometricAllowed()
         mBiometricUnlockController.onBiometricAuthenticated(1 /* userId */,
-                BiometricSourceType.FACE);
+                BiometricSourceType.FACE, true /* isStrongBiometric */);
         mBiometricUnlockController.onFinishedGoingToSleep(-1);
         verify(mHandler).post(any());
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index 2e6fbe7..408dfc0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -36,7 +36,6 @@
 
 import android.animation.Animator;
 import android.app.AlarmManager;
-import android.content.res.Resources;
 import android.graphics.Color;
 import android.os.Handler;
 import android.testing.AndroidTestingRunner;
@@ -91,8 +90,6 @@
     @Mock
     LightBarController mLightBarController;
     @Mock
-    Resources mResources;
-    @Mock
     DelayedWakeLock.Builder mDelayedWakeLockBuilder;
     @Mock
     private DelayedWakeLock mWakeLock;
@@ -216,8 +213,7 @@
         when(mDockManager.isDocked()).thenReturn(false);
 
         mScrimController = new ScrimController(mLightBarController,
-                mDozeParamenters, mAlarmManager, mKeyguardStateController,
-                mResources, mDelayedWakeLockBuilder,
+                mDozeParamenters, mAlarmManager, mKeyguardStateController, mDelayedWakeLockBuilder,
                 new FakeHandler(mLooper.getLooper()), mKeyguardUpdateMonitor, mSysuiColorExtractor,
                 mDockManager);
         mScrimController.setScrimVisibleListener(visible -> mScrimVisibility = visible);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/magnetictarget/MagnetizedObjectTest.kt b/packages/SystemUI/tests/src/com/android/systemui/util/magnetictarget/MagnetizedObjectTest.kt
new file mode 100644
index 0000000..f1672b1
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/magnetictarget/MagnetizedObjectTest.kt
@@ -0,0 +1,442 @@
+/*
+ * 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.systemui.util.magnetictarget
+
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import android.view.MotionEvent
+import android.view.View
+import androidx.dynamicanimation.animation.FloatPropertyCompat
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.util.animation.PhysicsAnimatorTestUtils
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertTrue
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers
+import org.mockito.ArgumentMatchers.anyFloat
+import org.mockito.Mockito
+import org.mockito.Mockito.`when`
+import org.mockito.Mockito.doAnswer
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.never
+import org.mockito.Mockito.times
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.verifyNoMoreInteractions
+
+@TestableLooper.RunWithLooper
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class MagnetizedObjectTest : SysuiTestCase() {
+    /** Incrementing value for fake MotionEvent timestamps. */
+    private var time = 0L
+
+    /** Value to add to each new MotionEvent's timestamp. */
+    private var timeStep = 100
+
+    private val underlyingObject = this
+
+    private lateinit var targetView: View
+
+    private val targetSize = 200
+    private val targetCenterX = 500
+    private val targetCenterY = 900
+    private val magneticFieldRadius = 200
+
+    private var objectX = 0f
+    private var objectY = 0f
+    private val objectSize = 50f
+
+    private lateinit var magneticTarget: MagnetizedObject.MagneticTarget
+    private lateinit var magnetizedObject: MagnetizedObject<*>
+    private lateinit var magnetListener: MagnetizedObject.MagnetListener
+
+    private val xProperty = object : FloatPropertyCompat<MagnetizedObjectTest>("") {
+        override fun setValue(target: MagnetizedObjectTest?, value: Float) {
+            objectX = value
+        }
+        override fun getValue(target: MagnetizedObjectTest?): Float {
+            return objectX
+        }
+    }
+
+    private val yProperty = object : FloatPropertyCompat<MagnetizedObjectTest>("") {
+        override fun setValue(target: MagnetizedObjectTest?, value: Float) {
+            objectY = value
+        }
+
+        override fun getValue(target: MagnetizedObjectTest?): Float {
+            return objectY
+        }
+    }
+
+    @Before
+    fun setup() {
+        PhysicsAnimatorTestUtils.prepareForTest()
+
+        // Mock the view since a real view's getLocationOnScreen() won't work unless it's attached
+        // to a real window (it'll always return x = 0, y = 0).
+        targetView = mock(View::class.java)
+        `when`(targetView.context).thenReturn(context)
+
+        // The mock target view will pretend that it's 200x200, and at (400, 800). This means it's
+        // occupying the bounds (400, 800, 600, 1000) and it has a center of (500, 900).
+        `when`(targetView.width).thenReturn(targetSize)  // width = 200
+        `when`(targetView.height).thenReturn(targetSize) // height = 200
+        doAnswer { invocation ->
+            (invocation.arguments[0] as IntArray).also { location ->
+                // Return the top left of the target.
+                location[0] = targetCenterX - targetSize / 2 // x = 400
+                location[1] = targetCenterY - targetSize / 2 // y = 800
+            }
+        }.`when`(targetView).getLocationOnScreen(ArgumentMatchers.any())
+        `when`(targetView.context).thenReturn(context)
+
+        magneticTarget = MagnetizedObject.MagneticTarget(targetView, magneticFieldRadius)
+
+        magnetListener = mock(MagnetizedObject.MagnetListener::class.java)
+        magnetizedObject = object : MagnetizedObject<MagnetizedObjectTest>(
+                context, underlyingObject, xProperty, yProperty) {
+            override fun getWidth(underlyingObject: MagnetizedObjectTest): Float {
+                return objectSize
+            }
+
+            override fun getHeight(underlyingObject: MagnetizedObjectTest): Float {
+                return objectSize
+            }
+
+            override fun getLocationOnScreen(
+                underlyingObject: MagnetizedObjectTest,
+                loc: IntArray
+            ) {
+                loc[0] = objectX.toInt()
+                loc[1] = objectY.toInt() }
+        }
+
+        magnetizedObject.magnetListener = magnetListener
+        magnetizedObject.addTarget(magneticTarget)
+
+        timeStep = 100
+    }
+
+    @Test
+    fun testMotionEventConsumption() {
+        // Start at (0, 0). No magnetic field here.
+        assertFalse(magnetizedObject.maybeConsumeMotionEvent(getMotionEvent(
+                x = 0, y = 0, action = MotionEvent.ACTION_DOWN)))
+
+        // Move to (400, 400), which is solidly outside the magnetic field.
+        assertFalse(magnetizedObject.maybeConsumeMotionEvent(getMotionEvent(
+                x = 200, y = 200)))
+
+        // Move to (305, 705). This would be in the magnetic field radius if magnetic fields were
+        // square. It's not, because they're not.
+        assertFalse(magnetizedObject.maybeConsumeMotionEvent(getMotionEvent(
+                x = targetCenterX - magneticFieldRadius + 5,
+                y = targetCenterY - magneticFieldRadius + 5)))
+
+        // Move to (400, 800). That's solidly in the radius so the magnetic target should begin
+        // consuming events.
+        assertTrue(magnetizedObject.maybeConsumeMotionEvent(getMotionEvent(
+                x = targetCenterX - 100,
+                y = targetCenterY - 100)))
+
+        // Release at (400, 800). Since we're in the magnetic target, it should return true and
+        // consume the ACTION_UP.
+        assertTrue(magnetizedObject.maybeConsumeMotionEvent(getMotionEvent(
+                x = 400, y = 800, action = MotionEvent.ACTION_UP)))
+
+        // ACTION_DOWN outside the field.
+        assertFalse(magnetizedObject.maybeConsumeMotionEvent(getMotionEvent(
+                x = 200, y = 200, action = MotionEvent.ACTION_DOWN)))
+
+        // Move to the center. We absolutely should consume events there.
+        assertTrue(magnetizedObject.maybeConsumeMotionEvent(getMotionEvent(
+                x = targetCenterX,
+                y = targetCenterY)))
+
+        // Drag out to (0, 0) and we should be returning false again.
+        assertFalse(magnetizedObject.maybeConsumeMotionEvent(getMotionEvent(
+                x = 0, y = 0)))
+
+        // The ACTION_UP event shouldn't be consumed either since it's outside the field.
+        assertFalse(magnetizedObject.maybeConsumeMotionEvent(getMotionEvent(
+                x = 0, y = 0, action = MotionEvent.ACTION_UP)))
+    }
+
+    @Test
+    fun testMotionEventConsumption_downInMagneticField() {
+        // We should consume DOWN events if they occur in the field.
+        assertTrue(magnetizedObject.maybeConsumeMotionEvent(getMotionEvent(
+                x = targetCenterX, y = targetCenterY, action = MotionEvent.ACTION_DOWN)))
+    }
+
+    @Test
+    fun testMoveIntoAroundAndOutOfMagneticField() {
+        // Move around but don't touch the magnetic field.
+        dispatchMotionEvents(
+                getMotionEvent(x = 0, y = 0, action = MotionEvent.ACTION_DOWN),
+                getMotionEvent(x = 100, y = 100),
+                getMotionEvent(x = 200, y = 200))
+
+        // You can't become unstuck if you were never stuck in the first place.
+        verify(magnetListener, never()).onStuckToTarget(magneticTarget)
+        verify(magnetListener, never()).onUnstuckFromTarget(
+                eq(magneticTarget), ArgumentMatchers.anyFloat(), ArgumentMatchers.anyFloat(),
+                eq(false))
+
+        // Move into and then around inside the magnetic field.
+        dispatchMotionEvents(
+                getMotionEvent(x = targetCenterX - 100, y = targetCenterY - 100),
+                getMotionEvent(x = targetCenterX, y = targetCenterY),
+                getMotionEvent(x = targetCenterX + 100, y = targetCenterY + 100))
+
+        // We should only have received one call to onStuckToTarget and none to unstuck.
+        verify(magnetListener, times(1)).onStuckToTarget(magneticTarget)
+        verify(magnetListener, never()).onUnstuckFromTarget(
+                eq(magneticTarget), ArgumentMatchers.anyFloat(), ArgumentMatchers.anyFloat(),
+                eq(false))
+
+        // Move out of the field and then release.
+        dispatchMotionEvents(
+                getMotionEvent(x = 100, y = 100),
+                getMotionEvent(x = 100, y = 100, action = MotionEvent.ACTION_UP))
+
+        // We should have received one unstuck call and no more stuck calls. We also should never
+        // have received an onReleasedInTarget call.
+        verify(magnetListener, times(1)).onUnstuckFromTarget(
+                eq(magneticTarget), ArgumentMatchers.anyFloat(), ArgumentMatchers.anyFloat(),
+                eq(false))
+        verifyNoMoreInteractions(magnetListener)
+    }
+
+    @Test
+    fun testMoveIntoOutOfAndBackIntoMagneticField() {
+        // Move into the field
+        dispatchMotionEvents(
+                getMotionEvent(
+                        x = targetCenterX - magneticFieldRadius,
+                        y = targetCenterY - magneticFieldRadius,
+                        action = MotionEvent.ACTION_DOWN),
+                getMotionEvent(
+                        x = targetCenterX, y = targetCenterY))
+
+        verify(magnetListener, times(1)).onStuckToTarget(magneticTarget)
+        verify(magnetListener, never()).onReleasedInTarget(magneticTarget)
+
+        // Move back out.
+        dispatchMotionEvents(
+                getMotionEvent(
+                        x = targetCenterX - magneticFieldRadius,
+                        y = targetCenterY - magneticFieldRadius))
+
+        verify(magnetListener, times(1)).onUnstuckFromTarget(
+                eq(magneticTarget), ArgumentMatchers.anyFloat(), ArgumentMatchers.anyFloat(),
+                eq(false))
+        verify(magnetListener, never()).onReleasedInTarget(magneticTarget)
+
+        // Move in again and release in the magnetic field.
+        dispatchMotionEvents(
+                getMotionEvent(x = targetCenterX - 100, y = targetCenterY - 100),
+                getMotionEvent(x = targetCenterX + 50, y = targetCenterY + 50),
+                getMotionEvent(x = targetCenterX, y = targetCenterY),
+                getMotionEvent(
+                        x = targetCenterX, y = targetCenterY, action = MotionEvent.ACTION_UP))
+
+        verify(magnetListener, times(2)).onStuckToTarget(magneticTarget)
+        verify(magnetListener).onReleasedInTarget(magneticTarget)
+        verifyNoMoreInteractions(magnetListener)
+    }
+
+    @Test
+    fun testFlingTowardsTarget_towardsTarget() {
+        timeStep = 10
+
+        // Forcefully fling the object towards the target (but never touch the magnetic field).
+        dispatchMotionEvents(
+                getMotionEvent(
+                        x = targetCenterX,
+                        y = 0,
+                        action = MotionEvent.ACTION_DOWN),
+                getMotionEvent(
+                        x = targetCenterX,
+                        y = targetCenterY / 2),
+                getMotionEvent(
+                        x = targetCenterX,
+                        y = targetCenterY - magneticFieldRadius * 2,
+                        action = MotionEvent.ACTION_UP))
+
+        // Nevertheless it should have ended up stuck to the target.
+        verify(magnetListener, times(1)).onStuckToTarget(magneticTarget)
+    }
+
+    @Test
+    fun testFlingTowardsTarget_towardsButTooSlow() {
+        // Very, very slowly fling the object towards the target (but never touch the magnetic
+        // field). This value is only used to create MotionEvent timestamps, it will not block the
+        // test for 10 seconds.
+        timeStep = 10000
+        dispatchMotionEvents(
+                getMotionEvent(
+                        x = targetCenterX,
+                        y = 0,
+                        action = MotionEvent.ACTION_DOWN),
+                getMotionEvent(
+                        x = targetCenterX,
+                        y = targetCenterY / 2),
+                getMotionEvent(
+                        x = targetCenterX,
+                        y = targetCenterY - magneticFieldRadius * 2,
+                        action = MotionEvent.ACTION_UP))
+
+        // No sticking should have occurred.
+        verifyNoMoreInteractions(magnetListener)
+    }
+
+    @Test
+    fun testFlingTowardsTarget_missTarget() {
+        timeStep = 10
+        // Forcefully fling the object down, but not towards the target.
+        dispatchMotionEvents(
+                getMotionEvent(
+                        x = 0,
+                        y = 0,
+                        action = MotionEvent.ACTION_DOWN),
+                getMotionEvent(
+                        x = 0,
+                        y = targetCenterY / 2),
+                getMotionEvent(
+                        x = 0,
+                        y = targetCenterY - magneticFieldRadius * 2,
+                        action = MotionEvent.ACTION_UP))
+
+        verifyNoMoreInteractions(magnetListener)
+    }
+
+    @Test
+    fun testMagnetAnimation() {
+        // Make sure the object starts at (0, 0).
+        assertEquals(0f, objectX)
+        assertEquals(0f, objectY)
+
+        // Trigger the magnet animation, and block the test until it ends.
+        PhysicsAnimatorTestUtils.setAllAnimationsBlock(true)
+        magnetizedObject.maybeConsumeMotionEvent(getMotionEvent(
+                x = targetCenterX,
+                y = targetCenterY,
+                action = MotionEvent.ACTION_DOWN))
+
+        // The object's (top-left) position should now position it centered over the target.
+        assertEquals(targetCenterX - objectSize / 2, objectX)
+        assertEquals(targetCenterY - objectSize / 2, objectY)
+    }
+
+    @Test
+    fun testMultipleTargets() {
+        val secondMagneticTarget = getSecondMagneticTarget()
+
+        // Drag into the second target.
+        dispatchMotionEvents(
+                getMotionEvent(x = 0, y = 0, action = MotionEvent.ACTION_DOWN),
+                getMotionEvent(x = 100, y = 900))
+
+        // Verify that we received an onStuck for the second target, and no others.
+        verify(magnetListener).onStuckToTarget(secondMagneticTarget)
+        verifyNoMoreInteractions(magnetListener)
+
+        // Drag into the original target.
+        dispatchMotionEvents(
+                getMotionEvent(x = 0, y = 0),
+                getMotionEvent(x = 500, y = 900))
+
+        // We should have unstuck from the second one and stuck into the original one.
+        verify(magnetListener).onUnstuckFromTarget(
+                eq(secondMagneticTarget), anyFloat(), anyFloat(), eq(false))
+        verify(magnetListener).onStuckToTarget(magneticTarget)
+        verifyNoMoreInteractions(magnetListener)
+    }
+
+    @Test
+    fun testMultipleTargets_flingIntoSecond() {
+        val secondMagneticTarget = getSecondMagneticTarget()
+
+        timeStep = 10
+
+        // Fling towards the second target.
+        dispatchMotionEvents(
+                getMotionEvent(x = 100, y = 0, action = MotionEvent.ACTION_DOWN),
+                getMotionEvent(x = 100, y = 350),
+                getMotionEvent(x = 100, y = 650, action = MotionEvent.ACTION_UP))
+
+        // Verify that we received an onStuck for the second target.
+        verify(magnetListener).onStuckToTarget(secondMagneticTarget)
+
+        // Fling towards the first target.
+        dispatchMotionEvents(
+                getMotionEvent(x = 300, y = 0, action = MotionEvent.ACTION_DOWN),
+                getMotionEvent(x = 400, y = 350),
+                getMotionEvent(x = 500, y = 650, action = MotionEvent.ACTION_UP))
+
+        // Verify that we received onStuck for the original target.
+        verify(magnetListener).onStuckToTarget(magneticTarget)
+    }
+
+    private fun getSecondMagneticTarget(): MagnetizedObject.MagneticTarget {
+        // The first target view is at bounds (400, 800, 600, 1000) and it has a center of
+        // (500, 900). We'll add a second one at bounds (0, 800, 200, 1000) with center (100, 900).
+        val secondTargetView = mock(View::class.java)
+        var secondTargetCenterX = 100
+        var secondTargetCenterY = 900
+
+        `when`(secondTargetView.context).thenReturn(context)
+        `when`(secondTargetView.width).thenReturn(targetSize)  // width = 200
+        `when`(secondTargetView.height).thenReturn(targetSize) // height = 200
+        doAnswer { invocation ->
+            (invocation.arguments[0] as IntArray).also { location ->
+                // Return the top left of the target.
+                location[0] = secondTargetCenterX - targetSize / 2 // x = 0
+                location[1] = secondTargetCenterY - targetSize / 2 // y = 800
+            }
+        }.`when`(secondTargetView).getLocationOnScreen(ArgumentMatchers.any())
+
+        return magnetizedObject.addTarget(secondTargetView, magneticFieldRadius)
+    }
+
+    /**
+     * Return a MotionEvent at the given coordinates, with the given action (or MOVE by default).
+     * The event's time fields will be incremented by 10ms each time this is called, so tha
+     * VelocityTracker works.
+     */
+    private fun getMotionEvent(
+        x: Int,
+        y: Int,
+        action: Int = MotionEvent.ACTION_MOVE
+    ): MotionEvent {
+        return MotionEvent.obtain(time, time, action, x.toFloat(), y.toFloat(), 0)
+                .also { time += timeStep }
+    }
+
+    /** Dispatch all of the provided events to the target view. */
+    private fun dispatchMotionEvents(vararg events: MotionEvent) {
+        events.forEach { magnetizedObject.maybeConsumeMotionEvent(it) }
+    }
+
+    /** Prevents Kotlin from being mad that eq() is nullable. */
+    private fun <T> eq(value: T): T = Mockito.eq(value) ?: value
+}
\ No newline at end of file
diff --git a/packages/Tethering/TEST_MAPPING b/packages/Tethering/TEST_MAPPING
new file mode 100644
index 0000000..73254cd
--- /dev/null
+++ b/packages/Tethering/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "postsubmit": [
+    {
+      "name": "TetheringTests"
+    }
+  ]
+}
diff --git a/packages/Tethering/common/TetheringLib/Android.bp b/packages/Tethering/common/TetheringLib/Android.bp
index cb0de7a..1a3d5b6 100644
--- a/packages/Tethering/common/TetheringLib/Android.bp
+++ b/packages/Tethering/common/TetheringLib/Android.bp
@@ -83,7 +83,6 @@
     name: "framework-tethering-stubs",
     srcs: [":framework-tethering-stubs-sources"],
     libs: ["framework-all"],
-    static_libs: ["tethering-aidl-interfaces-java"],
     sdk_version: "core_platform",
 }
 
diff --git a/packages/Tethering/common/TetheringLib/src/android/net/TetheringConstants.java b/packages/Tethering/common/TetheringLib/src/android/net/TetheringConstants.java
index df87ac9..a18f5da 100644
--- a/packages/Tethering/common/TetheringLib/src/android/net/TetheringConstants.java
+++ b/packages/Tethering/common/TetheringLib/src/android/net/TetheringConstants.java
@@ -33,6 +33,9 @@
  */
 @SystemApi(client = MODULE_LIBRARIES)
 public class TetheringConstants {
+    /** An explicit private class to avoid exposing constructor.*/
+    private TetheringConstants() { }
+
     /**
      * Extra used for communicating with the TetherService. Includes the type of tethering to
      * enable if any.
diff --git a/packages/Tethering/src/android/net/ip/IpServer.java b/packages/Tethering/src/android/net/ip/IpServer.java
index b4d49c0..3acc766 100644
--- a/packages/Tethering/src/android/net/ip/IpServer.java
+++ b/packages/Tethering/src/android/net/ip/IpServer.java
@@ -40,12 +40,14 @@
 import android.net.dhcp.DhcpServingParamsParcelExt;
 import android.net.dhcp.IDhcpLeaseCallbacks;
 import android.net.dhcp.IDhcpServer;
+import android.net.ip.IpNeighborMonitor.NeighborEvent;
 import android.net.ip.RouterAdvertisementDaemon.RaParams;
 import android.net.shared.NetdUtils;
 import android.net.shared.RouteUtils;
 import android.net.util.InterfaceParams;
 import android.net.util.InterfaceSet;
 import android.net.util.SharedLog;
+import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
 import android.os.RemoteException;
@@ -59,14 +61,17 @@
 import com.android.internal.util.State;
 import com.android.internal.util.StateMachine;
 
+import java.io.IOException;
 import java.net.Inet4Address;
 import java.net.Inet6Address;
 import java.net.InetAddress;
+import java.net.NetworkInterface;
 import java.net.UnknownHostException;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashSet;
+import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Objects;
 import java.util.Random;
@@ -149,6 +154,12 @@
 
     /** Capture IpServer dependencies, for injection. */
     public abstract static class Dependencies {
+        /** Create an IpNeighborMonitor to be used by this IpServer */
+        public IpNeighborMonitor getIpNeighborMonitor(Handler handler, SharedLog log,
+                IpNeighborMonitor.NeighborEventConsumer consumer) {
+            return new IpNeighborMonitor(handler, log, consumer);
+        }
+
         /** Create a RouterAdvertisementDaemon instance to be used by IpServer.*/
         public RouterAdvertisementDaemon getRouterAdvertisementDaemon(InterfaceParams ifParams) {
             return new RouterAdvertisementDaemon(ifParams);
@@ -159,6 +170,15 @@
             return InterfaceParams.getByName(ifName);
         }
 
+        /** Get |ifName|'s interface index. */
+        public int getIfindex(String ifName) {
+            try {
+                return NetworkInterface.getByName(ifName).getIndex();
+            } catch (IOException | NullPointerException e) {
+                Log.e(TAG, "Can't determine interface index for interface " + ifName);
+                return 0;
+            }
+        }
         /** Create a DhcpServer instance to be used by IpServer. */
         public abstract void makeDhcpServer(String ifName, DhcpServingParamsParcel params,
                 DhcpServerCallbacks cb);
@@ -184,6 +204,8 @@
     public static final int CMD_TETHER_CONNECTION_CHANGED   = BASE_IPSERVER + 9;
     // new IPv6 tethering parameters need to be processed
     public static final int CMD_IPV6_TETHER_UPDATE          = BASE_IPSERVER + 10;
+    // new neighbor cache entry on our interface
+    public static final int CMD_NEIGHBOR_EVENT              = BASE_IPSERVER + 11;
 
     private final State mInitialState;
     private final State mLocalHotspotState;
@@ -223,6 +245,40 @@
     @NonNull
     private List<TetheredClient> mDhcpLeases = Collections.emptyList();
 
+    private int mLastIPv6UpstreamIfindex = 0;
+
+    private class MyNeighborEventConsumer implements IpNeighborMonitor.NeighborEventConsumer {
+        public void accept(NeighborEvent e) {
+            sendMessage(CMD_NEIGHBOR_EVENT, e);
+        }
+    }
+
+    static class Ipv6ForwardingRule {
+        public final int upstreamIfindex;
+        public final int downstreamIfindex;
+        public final Inet6Address address;
+        public final MacAddress srcMac;
+        public final MacAddress dstMac;
+
+        Ipv6ForwardingRule(int upstreamIfindex, int downstreamIfIndex, Inet6Address address,
+                MacAddress srcMac, MacAddress dstMac) {
+            this.upstreamIfindex = upstreamIfindex;
+            this.downstreamIfindex = downstreamIfIndex;
+            this.address = address;
+            this.srcMac = srcMac;
+            this.dstMac = dstMac;
+        }
+
+        public Ipv6ForwardingRule onNewUpstream(int newUpstreamIfindex) {
+            return new Ipv6ForwardingRule(newUpstreamIfindex, downstreamIfindex, address, srcMac,
+                    dstMac);
+        }
+    }
+    private final LinkedHashMap<Inet6Address, Ipv6ForwardingRule> mIpv6ForwardingRules =
+            new LinkedHashMap<>();
+
+    private final IpNeighborMonitor mIpNeighborMonitor;
+
     public IpServer(
             String ifaceName, Looper looper, int interfaceType, SharedLog log,
             INetd netd, Callback callback, boolean usingLegacyDhcp, Dependencies deps) {
@@ -240,6 +296,12 @@
         mLastError = TetheringManager.TETHER_ERROR_NO_ERROR;
         mServingMode = STATE_AVAILABLE;
 
+        mIpNeighborMonitor = mDeps.getIpNeighborMonitor(getHandler(), mLog,
+                new MyNeighborEventConsumer());
+        if (!mIpNeighborMonitor.start()) {
+            mLog.e("Failed to create IpNeighborMonitor on " + mIfaceName);
+        }
+
         mInitialState = new InitialState();
         mLocalHotspotState = new LocalHotspotState();
         mTetheredState = new TetheredState();
@@ -607,13 +669,21 @@
         }
 
         RaParams params = null;
+        int upstreamIfindex = 0;
 
         if (v6only != null) {
+            final String upstreamIface = v6only.getInterfaceName();
+
             params = new RaParams();
-            params.mtu = v6only.getMtu();
+            // We advertise an mtu lower by 16, which is the closest multiple of 8 >= 14,
+            // the ethernet header size.  This makes kernel ebpf tethering offload happy.
+            // This hack should be reverted once we have the kernel fixed up.
+            // Note: this will automatically clamp to at least 1280 (ipv6 minimum mtu)
+            // see RouterAdvertisementDaemon.java putMtu()
+            params.mtu = v6only.getMtu() - 16;
             params.hasDefaultRoute = v6only.hasIpv6DefaultRoute();
 
-            if (params.hasDefaultRoute) params.hopLimit = getHopLimit(v6only.getInterfaceName());
+            if (params.hasDefaultRoute) params.hopLimit = getHopLimit(upstreamIface);
 
             for (LinkAddress linkAddr : v6only.getLinkAddresses()) {
                 if (linkAddr.getPrefixLength() != RFC7421_PREFIX_LENGTH) continue;
@@ -627,12 +697,18 @@
                     params.dnses.add(dnsServer);
                 }
             }
+
+            upstreamIfindex = mDeps.getIfindex(upstreamIface);
         }
+
         // If v6only is null, we pass in null to setRaParams(), which handles
         // deprecation of any existing RA data.
 
         setRaParams(params);
         mLastIPv6LinkProperties = v6only;
+
+        updateIpv6ForwardingRules(mLastIPv6UpstreamIfindex, upstreamIfindex, null);
+        mLastIPv6UpstreamIfindex = upstreamIfindex;
     }
 
     private void configureLocalIPv6Routes(
@@ -727,6 +803,73 @@
         }
     }
 
+    private void addIpv6ForwardingRule(Ipv6ForwardingRule rule) {
+        try {
+            mNetd.tetherRuleAddDownstreamIpv6(mInterfaceParams.index, rule.upstreamIfindex,
+                    rule.address.getAddress(),  mInterfaceParams.macAddr.toByteArray(),
+                    rule.dstMac.toByteArray());
+            mIpv6ForwardingRules.put(rule.address, rule);
+        } catch (RemoteException | ServiceSpecificException e) {
+            Log.e(TAG, "Could not add IPv6 downstream rule: " + e);
+        }
+    }
+
+    private void removeIpv6ForwardingRule(Ipv6ForwardingRule rule, boolean removeFromMap) {
+        try {
+            mNetd.tetherRuleRemoveDownstreamIpv6(rule.upstreamIfindex, rule.address.getAddress());
+            if (removeFromMap) {
+                mIpv6ForwardingRules.remove(rule.address);
+            }
+        } catch (RemoteException | ServiceSpecificException e) {
+            Log.e(TAG, "Could not remove IPv6 downstream rule: " + e);
+        }
+    }
+
+    // Convenience method to replace a rule with the same rule on a new upstream interface.
+    // Allows replacing the rules in one iteration pass without ConcurrentModificationExceptions.
+    // Relies on the fact that rules are in a map indexed by IP address.
+    private void updateIpv6ForwardingRule(Ipv6ForwardingRule rule, int newIfindex) {
+        addIpv6ForwardingRule(rule.onNewUpstream(newIfindex));
+        removeIpv6ForwardingRule(rule, false /*removeFromMap*/);
+    }
+
+    // Handles all updates to IPv6 forwarding rules. These can currently change only if the upstream
+    // changes or if a neighbor event is received.
+    private void updateIpv6ForwardingRules(int prevUpstreamIfindex, int upstreamIfindex,
+            NeighborEvent e) {
+        // If the upstream interface has changed, remove all rules and re-add them with the new
+        // upstream interface.
+        if (prevUpstreamIfindex != upstreamIfindex) {
+            for (Ipv6ForwardingRule rule : mIpv6ForwardingRules.values()) {
+                updateIpv6ForwardingRule(rule, upstreamIfindex);
+            }
+        }
+
+        // If we're here to process a NeighborEvent, do so now.
+        if (e == null) return;
+        if (!(e.ip instanceof Inet6Address) || e.ip.isMulticastAddress()
+                || e.ip.isLoopbackAddress() || e.ip.isLinkLocalAddress()) {
+            return;
+        }
+
+        Ipv6ForwardingRule rule = new Ipv6ForwardingRule(mLastIPv6UpstreamIfindex,
+                mInterfaceParams.index, (Inet6Address) e.ip, mInterfaceParams.macAddr,
+                e.macAddr);
+        if (e.isValid()) {
+            addIpv6ForwardingRule(rule);
+        } else {
+            removeIpv6ForwardingRule(rule, true /*removeFromMap*/);
+        }
+    }
+
+    private void handleNeighborEvent(NeighborEvent e) {
+        if (mInterfaceParams != null
+                && mInterfaceParams.index == e.ifindex
+                && mInterfaceParams.hasMacAddress) {
+            updateIpv6ForwardingRules(mLastIPv6UpstreamIfindex, mLastIPv6UpstreamIfindex, e);
+        }
+    }
+
     private byte getHopLimit(String upstreamIface) {
         try {
             int upstreamHopLimit = Integer.parseUnsignedInt(
@@ -1014,6 +1157,9 @@
                         }
                     }
                     break;
+                case CMD_NEIGHBOR_EVENT:
+                    handleNeighborEvent((NeighborEvent) message.obj);
+                    break;
                 default:
                     return false;
             }
diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java b/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java
index 6261def..72fe95b 100644
--- a/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java
+++ b/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java
@@ -314,9 +314,13 @@
 
         startStateMachineUpdaters(mHandler);
         startTrackDefaultNetwork();
-        getWifiManager().registerSoftApCallback(
-                mHandler::post /* executor */,
-                new TetheringSoftApCallback());
+
+        final WifiManager wifiManager = getWifiManager();
+        if (wifiManager != null) {
+            wifiManager.registerSoftApCallback(
+                  mHandler::post /* executor */,
+                  new TetheringSoftApCallback());
+        }
     }
 
     private void startStateMachineUpdaters(Handler handler) {
diff --git a/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java b/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
index acedfab..33b3558 100644
--- a/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
+++ b/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
@@ -29,6 +29,11 @@
 import static android.net.ip.IpServer.STATE_LOCAL_ONLY;
 import static android.net.ip.IpServer.STATE_TETHERED;
 import static android.net.ip.IpServer.STATE_UNAVAILABLE;
+import static android.net.netlink.NetlinkConstants.RTM_DELNEIGH;
+import static android.net.netlink.NetlinkConstants.RTM_NEWNEIGH;
+import static android.net.netlink.StructNdMsg.NUD_FAILED;
+import static android.net.netlink.StructNdMsg.NUD_REACHABLE;
+import static android.net.netlink.StructNdMsg.NUD_STALE;
 import static android.net.shared.Inet4AddressUtils.intToInet4AddressHTH;
 
 import static org.junit.Assert.assertEquals;
@@ -41,6 +46,7 @@
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.inOrder;
 import static org.mockito.Mockito.never;
@@ -52,6 +58,7 @@
 import static org.mockito.Mockito.when;
 
 import android.net.INetd;
+import android.net.InetAddresses;
 import android.net.InterfaceConfigurationParcel;
 import android.net.IpPrefix;
 import android.net.LinkAddress;
@@ -61,6 +68,8 @@
 import android.net.dhcp.DhcpServingParamsParcel;
 import android.net.dhcp.IDhcpServer;
 import android.net.dhcp.IDhcpServerCallbacks;
+import android.net.ip.IpNeighborMonitor.NeighborEvent;
+import android.net.ip.IpNeighborMonitor.NeighborEventConsumer;
 import android.net.util.InterfaceParams;
 import android.net.util.InterfaceSet;
 import android.net.util.SharedLog;
@@ -81,6 +90,7 @@
 import org.mockito.MockitoAnnotations;
 
 import java.net.Inet4Address;
+import java.net.InetAddress;
 
 @RunWith(AndroidJUnit4.class)
 @SmallTest
@@ -88,6 +98,8 @@
     private static final String IFACE_NAME = "testnet1";
     private static final String UPSTREAM_IFACE = "upstream0";
     private static final String UPSTREAM_IFACE2 = "upstream1";
+    private static final int UPSTREAM_IFINDEX = 101;
+    private static final int UPSTREAM_IFINDEX2 = 102;
     private static final String BLUETOOTH_IFACE_ADDR = "192.168.42.1";
     private static final int BLUETOOTH_DHCP_PREFIX_LENGTH = 24;
     private static final int DHCP_LEASE_TIME_SECS = 3600;
@@ -102,6 +114,7 @@
     @Mock private SharedLog mSharedLog;
     @Mock private IDhcpServer mDhcpServer;
     @Mock private RouterAdvertisementDaemon mRaDaemon;
+    @Mock private IpNeighborMonitor mIpNeighborMonitor;
     @Mock private IpServer.Dependencies mDependencies;
 
     @Captor private ArgumentCaptor<DhcpServingParamsParcel> mDhcpParamsCaptor;
@@ -111,6 +124,7 @@
             ArgumentCaptor.forClass(LinkProperties.class);
     private IpServer mIpServer;
     private InterfaceConfigurationParcel mInterfaceConfiguration;
+    private NeighborEventConsumer mNeighborEventConsumer;
 
     private void initStateMachine(int interfaceType) throws Exception {
         initStateMachine(interfaceType, false /* usingLegacyDhcp */);
@@ -130,16 +144,28 @@
         }).when(mDependencies).makeDhcpServer(any(), mDhcpParamsCaptor.capture(), any());
         when(mDependencies.getRouterAdvertisementDaemon(any())).thenReturn(mRaDaemon);
         when(mDependencies.getInterfaceParams(IFACE_NAME)).thenReturn(TEST_IFACE_PARAMS);
+
+        when(mDependencies.getIfindex(eq(UPSTREAM_IFACE))).thenReturn(UPSTREAM_IFINDEX);
+        when(mDependencies.getIfindex(eq(UPSTREAM_IFACE2))).thenReturn(UPSTREAM_IFINDEX2);
+
         mInterfaceConfiguration = new InterfaceConfigurationParcel();
         mInterfaceConfiguration.flags = new String[0];
         if (interfaceType == TETHERING_BLUETOOTH) {
             mInterfaceConfiguration.ipv4Addr = BLUETOOTH_IFACE_ADDR;
             mInterfaceConfiguration.prefixLength = BLUETOOTH_DHCP_PREFIX_LENGTH;
         }
+
+        ArgumentCaptor<NeighborEventConsumer> neighborCaptor =
+                ArgumentCaptor.forClass(NeighborEventConsumer.class);
+        doReturn(mIpNeighborMonitor).when(mDependencies).getIpNeighborMonitor(any(), any(),
+                neighborCaptor.capture());
+
         mIpServer = new IpServer(
                 IFACE_NAME, mLooper.getLooper(), interfaceType, mSharedLog, mNetd,
                 mCallback, usingLegacyDhcp, mDependencies);
         mIpServer.start();
+        mNeighborEventConsumer = neighborCaptor.getValue();
+
         // Starting the state machine always puts us in a consistent state and notifies
         // the rest of the world that we've changed from an unknown to available state.
         mLooper.dispatchAll();
@@ -158,7 +184,9 @@
         initStateMachine(interfaceType, usingLegacyDhcp);
         dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_TETHERED);
         if (upstreamIface != null) {
-            dispatchTetherConnectionChanged(upstreamIface);
+            LinkProperties lp = new LinkProperties();
+            lp.setInterfaceName(upstreamIface);
+            dispatchTetherConnectionChanged(upstreamIface, lp);
         }
         reset(mNetd, mCallback);
     }
@@ -170,6 +198,8 @@
 
     @Test
     public void startsOutAvailable() {
+        when(mDependencies.getIpNeighborMonitor(any(), any(), any()))
+                .thenReturn(mIpNeighborMonitor);
         mIpServer = new IpServer(IFACE_NAME, mLooper.getLooper(), TETHERING_BLUETOOTH, mSharedLog,
                 mNetd, mCallback, false /* usingLegacyDhcp */, mDependencies);
         mIpServer.start();
@@ -467,6 +497,89 @@
         verify(mDependencies, never()).makeDhcpServer(any(), any(), any());
     }
 
+    private InetAddress addr(String addr) throws Exception {
+        return InetAddresses.parseNumericAddress(addr);
+    }
+
+    private void recvNewNeigh(int ifindex, InetAddress addr, short nudState, MacAddress mac) {
+        mNeighborEventConsumer.accept(new NeighborEvent(0, RTM_NEWNEIGH, ifindex, addr,
+                nudState, mac));
+        mLooper.dispatchAll();
+    }
+
+    private void recvDelNeigh(int ifindex, InetAddress addr, short nudState, MacAddress mac) {
+        mNeighborEventConsumer.accept(new NeighborEvent(0, RTM_DELNEIGH, ifindex, addr,
+                nudState, mac));
+        mLooper.dispatchAll();
+    }
+
+    @Test
+    public void addRemoveipv6ForwardingRules() throws Exception {
+        initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE, false /* usingLegacyDhcp */);
+
+        final int myIfindex = TEST_IFACE_PARAMS.index;
+        final int notMyIfindex = myIfindex - 1;
+
+        final MacAddress myMac = TEST_IFACE_PARAMS.macAddr;
+        final InetAddress neighA = InetAddresses.parseNumericAddress("2001:db8::1");
+        final InetAddress neighB = InetAddresses.parseNumericAddress("2001:db8::2");
+        final InetAddress neighLL = InetAddresses.parseNumericAddress("fe80::1");
+        final InetAddress neighMC = InetAddresses.parseNumericAddress("ff02::1234");
+        final MacAddress macA = MacAddress.fromString("00:00:00:00:00:0a");
+        final MacAddress macB = MacAddress.fromString("11:22:33:00:00:0b");
+
+        reset(mNetd);
+
+        // Events on other interfaces are ignored.
+        recvNewNeigh(notMyIfindex, neighA, NUD_REACHABLE, macA);
+        verifyNoMoreInteractions(mNetd);
+
+        // Events on this interface are received and sent to netd.
+        recvNewNeigh(myIfindex, neighA, NUD_REACHABLE, macA);
+        verify(mNetd).tetherRuleAddDownstreamIpv6(eq(myIfindex), eq(UPSTREAM_IFINDEX),
+                eq(neighA.getAddress()), eq(myMac.toByteArray()), eq(macA.toByteArray()));
+        reset(mNetd);
+
+        recvNewNeigh(myIfindex, neighB, NUD_REACHABLE, macB);
+        verify(mNetd).tetherRuleAddDownstreamIpv6(eq(myIfindex), eq(UPSTREAM_IFINDEX),
+                eq(neighB.getAddress()), eq(myMac.toByteArray()), eq(macB.toByteArray()));
+        reset(mNetd);
+
+        // Link-local and multicast neighbors are ignored.
+        recvNewNeigh(notMyIfindex, neighLL, NUD_REACHABLE, macA);
+        verifyNoMoreInteractions(mNetd);
+        recvNewNeigh(notMyIfindex, neighMC, NUD_REACHABLE, macA);
+        verifyNoMoreInteractions(mNetd);
+
+        // A neighbor that is no longer valid causes the rule to be removed.
+        recvNewNeigh(myIfindex, neighA, NUD_FAILED, macA);
+        verify(mNetd).tetherRuleRemoveDownstreamIpv6(eq(UPSTREAM_IFINDEX), eq(neighA.getAddress()));
+        reset(mNetd);
+
+        // A neighbor that is deleted causes the rule to be removed.
+        recvDelNeigh(myIfindex, neighB, NUD_STALE, macB);
+        verify(mNetd).tetherRuleRemoveDownstreamIpv6(eq(UPSTREAM_IFINDEX), eq(neighB.getAddress()));
+        reset(mNetd);
+
+        // Upstream changes result in deleting and re-adding the rules.
+        recvNewNeigh(myIfindex, neighA, NUD_REACHABLE, macA);
+        recvNewNeigh(myIfindex, neighB, NUD_REACHABLE, macB);
+        reset(mNetd);
+
+        InOrder inOrder = inOrder(mNetd);
+        LinkProperties lp = new LinkProperties();
+        lp.setInterfaceName(UPSTREAM_IFACE2);
+        dispatchTetherConnectionChanged(UPSTREAM_IFACE2, lp);
+        inOrder.verify(mNetd).tetherRuleAddDownstreamIpv6(eq(myIfindex), eq(UPSTREAM_IFINDEX2),
+                eq(neighA.getAddress()), eq(myMac.toByteArray()), eq(macA.toByteArray()));
+        inOrder.verify(mNetd).tetherRuleRemoveDownstreamIpv6(eq(UPSTREAM_IFINDEX),
+                    eq(neighA.getAddress()));
+        inOrder.verify(mNetd).tetherRuleAddDownstreamIpv6(eq(myIfindex), eq(UPSTREAM_IFINDEX2),
+                eq(neighB.getAddress()), eq(myMac.toByteArray()), eq(macB.toByteArray()));
+        inOrder.verify(mNetd).tetherRuleRemoveDownstreamIpv6(eq(UPSTREAM_IFINDEX),
+                eq(neighB.getAddress()));
+    }
+
     private void assertDhcpStarted(IpPrefix expectedPrefix) throws Exception {
         verify(mDependencies, times(1)).makeDhcpServer(eq(IFACE_NAME), any(), any());
         verify(mDhcpServer, timeout(MAKE_DHCPSERVER_TIMEOUT_MS).times(1)).startWithCallbacks(
@@ -508,13 +621,21 @@
      *
      * @see #dispatchCommand(int)
      * @param upstreamIface String name of upstream interface (or null)
+     * @param v6lp IPv6 LinkProperties of the upstream interface, or null for an IPv4-only upstream.
      */
-    private void dispatchTetherConnectionChanged(String upstreamIface) {
+    private void dispatchTetherConnectionChanged(String upstreamIface, LinkProperties v6lp) {
         mIpServer.sendMessage(IpServer.CMD_TETHER_CONNECTION_CHANGED,
                 new InterfaceSet(upstreamIface));
+        if (v6lp != null) {
+            mIpServer.sendMessage(IpServer.CMD_IPV6_TETHER_UPDATE, v6lp);
+        }
         mLooper.dispatchAll();
     }
 
+    private void dispatchTetherConnectionChanged(String upstreamIface) {
+        dispatchTetherConnectionChanged(upstreamIface, null);
+    }
+
     private void assertIPv4AddressAndDirectlyConnectedRoute(LinkProperties lp) {
         // Find the first IPv4 LinkAddress.
         LinkAddress addr4 = null;
diff --git a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java
index 8e5aaf2..f2074bd 100644
--- a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java
+++ b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java
@@ -95,6 +95,7 @@
 import android.net.dhcp.DhcpServerCallbacks;
 import android.net.dhcp.DhcpServingParamsParcel;
 import android.net.dhcp.IDhcpServer;
+import android.net.ip.IpNeighborMonitor;
 import android.net.ip.IpServer;
 import android.net.ip.RouterAdvertisementDaemon;
 import android.net.util.InterfaceParams;
@@ -173,6 +174,7 @@
     @Mock private UpstreamNetworkMonitor mUpstreamNetworkMonitor;
     @Mock private IPv6TetheringCoordinator mIPv6TetheringCoordinator;
     @Mock private RouterAdvertisementDaemon mRouterAdvertisementDaemon;
+    @Mock private IpNeighborMonitor mIpNeighborMonitor;
     @Mock private IDhcpServer mDhcpServer;
     @Mock private INetd mNetd;
     @Mock private UserManager mUserManager;
@@ -278,6 +280,11 @@
                 }
             }).run();
         }
+
+        public IpNeighborMonitor getIpNeighborMonitor(Handler h, SharedLog l,
+                IpNeighborMonitor.NeighborEventConsumer c) {
+            return mIpNeighborMonitor;
+        }
     }
 
     private class MockTetheringConfiguration extends TetheringConfiguration {
diff --git a/packages/WallpaperCropper/src/com/android/photos/views/TiledImageRenderer.java b/packages/WallpaperCropper/src/com/android/photos/views/TiledImageRenderer.java
index fcb113e..210fdc6 100644
--- a/packages/WallpaperCropper/src/com/android/photos/views/TiledImageRenderer.java
+++ b/packages/WallpaperCropper/src/com/android/photos/views/TiledImageRenderer.java
@@ -163,7 +163,7 @@
 
     private static boolean isHighResolution(Context context) {
         DisplayMetrics metrics = new DisplayMetrics();
-        context.getDisplay().getMetrics(metrics);
+        context.getDisplayNoVerify().getMetrics(metrics);
         return metrics.heightPixels > 2048 ||  metrics.widthPixels > 2048;
     }
 
diff --git a/proto/src/system_messages.proto b/proto/src/system_messages.proto
index eda3fb9..cff5504 100644
--- a/proto/src/system_messages.proto
+++ b/proto/src/system_messages.proto
@@ -252,6 +252,9 @@
     // Package: android
     NOTE_ID_WIFI_SIM_REQUIRED = 60;
 
+    // Inform the user a foreground service while-in-use permission is restricted.
+    NOTE_FOREGROUND_SERVICE_WHILE_IN_USE_PERMISSION = 61;
+
     // ADD_NEW_IDS_ABOVE_THIS_LINE
     // Legacy IDs with arbitrary values appear below
     // Legacy IDs existed as stable non-conflicting constants prior to the O release
diff --git a/services/Android.bp b/services/Android.bp
index c77e75d..db6e21a 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -114,9 +114,10 @@
     name: "services-stubs.sources",
     srcs: [":services-all-sources"],
     installable: false,
-    // TODO: remove the --hide options below
     args: " --show-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.SYSTEM_SERVER\\)" +
         " --hide-annotation android.annotation.Hide" +
+        " --hide InternalClasses" + // com.android.* classes are okay in this interface
+        // TODO: remove the --hide options below
         " --hide-package com.google.android.startop.iorap" +
         " --hide ReferencesHidden" +
         " --hide DeprecationMismatch" +
diff --git a/services/accessibility/OWNERS b/services/accessibility/OWNERS
index 265674a..c6f42f7 100644
--- a/services/accessibility/OWNERS
+++ b/services/accessibility/OWNERS
@@ -1,3 +1,4 @@
 svetoslavganov@google.com
 pweaver@google.com
 rhedjao@google.com
+qasid@google.com
diff --git a/services/api/current.txt b/services/api/current.txt
index 8a82e61..26a65f2 100644
--- a/services/api/current.txt
+++ b/services/api/current.txt
@@ -3,9 +3,9 @@
 
   public interface RuntimePermissionsPersistence {
     method @NonNull public static com.android.permission.persistence.RuntimePermissionsPersistence createInstance();
-    method public void delete(@NonNull android.os.UserHandle);
-    method @Nullable public com.android.permission.persistence.RuntimePermissionsState read(@NonNull android.os.UserHandle);
-    method public void write(@NonNull com.android.permission.persistence.RuntimePermissionsState, @NonNull android.os.UserHandle);
+    method public void deleteAsUser(@NonNull android.os.UserHandle);
+    method @Nullable public com.android.permission.persistence.RuntimePermissionsState readAsUser(@NonNull android.os.UserHandle);
+    method public void writeAsUser(@NonNull com.android.permission.persistence.RuntimePermissionsState, @NonNull android.os.UserHandle);
   }
 
   public final class RuntimePermissionsState {
@@ -30,9 +30,9 @@
 
   public interface RolesPersistence {
     method @NonNull public static com.android.role.persistence.RolesPersistence createInstance();
-    method public void delete(@NonNull android.os.UserHandle);
-    method @Nullable public com.android.role.persistence.RolesState read(@NonNull android.os.UserHandle);
-    method public void write(@NonNull com.android.role.persistence.RolesState, @NonNull android.os.UserHandle);
+    method public void deleteAsUser(@NonNull android.os.UserHandle);
+    method @Nullable public com.android.role.persistence.RolesState readAsUser(@NonNull android.os.UserHandle);
+    method public void writeAsUser(@NonNull com.android.role.persistence.RolesState, @NonNull android.os.UserHandle);
   }
 
   public final class RolesState {
diff --git a/services/api/lint-baseline.txt b/services/api/lint-baseline.txt
index 0b8658c..e985ddb 100644
--- a/services/api/lint-baseline.txt
+++ b/services/api/lint-baseline.txt
@@ -1,35 +1,5 @@
 // Baseline format: 1.0
-InternalClasses: com.android.permission.persistence.RuntimePermissionsPersistence:
-    Internal classes must not be exposed
-InternalClasses: com.android.permission.persistence.RuntimePermissionsState:
-    Internal classes must not be exposed
-InternalClasses: com.android.permission.persistence.RuntimePermissionsState.PermissionState:
-    Internal classes must not be exposed
-InternalClasses: com.android.role.persistence.RolesPersistence:
-    Internal classes must not be exposed
-InternalClasses: com.android.role.persistence.RolesState:
-    Internal classes must not be exposed
-InternalClasses: com.android.server.SystemService:
-    Internal classes must not be exposed
-InternalClasses: com.android.server.SystemService.TargetUser:
-    Internal classes must not be exposed
-
-
 ProtectedMember: com.android.server.SystemService#publishBinderService(String, android.os.IBinder):
     Protected methods not allowed; must be public: method com.android.server.SystemService.publishBinderService(String,android.os.IBinder)}
 ProtectedMember: com.android.server.SystemService#publishBinderService(String, android.os.IBinder, boolean):
     Protected methods not allowed; must be public: method com.android.server.SystemService.publishBinderService(String,android.os.IBinder,boolean)}
-
-
-UserHandleName: com.android.permission.persistence.RuntimePermissionsPersistence#delete(android.os.UserHandle):
-    Method taking UserHandle should be named `doFooAsUser` or `queryFooForUser`, was `delete`
-UserHandleName: com.android.permission.persistence.RuntimePermissionsPersistence#read(android.os.UserHandle):
-    Method taking UserHandle should be named `doFooAsUser` or `queryFooForUser`, was `read`
-UserHandleName: com.android.permission.persistence.RuntimePermissionsPersistence#write(com.android.permission.persistence.RuntimePermissionsState, android.os.UserHandle):
-    Method taking UserHandle should be named `doFooAsUser` or `queryFooForUser`, was `write`
-UserHandleName: com.android.role.persistence.RolesPersistence#delete(android.os.UserHandle):
-    Method taking UserHandle should be named `doFooAsUser` or `queryFooForUser`, was `delete`
-UserHandleName: com.android.role.persistence.RolesPersistence#read(android.os.UserHandle):
-    Method taking UserHandle should be named `doFooAsUser` or `queryFooForUser`, was `read`
-UserHandleName: com.android.role.persistence.RolesPersistence#write(com.android.role.persistence.RolesState, android.os.UserHandle):
-    Method taking UserHandle should be named `doFooAsUser` or `queryFooForUser`, was `write`
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index 7151d2b..a8a2791 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -281,7 +281,7 @@
     }
 
     private void computeMaximumWidgetBitmapMemory() {
-        Display display = mContext.getDisplay();
+        Display display = mContext.getDisplayNoVerify();
         Point size = new Point();
         display.getRealSize(size);
         // Cap memory usage at 1.5 times the size of the display
diff --git a/services/autofill/java/com/android/server/autofill/InlineSuggestionSession.java b/services/autofill/java/com/android/server/autofill/InlineSuggestionSession.java
index 1fc48d2..6daa106 100644
--- a/services/autofill/java/com/android/server/autofill/InlineSuggestionSession.java
+++ b/services/autofill/java/com/android/server/autofill/InlineSuggestionSession.java
@@ -21,6 +21,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.ComponentName;
+import android.os.Bundle;
 import android.os.RemoteException;
 import android.util.Log;
 import android.view.autofill.AutofillId;
@@ -29,6 +30,7 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.view.IInlineSuggestionsRequestCallback;
 import com.android.internal.view.IInlineSuggestionsResponseCallback;
+import com.android.internal.view.InlineSuggestionsRequestInfo;
 import com.android.server.inputmethod.InputMethodManagerInternal;
 
 import java.util.concurrent.CancellationException;
@@ -71,8 +73,10 @@
         synchronized (mLock) {
             cancelCurrentRequest();
             mPendingImeResponse = new CompletableFuture<>();
+            // TODO(b/146454892): pipe the uiExtras from the ExtServices.
             mInputMethodManagerInternal.onCreateInlineSuggestionsRequest(
-                    mUserId, mComponentName, currentViewId,
+                    mUserId,
+                    new InlineSuggestionsRequestInfo(mComponentName, currentViewId, new Bundle()),
                     new InlineSuggestionsRequestCallbackImpl(mPendingImeResponse));
         }
     }
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index f544517..317ce4c 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -1158,6 +1158,18 @@
             } catch (RemoteException e) {
                 Slog.e(TAG, "Error requesting to hide fill UI", e);
             }
+            try {
+                final InlineSuggestionSession.ImeResponse imeResponse =
+                        mInlineSuggestionSession.waitAndGetImeResponse();
+                if (imeResponse == null) {
+                    Log.w(TAG, "Session input method callback is not set yet");
+                    return;
+                }
+                imeResponse.getCallback().onInlineSuggestionsResponse(
+                        new InlineSuggestionsResponse(Collections.EMPTY_LIST));
+            } catch (RemoteException e) {
+                Slog.e(TAG, "RemoteException hiding inline suggestions");
+            }
         }
     }
 
diff --git a/services/autofill/java/com/android/server/autofill/ui/CustomScrollView.java b/services/autofill/java/com/android/server/autofill/ui/CustomScrollView.java
index 813fc8d..14bd7d7 100644
--- a/services/autofill/java/com/android/server/autofill/ui/CustomScrollView.java
+++ b/services/autofill/java/com/android/server/autofill/ui/CustomScrollView.java
@@ -75,7 +75,7 @@
         final TypedValue typedValue = new TypedValue();
         final Point point = new Point();
         final Context context = getContext();
-        context.getDisplay().getSize(point);
+        context.getDisplayNoVerify().getSize(point);
         context.getTheme().resolveAttribute(R.attr.autofillSaveCustomSubtitleMaxHeight,
                 typedValue, true);
         final View child = getChildAt(0);
diff --git a/services/autofill/java/com/android/server/autofill/ui/FillUi.java b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
index 5dc43ef..344b92f 100644
--- a/services/autofill/java/com/android/server/autofill/ui/FillUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
@@ -165,7 +165,7 @@
         // In full screen we only initialize size once assuming screen size never changes
         if (mFullScreen) {
             final Point outPoint = mTempPoint;
-            mContext.getDisplay().getSize(outPoint);
+            mContext.getDisplayNoVerify().getSize(outPoint);
             // full with of screen and half height of screen
             mContentWidth = LayoutParams.MATCH_PARENT;
             mContentHeight = outPoint.y / 2;
@@ -559,7 +559,7 @@
     }
 
     private static void resolveMaxWindowSize(Context context, Point outPoint) {
-        context.getDisplay().getSize(outPoint);
+        context.getDisplayNoVerify().getSize(outPoint);
         final TypedValue typedValue = sTempTypedValue;
         context.getTheme().resolveAttribute(R.attr.autofillDatasetPickerMaxWidth,
                 typedValue, true);
diff --git a/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java b/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java
index a8886fc..17cdf61 100644
--- a/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java
+++ b/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java
@@ -82,12 +82,17 @@
         if (sDebug) Slog.d(TAG, "createInlineSuggestionsResponse called");
         final BiConsumer<Dataset, Integer> onClickFactory;
         if (response.getAuthentication() != null) {
-            onClickFactory = (dataset, datasetIndex) -> client.authenticate(response.getRequestId(),
-                    datasetIndex, response.getAuthentication(), response.getClientState(),
-                    /* authenticateInline= */ true);
+            onClickFactory = (dataset, datasetIndex) -> {
+                client.requestHideFillUi(autofillId);
+                client.authenticate(response.getRequestId(),
+                        datasetIndex, response.getAuthentication(), response.getClientState(),
+                        /* authenticateInline= */ true);
+            };
         } else {
-            onClickFactory = (dataset, datasetIndex) ->
-                    client.fill(response.getRequestId(), datasetIndex, dataset);
+            onClickFactory = (dataset, datasetIndex) -> {
+                client.requestHideFillUi(autofillId);
+                client.fill(response.getRequestId(), datasetIndex, dataset);
+            };
         }
 
         final List<Dataset> datasetList = response.getDatasets();
diff --git a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
index 3c37f73..e434be6 100644
--- a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
+++ b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
@@ -76,9 +76,7 @@
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.List;
-import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
 
@@ -802,6 +800,7 @@
             final int size = in.getDataSize();
 
             if (excludedKeysForPackage != null && excludedKeysForPackage.contains(key)) {
+                Slog.i(TAG, "Skipping blocked key " + key);
                 in.skipEntityData();
                 continue;
             }
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 6fc6084..228d9be 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -113,6 +113,7 @@
         "android.hardware.broadcastradio-V2.0-java",
         "android.hardware.health-V1.0-java",
         "android.hardware.health-V2.0-java",
+        "android.hardware.health-V2.1-java",
         "android.hardware.light-java",
         "android.hardware.weaver-V1.0-java",
         "android.hardware.biometrics.face-V1.1-java",
diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java
index 76f6ef6..0f8d57e 100644
--- a/services/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -29,8 +29,7 @@
 import android.content.pm.PackageManager.ComponentInfoFlags;
 import android.content.pm.PackageManager.PackageInfoFlags;
 import android.content.pm.PackageManager.ResolveInfoFlags;
-import android.content.pm.parsing.AndroidPackage;
-import android.content.pm.parsing.ComponentParseUtils;
+import android.content.pm.parsing.component.ParsedMainComponent;
 import android.os.Bundle;
 import android.os.PersistableBundle;
 import android.util.ArrayMap;
@@ -38,6 +37,8 @@
 import android.util.SparseArray;
 
 import com.android.server.pm.PackageList;
+import com.android.server.pm.PackageSetting;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
 
 import java.io.IOException;
 import java.lang.annotation.Retention;
@@ -586,9 +587,7 @@
      */
     public abstract @Nullable AndroidPackage getPackage(@NonNull String packageName);
 
-    // TODO(b/135203078): PackageSetting can't be referenced directly. Should move to a server side
-    //  internal PM which is aware of PS.
-    public abstract @Nullable Object getPackageSetting(String packageName);
+    public abstract @Nullable PackageSetting getPackageSetting(String packageName);
 
     /**
      * Returns a package for the given UID. If the UID is part of a shared user ID, one
@@ -625,18 +624,17 @@
      */
     public abstract void removePackageListObserver(@NonNull PackageListObserver observer);
 
-    // TODO(b/135203078): PackageSetting can't be referenced directly
     /**
      * Returns a package object for the disabled system package name.
      */
-    public abstract @Nullable Object getDisabledSystemPackage(@NonNull String packageName);
+    public abstract @Nullable PackageSetting getDisabledSystemPackage(@NonNull String packageName);
 
     /**
      * Returns the package name for the disabled system package.
      *
      * This is equivalent to
      * {@link #getDisabledSystemPackage(String)}
-     *     .{@link com.android.server.pm.PackageSetting#pkg}
+     *     .{@link PackageSetting#pkg}
      *     .{@link AndroidPackage#getPackageName()}
      */
     public abstract @Nullable String getDisabledSystemPackageName(@NonNull String packageName);
@@ -677,7 +675,7 @@
     /**
      * Returns whether or not access to the application should be filtered.
      *
-     * @see #filterAppAccess(android.content.pm.PackageParser.Package, int, int)
+     * @see #filterAppAccess(AndroidPackage, int, int)
      */
     public abstract boolean filterAppAccess(
             @NonNull String packageName, int callingUid, int userId);
@@ -763,21 +761,29 @@
             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);
 
     /**
      * Perform the given action for each package.
-     * Note that packages lock will be held while performin the actions.
+     * Note that packages lock will be held while performing the actions.
      *
      * @param actionLocked action to be performed
      */
     public abstract void forEachPackage(Consumer<AndroidPackage> actionLocked);
 
     /**
+     * Perform the given action for each {@link PackageSetting}.
+     * Note that packages lock will be held while performing the actions.
+     *
+     * @param actionLocked action to be performed
+     */
+    public abstract void forEachPackageSetting(Consumer<PackageSetting> actionLocked);
+
+    /**
      * Perform the given action for each installed package for a user.
      * Note that packages lock will be held while performin the actions.
      */
diff --git a/services/core/java/com/android/server/BatteryService.java b/services/core/java/com/android/server/BatteryService.java
index c8894e7..f1f5005 100644
--- a/services/core/java/com/android/server/BatteryService.java
+++ b/services/core/java/com/android/server/BatteryService.java
@@ -27,8 +27,10 @@
 import android.database.ContentObserver;
 import android.hardware.health.V1_0.HealthInfo;
 import android.hardware.health.V2_0.IHealth;
-import android.hardware.health.V2_0.IHealthInfoCallback;
 import android.hardware.health.V2_0.Result;
+import android.hardware.health.V2_1.BatteryCapacityLevel;
+import android.hardware.health.V2_1.Constants;
+import android.hardware.health.V2_1.IHealthInfoCallback;
 import android.hidl.manager.V1_0.IServiceManager;
 import android.hidl.manager.V1_0.IServiceNotification;
 import android.metrics.LogMaker;
@@ -145,6 +147,7 @@
 
     private HealthInfo mHealthInfo;
     private final HealthInfo mLastHealthInfo = new HealthInfo();
+    private android.hardware.health.V2_1.HealthInfo mHealthInfo2p1;
     private boolean mBatteryLevelCritical;
     private int mLastBatteryStatus;
     private int mLastBatteryHealth;
@@ -359,6 +362,9 @@
     }
 
     private boolean shouldShutdownLocked() {
+        if (mHealthInfo2p1.batteryCapacityLevel != BatteryCapacityLevel.UNSUPPORTED) {
+            return (mHealthInfo2p1.batteryCapacityLevel == BatteryCapacityLevel.CRITICAL);
+        }
         if (mHealthInfo.batteryLevel > 0) {
             return false;
         }
@@ -416,22 +422,23 @@
         }
     }
 
-    private void update(android.hardware.health.V2_0.HealthInfo info) {
+    private void update(android.hardware.health.V2_1.HealthInfo info) {
         traceBegin("HealthInfoUpdate");
 
         Trace.traceCounter(Trace.TRACE_TAG_POWER, "BatteryChargeCounter",
-                info.legacy.batteryChargeCounter);
+                info.legacy.legacy.batteryChargeCounter);
         Trace.traceCounter(Trace.TRACE_TAG_POWER, "BatteryCurrent",
-                info.legacy.batteryCurrent);
+                info.legacy.legacy.batteryCurrent);
 
         synchronized (mLock) {
             if (!mUpdatesStopped) {
-                mHealthInfo = info.legacy;
+                mHealthInfo = info.legacy.legacy;
+                mHealthInfo2p1 = info;
                 // Process the new values.
                 processValuesLocked(false);
                 mLock.notifyAll(); // for any waiters on new info
             } else {
-                copy(mLastHealthInfo, info.legacy);
+                copy(mLastHealthInfo, info.legacy.legacy);
             }
         }
         traceEnd();
@@ -485,7 +492,8 @@
             mBatteryStats.setBatteryState(mHealthInfo.batteryStatus, mHealthInfo.batteryHealth,
                     mPlugType, mHealthInfo.batteryLevel, mHealthInfo.batteryTemperature,
                     mHealthInfo.batteryVoltage, mHealthInfo.batteryChargeCounter,
-                    mHealthInfo.batteryFullCharge);
+                    mHealthInfo.batteryFullCharge,
+                    mHealthInfo2p1.batteryChargeTimeToFullNowSeconds);
         } catch (RemoteException e) {
             // Should never happen.
         }
@@ -1123,8 +1131,21 @@
     private final class HealthHalCallback extends IHealthInfoCallback.Stub
             implements HealthServiceWrapper.Callback {
         @Override public void healthInfoChanged(android.hardware.health.V2_0.HealthInfo props) {
+            android.hardware.health.V2_1.HealthInfo propsLatest =
+                    new android.hardware.health.V2_1.HealthInfo();
+            propsLatest.legacy = props;
+
+            propsLatest.batteryCapacityLevel = BatteryCapacityLevel.UNSUPPORTED;
+            propsLatest.batteryChargeTimeToFullNowSeconds =
+                Constants.BATTERY_CHARGE_TIME_TO_FULL_NOW_SECONDS_UNSUPPORTED;
+
+            BatteryService.this.update(propsLatest);
+        }
+
+        @Override public void healthInfoChanged_2_1(android.hardware.health.V2_1.HealthInfo props) {
             BatteryService.this.update(props);
         }
+
         // on new service registered
         @Override public void onRegistration(IHealth oldService, IHealth newService,
                 String instance) {
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index f7eabac..e48ef5a 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -1534,7 +1534,8 @@
     }
 
     @Override
-    public NetworkCapabilities[] getDefaultNetworkCapabilitiesForUser(int userId) {
+    public NetworkCapabilities[] getDefaultNetworkCapabilitiesForUser(
+                int userId, String callingPackageName) {
         // The basic principle is: if an app's traffic could possibly go over a
         // network, without the app doing anything multinetwork-specific,
         // (hence, by "default"), then include that network's capabilities in
@@ -1556,7 +1557,10 @@
         NetworkAgentInfo nai = getDefaultNetwork();
         NetworkCapabilities nc = getNetworkCapabilitiesInternal(nai);
         if (nc != null) {
-            result.put(nai.network, nc);
+            result.put(
+                    nai.network,
+                    maybeSanitizeLocationInfoForCaller(
+                            nc, Binder.getCallingUid(), callingPackageName));
         }
 
         synchronized (mVpns) {
@@ -1566,10 +1570,12 @@
                     Network[] networks = vpn.getUnderlyingNetworks();
                     if (networks != null) {
                         for (Network network : networks) {
-                            nai = getNetworkAgentInfoForNetwork(network);
-                            nc = getNetworkCapabilitiesInternal(nai);
+                            nc = getNetworkCapabilitiesInternal(network);
                             if (nc != null) {
-                                result.put(network, nc);
+                                result.put(
+                                        network,
+                                        maybeSanitizeLocationInfoForCaller(
+                                                nc, Binder.getCallingUid(), callingPackageName));
                             }
                         }
                     }
@@ -1636,20 +1642,26 @@
         }
     }
 
+    private NetworkCapabilities getNetworkCapabilitiesInternal(Network network) {
+        return getNetworkCapabilitiesInternal(getNetworkAgentInfoForNetwork(network));
+    }
+
     private NetworkCapabilities getNetworkCapabilitiesInternal(NetworkAgentInfo nai) {
         if (nai == null) return null;
         synchronized (nai) {
             if (nai.networkCapabilities == null) return null;
             return networkCapabilitiesRestrictedForCallerPermissions(
-                    nai.networkCapabilities,
-                    Binder.getCallingPid(), Binder.getCallingUid());
+                    nai.networkCapabilities, Binder.getCallingPid(), Binder.getCallingUid());
         }
     }
 
     @Override
-    public NetworkCapabilities getNetworkCapabilities(Network network) {
+    public NetworkCapabilities getNetworkCapabilities(Network network, String callingPackageName) {
+        mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackageName);
         enforceAccessPermission();
-        return getNetworkCapabilitiesInternal(getNetworkAgentInfoForNetwork(network));
+        return maybeSanitizeLocationInfoForCaller(
+                getNetworkCapabilitiesInternal(network),
+                Binder.getCallingUid(), callingPackageName);
     }
 
     @VisibleForTesting
@@ -1665,20 +1677,34 @@
         }
         newNc.setAdministratorUids(Collections.EMPTY_LIST);
 
-        maybeSanitizeLocationInfoForCaller(newNc, callerUid);
-
         return newNc;
     }
 
-    private void maybeSanitizeLocationInfoForCaller(
-            NetworkCapabilities nc, int callerUid) {
-        // TODO(b/142072839): Conditionally reset the owner UID if the following
-        // conditions are not met:
-        // 1. The destination app is the network owner
-        // 2. The destination app has the ACCESS_COARSE_LOCATION permission granted
-        // if target SDK<29 or otherwise has the ACCESS_FINE_LOCATION permission granted
-        // 3. The user's location toggle is on
-        nc.setOwnerUid(INVALID_UID);
+    @VisibleForTesting
+    @Nullable
+    NetworkCapabilities maybeSanitizeLocationInfoForCaller(
+            @Nullable NetworkCapabilities nc, int callerUid, @NonNull String callerPkgName) {
+        if (nc == null) {
+            return null;
+        }
+        final NetworkCapabilities newNc = new NetworkCapabilities(nc);
+        if (callerUid != newNc.getOwnerUid()) {
+            newNc.setOwnerUid(INVALID_UID);
+            return newNc;
+        }
+
+        Binder.withCleanCallingIdentity(
+                () -> {
+                    if (!mLocationPermissionChecker.checkLocationPermission(
+                            callerPkgName, null /* featureId */, callerUid, null /* message */)) {
+                        // Caller does not have the requisite location permissions. Reset the
+                        // owner's UID in the NetworkCapabilities.
+                        newNc.setOwnerUid(INVALID_UID);
+                    }
+                }
+        );
+
+        return newNc;
     }
 
     private LinkProperties linkPropertiesRestrictedForCallerPermissions(
@@ -1753,7 +1779,7 @@
     public boolean isActiveNetworkMetered() {
         enforceAccessPermission();
 
-        final NetworkCapabilities caps = getNetworkCapabilities(getActiveNetwork());
+        final NetworkCapabilities caps = getNetworkCapabilitiesInternal(getActiveNetwork());
         if (caps != null) {
             return !caps.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
         } else {
@@ -5330,8 +5356,8 @@
         }
 
         public String toString() {
-            return "uid/pid:" + mUid + "/" + mPid + " " + request +
-                    (mPendingIntent == null ? "" : " to trigger " + mPendingIntent);
+            return "uid/pid:" + mUid + "/" + mPid + " " + request
+                    + (mPendingIntent == null ? "" : " to trigger " + mPendingIntent);
         }
     }
 
@@ -6408,8 +6434,13 @@
         }
         switch (notificationType) {
             case ConnectivityManager.CALLBACK_AVAILABLE: {
-                putParcelable(bundle, networkCapabilitiesRestrictedForCallerPermissions(
-                        networkAgent.networkCapabilities, nri.mPid, nri.mUid));
+                final NetworkCapabilities nc =
+                        networkCapabilitiesRestrictedForCallerPermissions(
+                                networkAgent.networkCapabilities, nri.mPid, nri.mUid);
+                putParcelable(
+                        bundle,
+                        maybeSanitizeLocationInfoForCaller(
+                                nc, nri.mUid, nri.request.getRequestorPackageName()));
                 putParcelable(bundle, linkPropertiesRestrictedForCallerPermissions(
                         networkAgent.linkProperties, nri.mPid, nri.mUid));
                 // For this notification, arg1 contains the blocked status.
@@ -6422,9 +6453,13 @@
             }
             case ConnectivityManager.CALLBACK_CAP_CHANGED: {
                 // networkAgent can't be null as it has been accessed a few lines above.
-                final NetworkCapabilities nc = networkCapabilitiesRestrictedForCallerPermissions(
-                        networkAgent.networkCapabilities, nri.mPid, nri.mUid);
-                putParcelable(bundle, nc);
+                final NetworkCapabilities netCap =
+                        networkCapabilitiesRestrictedForCallerPermissions(
+                                networkAgent.networkCapabilities, nri.mPid, nri.mUid);
+                putParcelable(
+                        bundle,
+                        maybeSanitizeLocationInfoForCaller(
+                                netCap, nri.mUid, nri.request.getRequestorPackageName()));
                 break;
             }
             case ConnectivityManager.CALLBACK_IP_CHANGED: {
diff --git a/services/core/java/com/android/server/IntentResolver.java b/services/core/java/com/android/server/IntentResolver.java
index 05820d2..7ec2a34 100644
--- a/services/core/java/com/android/server/IntentResolver.java
+++ b/services/core/java/com/android/server/IntentResolver.java
@@ -16,6 +16,7 @@
 
 package com.android.server;
 
+import android.annotation.NonNull;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.net.Uri;
@@ -44,29 +45,30 @@
 /**
  * {@hide}
  */
-public abstract class IntentResolver<F extends IntentFilter, R extends Object> {
+public abstract class IntentResolver<F, R extends Object> {
     final private static String TAG = "IntentResolver";
     final private static boolean DEBUG = false;
     final private static boolean localLOGV = DEBUG || false;
     final private static boolean localVerificationLOGV = DEBUG || false;
 
     public void addFilter(F f) {
+        IntentFilter intentFilter = getIntentFilter(f);
         if (localLOGV) {
             Slog.v(TAG, "Adding filter: " + f);
-            f.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), "      ");
+            intentFilter.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), "      ");
             Slog.v(TAG, "    Building Lookup Maps:");
         }
 
         mFilters.add(f);
-        int numS = register_intent_filter(f, f.schemesIterator(),
+        int numS = register_intent_filter(f, intentFilter.schemesIterator(),
                 mSchemeToFilter, "      Scheme: ");
         int numT = register_mime_types(f, "      Type: ");
         if (numS == 0 && numT == 0) {
-            register_intent_filter(f, f.actionsIterator(),
+            register_intent_filter(f, intentFilter.actionsIterator(),
                     mActionToFilter, "      Action: ");
         }
         if (numT != 0) {
-            register_intent_filter(f, f.actionsIterator(),
+            register_intent_filter(f, intentFilter.actionsIterator(),
                     mTypedActionToFilter, "      TypedAction: ");
         }
     }
@@ -153,7 +155,7 @@
                 if (cur == null) {
                     break;
                 }
-                if (filterEquals(cur, matching)) {
+                if (filterEquals(getIntentFilter(cur), matching)) {
                     if (res == null) {
                         res = new ArrayList<>();
                     }
@@ -178,7 +180,7 @@
         } else {
             ArrayList<F> res = null;
             for (F cur : mFilters) {
-                if (filterEquals(cur, matching)) {
+                if (filterEquals(getIntentFilter(cur), matching)) {
                     if (res == null) {
                         res = new ArrayList<>();
                     }
@@ -195,21 +197,22 @@
     }
 
     protected void removeFilterInternal(F f) {
+        IntentFilter intentFilter = getIntentFilter(f);
         if (localLOGV) {
             Slog.v(TAG, "Removing filter: " + f);
-            f.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), "      ");
+            intentFilter.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), "      ");
             Slog.v(TAG, "    Cleaning Lookup Maps:");
         }
 
-        int numS = unregister_intent_filter(f, f.schemesIterator(),
+        int numS = unregister_intent_filter(f, intentFilter.schemesIterator(),
                 mSchemeToFilter, "      Scheme: ");
         int numT = unregister_mime_types(f, "      Type: ");
         if (numS == 0 && numT == 0) {
-            unregister_intent_filter(f, f.actionsIterator(),
+            unregister_intent_filter(f, intentFilter.actionsIterator(),
                     mActionToFilter, "      Action: ");
         }
         if (numT != 0) {
-            unregister_intent_filter(f, f.actionsIterator(),
+            unregister_intent_filter(f, intentFilter.actionsIterator(),
                     mTypedActionToFilter, "      TypedAction: ");
         }
     }
@@ -272,7 +275,7 @@
                         if (printer == null) {
                             printer = new PrintWriterPrinter(out);
                         }
-                        filter.dump(printer, fprefix + "  ");
+                        getIntentFilter(filter).dump(printer, fprefix + "  ");
                     }
                 }
             }
@@ -527,7 +530,7 @@
      * @see android.content.IntentFilter#getAutoVerify()
      */
     protected boolean isFilterVerified(F filter) {
-        return filter.isVerified();
+        return getIntentFilter(filter).isVerified();
     }
 
     /**
@@ -591,7 +594,7 @@
     }
 
     private final int register_mime_types(F filter, String prefix) {
-        final Iterator<String> i = filter.typesIterator();
+        final Iterator<String> i = getIntentFilter(filter).typesIterator();
         if (i == null) {
             return 0;
         }
@@ -622,7 +625,7 @@
     }
 
     private final int unregister_mime_types(F filter, String prefix) {
-        final Iterator<String> i = filter.typesIterator();
+        final Iterator<String> i = getIntentFilter(filter).typesIterator();
         if (i == null) {
             return 0;
         }
@@ -762,12 +765,14 @@
             }
 
             // Are we verified ?
-            if (filter.getAutoVerify()) {
+            IntentFilter intentFilter = getIntentFilter(filter);
+            if (intentFilter.getAutoVerify()) {
                 if (localVerificationLOGV || debug) {
                     Slog.v(TAG, "  Filter verified: " + isFilterVerified(filter));
-                    int authorities = filter.countDataAuthorities();
+                    int authorities = intentFilter.countDataAuthorities();
                     for (int z = 0; z < authorities; z++) {
-                        Slog.v(TAG, "   " + filter.getDataAuthority(z).getHost());
+                        Slog.v(TAG, "   " + intentFilter.getDataAuthority(z)
+                                .getHost());
                     }
                 }
             }
@@ -780,12 +785,12 @@
                 continue;
             }
 
-            match = filter.match(action, resolvedType, scheme, data, categories, TAG);
+            match = intentFilter.match(action, resolvedType, scheme, data, categories, TAG);
             if (match >= 0) {
                 if (debug) Slog.v(TAG, "  Filter matched!  match=0x" +
                         Integer.toHexString(match) + " hasDefault="
-                        + filter.hasCategory(Intent.CATEGORY_DEFAULT));
-                if (!defaultOnly || filter.hasCategory(Intent.CATEGORY_DEFAULT)) {
+                        + intentFilter.hasCategory(Intent.CATEGORY_DEFAULT));
+                if (!defaultOnly || intentFilter.hasCategory(Intent.CATEGORY_DEFAULT)) {
                     final R oneResult = newResult(filter, match, userId);
                     if (debug) Slog.v(TAG, "    Created result: " + oneResult);
                     if (oneResult != null) {
@@ -793,7 +798,7 @@
                         if (debug) {
                             dumpFilter(logPrintWriter, "    ", filter);
                             logPrintWriter.flush();
-                            filter.dump(logPrinter, "    ");
+                            intentFilter.dump(logPrinter, "    ");
                         }
                     }
                 } else {
@@ -875,4 +880,11 @@
      * All of the actions that have been registered and specified a MIME type.
      */
     private final ArrayMap<String, F[]> mTypedActionToFilter = new ArrayMap<String, F[]>();
+
+    /**
+     * Rather than refactoring the entire class, this allows the input {@link F} to be a type
+     * other than {@link IntentFilter}, transforming it whenever necessary. It is valid to use
+     * {@link IntentFilter} directly as {@link F} and just return {@param input}.
+     */
+    protected abstract IntentFilter getIntentFilter(@NonNull F input);
 }
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index 5db5115..d515332 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -862,10 +862,6 @@
             }
         }
 
-        public void requestSetAllowed(boolean allowed) {
-            mProvider.requestSetAllowed(allowed);
-        }
-
         public void onUserStarted(int userId) {
             synchronized (mLock) {
                 // clear the user's enabled state in order to force a reevalution of whether the
@@ -2931,18 +2927,6 @@
     private class LocalService extends LocationManagerInternal {
 
         @Override
-        public void requestSetProviderAllowed(String provider, boolean allowed) {
-            Preconditions.checkArgument(provider != null, "invalid null provider");
-
-            synchronized (mLock) {
-                LocationProviderManager manager = getLocationProviderManager(provider);
-                if (manager != null) {
-                    manager.requestSetAllowed(allowed);
-                }
-            }
-        }
-
-        @Override
         public boolean isProviderEnabledForUser(@NonNull String provider, int userId) {
             synchronized (mLock) {
                 LocationProviderManager manager = getLocationProviderManager(provider);
diff --git a/services/core/java/com/android/server/PinnerService.java b/services/core/java/com/android/server/PinnerService.java
index 6fb7b26..93859b3 100644
--- a/services/core/java/com/android/server/PinnerService.java
+++ b/services/core/java/com/android/server/PinnerService.java
@@ -103,7 +103,7 @@
     private static boolean PROP_PIN_CAMERA =
             DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_RUNTIME_NATIVE_BOOT,
                                     "pin_camera",
-                                    SystemProperties.getBoolean("pinner.pin_camera", true));
+                                    SystemProperties.getBoolean("pinner.pin_camera", false));
     // Pin using pinlist.meta when pinning apps.
     private static boolean PROP_PIN_PINLIST = SystemProperties.getBoolean(
             "pinner.use_pinlist", true);
diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java
index a1ccd84..8900eee 100644
--- a/services/core/java/com/android/server/Watchdog.java
+++ b/services/core/java/com/android/server/Watchdog.java
@@ -100,7 +100,7 @@
         "media.codec", // vendor/bin/hw/android.hardware.media.omx@1.0-service
         "media.swcodec", // /apex/com.android.media.swcodec/bin/mediaswcodec
         "com.android.bluetooth",  // Bluetooth service
-        "/system/bin/statsd",  // Stats daemon
+        "/apex/com.android.os.statsd/bin/statsd",  // Stats daemon
     };
 
     public static final List<String> HAL_INTERFACES_OF_INTEREST = Arrays.asList(
diff --git a/services/core/java/com/android/server/adb/AdbDebuggingManager.java b/services/core/java/com/android/server/adb/AdbDebuggingManager.java
index 1099413..f16e3ce 100644
--- a/services/core/java/com/android/server/adb/AdbDebuggingManager.java
+++ b/services/core/java/com/android/server/adb/AdbDebuggingManager.java
@@ -29,6 +29,7 @@
 import android.content.res.Resources;
 import android.database.ContentObserver;
 import android.debug.AdbProtoEnums;
+import android.debug.AdbTransportType;
 import android.net.LocalSocket;
 import android.net.LocalSocketAddress;
 import android.net.Uri;
@@ -722,13 +723,21 @@
     }
 
     /**
-     * When {@code enabled} is {@code true}, this allows ADB debugging and starts the ADB hanler
-     * thread. When {@code enabled} is {@code false}, this disallows ADB debugging and shuts
-     * down the handler thread.
+     * When {@code enabled} is {@code true}, this allows ADB debugging and starts the ADB handler
+     * thread. When {@code enabled} is {@code false}, this disallows ADB debugging for the given
+     * @{code transportType}. See {@link IAdbTransport} for all available transport types.
+     * If all transport types are disabled, the ADB handler thread will shut down.
      */
-    public void setAdbEnabled(boolean enabled) {
-        mHandler.sendEmptyMessage(enabled ? AdbDebuggingHandler.MESSAGE_ADB_ENABLED
-                                          : AdbDebuggingHandler.MESSAGE_ADB_DISABLED);
+    public void setAdbEnabled(boolean enabled, byte transportType) {
+        if (transportType == AdbTransportType.USB) {
+            mHandler.sendEmptyMessage(enabled ? AdbDebuggingHandler.MESSAGE_ADB_ENABLED
+                                              : AdbDebuggingHandler.MESSAGE_ADB_DISABLED);
+        } else if (transportType == AdbTransportType.WIFI) {
+            // TODO(joshuaduong): Not implemented
+        } else {
+            throw new IllegalArgumentException(
+                    "setAdbEnabled called with unimplemented transport type=" + transportType);
+        }
     }
 
     /**
diff --git a/services/core/java/com/android/server/adb/AdbService.java b/services/core/java/com/android/server/adb/AdbService.java
index c125b1b..0d161b9 100644
--- a/services/core/java/com/android/server/adb/AdbService.java
+++ b/services/core/java/com/android/server/adb/AdbService.java
@@ -15,19 +15,23 @@
  */
 package com.android.server.adb;
 
+import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
+
+import android.annotation.NonNull;
+import android.annotation.UserIdInt;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.database.ContentObserver;
 import android.debug.AdbManagerInternal;
+import android.debug.AdbTransportType;
 import android.debug.IAdbManager;
 import android.debug.IAdbTransport;
+import android.debug.PairDevice;
 import android.hardware.usb.UsbManager;
+import android.net.Uri;
 import android.os.Binder;
-import android.os.Handler;
 import android.os.IBinder;
-import android.os.Looper;
-import android.os.Message;
 import android.os.RemoteException;
 import android.os.SystemProperties;
 import android.provider.Settings;
@@ -38,7 +42,6 @@
 import android.util.Slog;
 import android.util.proto.ProtoOutputStream;
 
-
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.dump.DualDumpOutputStream;
@@ -50,6 +53,7 @@
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.Collections;
+import java.util.Map;
 
 /**
  * The Android Debug Bridge (ADB) service. This controls the availability of ADB and authorization
@@ -77,7 +81,8 @@
             if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
                 mAdbService.systemReady();
             } else if (phase == SystemService.PHASE_BOOT_COMPLETED) {
-                mAdbService.bootCompleted();
+                FgThread.getHandler().sendMessage(obtainMessage(
+                        AdbService::bootCompleted, mAdbService));
             }
         }
     }
@@ -94,8 +99,14 @@
         }
 
         @Override
-        public boolean isAdbEnabled() {
-            return mAdbEnabled;
+        public boolean isAdbEnabled(byte transportType) {
+            if (transportType == AdbTransportType.USB) {
+                return mIsAdbUsbEnabled;
+            } else if (transportType == AdbTransportType.WIFI) {
+                return mIsAdbWifiEnabled;
+            }
+            throw new IllegalArgumentException(
+                    "isAdbEnabled called with unimplemented transport type=" + transportType);
         }
 
         @Override
@@ -109,77 +120,70 @@
         }
     }
 
-    private final class AdbHandler extends Handler {
-        AdbHandler(Looper looper) {
-            super(looper);
-            try {
-                /*
-                 * Use the normal bootmode persistent prop to maintain state of adb across
-                 * all boot modes.
-                 */
-                mAdbEnabled = containsFunction(
-                        SystemProperties.get(USB_PERSISTENT_CONFIG_PROPERTY, ""),
-                        UsbManager.USB_FUNCTION_ADB);
+    private void initAdbState() {
+        try {
+            /*
+             * Use the normal bootmode persistent prop to maintain state of adb across
+             * all boot modes.
+             */
+            mIsAdbUsbEnabled = containsFunction(
+                    SystemProperties.get(USB_PERSISTENT_CONFIG_PROPERTY, ""),
+                    UsbManager.USB_FUNCTION_ADB);
+            // TODO(joshuaduong): Read the adb wifi state from a persistent system
+            // property (persist.sys.adb.wifi).
+            mIsAdbWifiEnabled = false;
 
-                // register observer to listen for settings changes
-                mContentResolver.registerContentObserver(
-                        Settings.Global.getUriFor(Settings.Global.ADB_ENABLED),
-                        false, new AdbSettingsObserver());
-            } catch (Exception e) {
-                Slog.e(TAG, "Error initializing AdbHandler", e);
-            }
-        }
-
-        private boolean containsFunction(String functions, String function) {
-            int index = functions.indexOf(function);
-            if (index < 0) return false;
-            if (index > 0 && functions.charAt(index - 1) != ',') return false;
-            int charAfter = index + function.length();
-            if (charAfter < functions.length() && functions.charAt(charAfter) != ',') return false;
-            return true;
-        }
-
-        public void sendMessage(int what, boolean arg) {
-            removeMessages(what);
-            Message m = Message.obtain(this, what);
-            m.arg1 = (arg ? 1 : 0);
-            sendMessage(m);
-        }
-
-        @Override
-        public void handleMessage(Message msg) {
-            switch (msg.what) {
-                case MSG_ENABLE_ADB:
-                    setAdbEnabled(msg.arg1 == 1);
-                    break;
-                case MSG_BOOT_COMPLETED:
-                    if (mDebuggingManager != null) {
-                        mDebuggingManager.setAdbEnabled(mAdbEnabled);
-                    }
-                    break;
-            }
+            // register observer to listen for settings changes
+            mObserver = new AdbSettingsObserver();
+            mContentResolver.registerContentObserver(
+                    Settings.Global.getUriFor(Settings.Global.ADB_ENABLED),
+                    false, mObserver);
+            mContentResolver.registerContentObserver(
+                    Settings.Global.getUriFor(Settings.Global.ADB_WIFI_ENABLED),
+                    false, mObserver);
+        } catch (Exception e) {
+            Slog.e(TAG, "Error in initAdbState", e);
         }
     }
 
+    private static boolean containsFunction(String functions, String function) {
+        int index = functions.indexOf(function);
+        if (index < 0) return false;
+        if (index > 0 && functions.charAt(index - 1) != ',') return false;
+        int charAfter = index + function.length();
+        if (charAfter < functions.length() && functions.charAt(charAfter) != ',') return false;
+        return true;
+    }
+
     private class AdbSettingsObserver extends ContentObserver {
+        private final Uri mAdbUsbUri = Settings.Global.getUriFor(Settings.Global.ADB_ENABLED);
+        private final Uri mAdbWifiUri = Settings.Global.getUriFor(Settings.Global.ADB_WIFI_ENABLED);
+
         AdbSettingsObserver() {
             super(null);
         }
 
         @Override
-        public void onChange(boolean selfChange) {
-            boolean enable = (Settings.Global.getInt(mContentResolver,
-                    Settings.Global.ADB_ENABLED, 0) > 0);
-            mHandler.sendMessage(MSG_ENABLE_ADB, enable);
+        public void onChange(boolean selfChange, @NonNull Uri uri, @UserIdInt int userId) {
+            if (mAdbUsbUri.equals(uri)) {
+                boolean shouldEnable = (Settings.Global.getInt(mContentResolver,
+                        Settings.Global.ADB_ENABLED, 0) > 0);
+                FgThread.getHandler().sendMessage(obtainMessage(
+                        AdbService::setAdbEnabled, AdbService.this, shouldEnable,
+                            AdbTransportType.USB));
+            } else if (mAdbWifiUri.equals(uri)) {
+                boolean shouldEnable = (Settings.Global.getInt(mContentResolver,
+                        Settings.Global.ADB_WIFI_ENABLED, 0) > 0);
+                FgThread.getHandler().sendMessage(obtainMessage(
+                        AdbService::setAdbEnabled, AdbService.this, shouldEnable,
+                            AdbTransportType.WIFI));
+            }
         }
     }
 
     private static final String TAG = "AdbService";
     private static final boolean DEBUG = false;
 
-    private static final int MSG_ENABLE_ADB = 1;
-    private static final int MSG_BOOT_COMPLETED = 2;
-
     /**
      * The persistent property which stores whether adb is enabled or not.
      * May also contain vendor-specific default functions for testing purposes.
@@ -188,12 +192,14 @@
 
     private final Context mContext;
     private final ContentResolver mContentResolver;
-    private final AdbService.AdbHandler mHandler;
     private final ArrayMap<IBinder, IAdbTransport> mTransports = new ArrayMap<>();
 
-    private boolean mAdbEnabled;
+    private boolean mIsAdbUsbEnabled;
+    private boolean mIsAdbWifiEnabled;
     private AdbDebuggingManager mDebuggingManager;
 
+    private ContentObserver mObserver;
+
     private AdbService(Context context) {
         mContext = context;
         mContentResolver = context.getContentResolver();
@@ -204,8 +210,7 @@
             mDebuggingManager = new AdbDebuggingManager(context);
         }
 
-        mHandler = new AdbHandler(FgThread.get().getLooper());
-
+        initAdbState();
         LocalServices.addService(AdbManagerInternal.class, new AdbManagerInternalImpl());
     }
 
@@ -219,7 +224,9 @@
         // make sure the ADB_ENABLED setting value matches the current state
         try {
             Settings.Global.putInt(mContentResolver,
-                    Settings.Global.ADB_ENABLED, mAdbEnabled ? 1 : 0);
+                    Settings.Global.ADB_ENABLED, mIsAdbUsbEnabled ? 1 : 0);
+            Settings.Global.putInt(mContentResolver,
+                    Settings.Global.ADB_WIFI_ENABLED, mIsAdbWifiEnabled ? 1 : 0);
         } catch (SecurityException e) {
             // If UserManager.DISALLOW_DEBUGGING_FEATURES is on, that this setting can't be changed.
             Slog.d(TAG, "ADB_ENABLED is restricted.");
@@ -231,7 +238,10 @@
      */
     public void bootCompleted() {
         if (DEBUG) Slog.d(TAG, "boot completed");
-        mHandler.sendEmptyMessage(MSG_BOOT_COMPLETED);
+        if (mDebuggingManager != null) {
+            mDebuggingManager.setAdbEnabled(mIsAdbUsbEnabled, AdbTransportType.USB);
+            mDebuggingManager.setAdbEnabled(mIsAdbWifiEnabled, AdbTransportType.WIFI);
+        }
     }
 
     @Override
@@ -285,24 +295,82 @@
                 PackageManager.FEATURE_CAMERA_ANY);
     }
 
-    private void setAdbEnabled(boolean enable) {
-        if (DEBUG) Slog.d(TAG, "setAdbEnabled(" + enable + "), mAdbEnabled=" + mAdbEnabled);
+    @Override
+    public void allowWirelessDebugging(boolean alwaysAllow, String bssid) {
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_DEBUGGING, null);
+        // TODO(joshuaduong): NOT IMPLEMENTED
+    }
 
-        if (enable == mAdbEnabled) {
+    @Override
+    public void denyWirelessDebugging() {
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_DEBUGGING, null);
+        // TODO(joshuaduong): NOT IMPLEMENTED
+    }
+
+    @Override
+    public Map<String, PairDevice> getPairedDevices() {
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_DEBUGGING, null);
+        // TODO(joshuaduong): NOT IMPLEMENTED
+        return null;
+    }
+
+    @Override
+    public void unpairDevice(String fingerprint) {
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_DEBUGGING, null);
+        // TODO(joshuaduong): NOT IMPLEMENTED
+    }
+
+    @Override
+    public void enablePairingByPairingCode() {
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_DEBUGGING, null);
+        // TODO(joshuaduong): NOT IMPLEMENTED
+    }
+
+    @Override
+    public void enablePairingByQrCode(String serviceName, String password) {
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_DEBUGGING, null);
+        // TODO(joshuaduong): NOT IMPLEMENTED
+    }
+
+    @Override
+    public void disablePairing() {
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_DEBUGGING, null);
+        // TODO(joshuaduong): NOT IMPLEMENTED
+    }
+
+    @Override
+    public int getAdbWirelessPort() {
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_DEBUGGING, null);
+        // TODO(joshuaduong): NOT IMPLEMENTED
+        return 0;
+    }
+
+    private void setAdbEnabled(boolean enable, byte transportType) {
+        if (DEBUG) {
+            Slog.d(TAG, "setAdbEnabled(" + enable + "), mIsAdbUsbEnabled=" + mIsAdbUsbEnabled
+                    + ", mIsAdbWifiEnabled=" + mIsAdbWifiEnabled + ", transportType="
+                        + transportType);
+        }
+
+        if (transportType == AdbTransportType.USB && enable != mIsAdbUsbEnabled) {
+            mIsAdbUsbEnabled = enable;
+        } else if (transportType == AdbTransportType.WIFI && enable != mIsAdbWifiEnabled) {
+            mIsAdbWifiEnabled = enable;
+        } else {
+            // No change
             return;
         }
-        mAdbEnabled = enable;
 
         for (IAdbTransport transport : mTransports.values()) {
             try {
-                transport.onAdbEnabled(enable);
+                transport.onAdbEnabled(enable, transportType);
             } catch (RemoteException e) {
                 Slog.w(TAG, "Unable to send onAdbEnabled to transport " + transport.toString());
             }
         }
 
         if (mDebuggingManager != null) {
-            mDebuggingManager.setAdbEnabled(enable);
+            mDebuggingManager.setAdbEnabled(enable, transportType);
         }
     }
 
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 50f43b5..2bcb28d 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -62,7 +62,6 @@
 import android.content.pm.ParceledListSlice;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
-import android.content.res.Resources;
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Build;
@@ -91,7 +90,6 @@
 import android.util.TimeUtils;
 import android.util.proto.ProtoOutputStream;
 import android.webkit.WebViewZygote;
-import android.widget.Toast;
 
 import com.android.internal.R;
 import com.android.internal.app.procstats.ServiceState;
@@ -4687,20 +4685,35 @@
     }
 
     // TODO: remove this toast after feature development is done
-    private void showWhileInUsePermissionInFgsBlockedToastLocked(String callingPackage) {
-        final Resources res = mAm.mContext.getResources();
-        final String toastMsg = res.getString(
-                        R.string.allow_while_in_use_permission_in_fgs, callingPackage);
-        mAm.mUiHandler.post(() -> {
-            Toast.makeText(mAm.mContext, toastMsg, Toast.LENGTH_LONG).show();
-        });
+    private void showWhileInUsePermissionInFgsBlockedNotificationLocked(String callingPackage,
+            String detailInfo) {
+        final Context context = mAm.mContext;
+        final String title = "Foreground Service While-in-use Permission Restricted";
+        final String content = "App affected:" + callingPackage + ", please file a bug report";
+        Notification.Builder n =
+                new Notification.Builder(context,
+                        SystemNotificationChannels.ALERTS)
+                        .setSmallIcon(R.drawable.stat_sys_vitals)
+                        .setWhen(0)
+                        .setColor(context.getColor(
+                                com.android.internal.R.color.system_notification_accent_color))
+                        .setTicker(title)
+                        .setContentTitle(title)
+                        .setContentText(content)
+                        .setStyle(new Notification.BigTextStyle().bigText(detailInfo));
+        final NotificationManager notificationManager =
+                (NotificationManager) context.getSystemService(context.NOTIFICATION_SERVICE);
+        notificationManager.notifyAsUser(null,
+                SystemMessageProto.SystemMessage.NOTE_FOREGROUND_SERVICE_WHILE_IN_USE_PERMISSION,
+                n.build(), UserHandle.ALL);
     }
 
     // TODO: remove this toast after feature development is done
     // show a toast message to ask user to file a bugreport so we know how many apps are impacted by
     // the new background started foreground service while-in-use permission restriction.
-    void showWhileInUseDebugToastLocked(int uid, int op, int mode) {
-        StringBuilder sb = new StringBuilder();
+    void showWhileInUseDebugNotificationLocked(int uid, int op, int mode) {
+        StringBuilder packageNameBuilder = new StringBuilder();
+        StringBuilder detailInfoBuilder = new StringBuilder();
         for (int i = mAm.mProcessList.mLruProcesses.size() - 1; i >= 0; i--) {
             ProcessRecord pr = mAm.mProcessList.mLruProcesses.get(i);
             if (pr.uid != uid) {
@@ -4713,17 +4726,22 @@
                 }
                 if (!r.mAllowWhileInUsePermissionInFgs
                         && r.mInfoDenyWhileInUsePermissionInFgs != null) {
-                    Slog.wtf(TAG, r.mInfoDenyWhileInUsePermissionInFgs
-                            + " affected while-use-permission:" + AppOpsManager.opToPublicName(op));
-                    sb.append(r.mRecentCallingPackage + " ");
+                    final String msg = r.mInfoDenyWhileInUsePermissionInFgs
+                            + " affected while-in-use permission:"
+                            + AppOpsManager.opToPublicName(op);
+                    Slog.wtf(TAG, msg);
+                    packageNameBuilder.append(r.mRecentCallingPackage + " ");
+                    detailInfoBuilder.append(msg);
+                    detailInfoBuilder.append("\n");
                 }
             }
         }
 
-        final String callingPackageStr = sb.toString();
+        final String callingPackageStr = packageNameBuilder.toString();
         if (mAm.mConstants.mFlagForegroundServiceStartsLoggingEnabled
                 && !callingPackageStr.isEmpty()) {
-            showWhileInUsePermissionInFgsBlockedToastLocked(callingPackageStr);
+            showWhileInUsePermissionInFgsBlockedNotificationLocked(callingPackageStr,
+                    detailInfoBuilder.toString());
         }
     }
 }
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 9082807..a529f24 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -1045,6 +1045,11 @@
         }
 
         @Override
+        protected IntentFilter getIntentFilter(@NonNull BroadcastFilter input) {
+            return input;
+        }
+
+        @Override
         protected BroadcastFilter[] newArray(int size) {
             return new BroadcastFilter[size];
         }
@@ -7266,7 +7271,7 @@
 
         // Wait for the provider to be published...
         final long timeout =
-                SystemClock.uptimeMillis() + ContentResolver.CONTENT_PROVIDER_WAIT_TIMEOUT_MILLIS;
+                SystemClock.uptimeMillis() + ContentResolver.CONTENT_PROVIDER_READY_TIMEOUT_MILLIS;
         boolean timedOut = false;
         synchronized (cpr) {
             while (cpr.provider == null) {
@@ -14605,6 +14610,11 @@
             if (index < 0) {
                 ProcessList.remove(app.pid);
             }
+
+            // Remove provider publish timeout because we will start a new timeout when the
+            // restarted process is attaching (if the process contains launching providers).
+            mHandler.removeMessages(CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG, app);
+
             mProcessList.addProcessNameLocked(app);
             app.pendingStart = false;
             mProcessList.startProcessLocked(app,
@@ -19333,7 +19343,8 @@
         @Override
         public void showWhileInUseDebugToast(int uid, int op, int mode) {
             synchronized (ActivityManagerService.this) {
-                ActivityManagerService.this.mServices.showWhileInUseDebugToastLocked(uid, op, mode);
+                ActivityManagerService.this.mServices.showWhileInUseDebugNotificationLocked(
+                        uid, op, mode);
             }
         }
     }
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index ed6ace3..119394f 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -1135,7 +1135,7 @@
     @Override
     public void setBatteryState(final int status, final int health, final int plugType,
             final int level, final int temp, final int volt, final int chargeUAh,
-            final int chargeFullUAh) {
+            final int chargeFullUAh, final long chargeTimeToFullSeconds) {
         enforceCallingPermission();
 
         // BatteryService calls us here and we may update external state. It would be wrong
@@ -1147,7 +1147,7 @@
                     // The battery state has not changed, so we don't need to sync external
                     // stats immediately.
                     mStats.setBatteryStateLocked(status, health, plugType, level, temp, volt,
-                            chargeUAh, chargeFullUAh);
+                            chargeUAh, chargeFullUAh, chargeTimeToFullSeconds);
                     return;
                 }
             }
@@ -1160,7 +1160,7 @@
             mWorker.scheduleRunnable(() -> {
                 synchronized (mStats) {
                     mStats.setBatteryStateLocked(status, health, plugType, level, temp, volt,
-                            chargeUAh, chargeFullUAh);
+                            chargeUAh, chargeFullUAh, chargeTimeToFullSeconds);
                 }
             });
         });
diff --git a/services/core/java/com/android/server/am/CoreSettingsObserver.java b/services/core/java/com/android/server/am/CoreSettingsObserver.java
index a03f0bb..48ceba9 100644
--- a/services/core/java/com/android/server/am/CoreSettingsObserver.java
+++ b/services/core/java/com/android/server/am/CoreSettingsObserver.java
@@ -16,6 +16,7 @@
 
 package com.android.server.am;
 
+import android.annotation.NonNull;
 import android.app.ActivityThread;
 import android.content.Context;
 import android.database.ContentObserver;
@@ -32,6 +33,7 @@
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 
 /**
  * Helper class for watching a set of core settings which the framework
@@ -42,16 +44,20 @@
 final class CoreSettingsObserver extends ContentObserver {
     private static final String LOG_TAG = CoreSettingsObserver.class.getSimpleName();
 
-    private static class DeviceConfigEntry {
+    private static class DeviceConfigEntry<T> {
         String namespace;
         String flag;
         String coreSettingKey;
-        Class<?> type;
-        DeviceConfigEntry(String namespace, String flag, String coreSettingKey, Class<?> type) {
+        Class<T> type;
+        T defaultValue;
+
+        DeviceConfigEntry(String namespace, String flag, String coreSettingKey, Class<T> type,
+                @NonNull T defaultValue) {
             this.namespace = namespace;
             this.flag = flag;
             this.coreSettingKey = coreSettingKey;
             this.type = type;
+            this.defaultValue = Objects.requireNonNull(defaultValue);
         }
     }
 
@@ -105,24 +111,34 @@
         sGlobalSettingToTypeMap.put(Settings.Global.GAME_DRIVER_SPHAL_LIBRARIES, String.class);
         // add other global settings here...
 
-        sDeviceConfigEntries.add(new DeviceConfigEntry(
-                DeviceConfig.NAMESPACE_WIDGET, WidgetFlags.ENABLE_CURSOR_CONTROL,
-                WidgetFlags.KEY_ENABLE_CURSOR_CONTROL, boolean.class));
-        sDeviceConfigEntries.add(new DeviceConfigEntry(
+        sDeviceConfigEntries.add(new DeviceConfigEntry<Boolean>(
+                DeviceConfig.NAMESPACE_WIDGET, WidgetFlags.ENABLE_CURSOR_DRAG_FROM_ANYWHERE,
+                WidgetFlags.KEY_ENABLE_CURSOR_DRAG_FROM_ANYWHERE, boolean.class,
+                WidgetFlags.ENABLE_CURSOR_DRAG_FROM_ANYWHERE_DEFAULT));
+        sDeviceConfigEntries.add(new DeviceConfigEntry<Boolean>(
+                DeviceConfig.NAMESPACE_WIDGET, WidgetFlags.ENABLE_INSERTION_HANDLE_GESTURES,
+                WidgetFlags.KEY_ENABLE_INSERTION_HANDLE_GESTURES, boolean.class,
+                WidgetFlags.ENABLE_INSERTION_HANDLE_GESTURES_DEFAULT));
+        sDeviceConfigEntries.add(new DeviceConfigEntry<Integer>(
                 DeviceConfig.NAMESPACE_WIDGET, WidgetFlags.INSERTION_HANDLE_DELTA_HEIGHT,
-                WidgetFlags.KEY_INSERTION_HANDLE_DELTA_HEIGHT, int.class));
-        sDeviceConfigEntries.add(new DeviceConfigEntry(
+                WidgetFlags.KEY_INSERTION_HANDLE_DELTA_HEIGHT, int.class,
+                WidgetFlags.INSERTION_HANDLE_DELTA_HEIGHT_DEFAULT));
+        sDeviceConfigEntries.add(new DeviceConfigEntry<Integer>(
                 DeviceConfig.NAMESPACE_WIDGET, WidgetFlags.INSERTION_HANDLE_OPACITY,
-                WidgetFlags.KEY_INSERTION_HANDLE_OPACITY, int.class));
-        sDeviceConfigEntries.add(new DeviceConfigEntry(
+                WidgetFlags.KEY_INSERTION_HANDLE_OPACITY, int.class,
+                WidgetFlags.INSERTION_HANDLE_OPACITY_DEFAULT));
+        sDeviceConfigEntries.add(new DeviceConfigEntry<Boolean>(
                 DeviceConfig.NAMESPACE_WIDGET, WidgetFlags.ENABLE_NEW_MAGNIFIER,
-                WidgetFlags.KEY_ENABLE_NEW_MAGNIFIER, boolean.class));
-        sDeviceConfigEntries.add(new DeviceConfigEntry(
+                WidgetFlags.KEY_ENABLE_NEW_MAGNIFIER, boolean.class,
+                WidgetFlags.ENABLE_NEW_MAGNIFIER_DEFAULT));
+        sDeviceConfigEntries.add(new DeviceConfigEntry<Float>(
                 DeviceConfig.NAMESPACE_WIDGET, WidgetFlags.MAGNIFIER_ZOOM_FACTOR,
-                WidgetFlags.KEY_MAGNIFIER_ZOOM_FACTOR, float.class));
-        sDeviceConfigEntries.add(new DeviceConfigEntry(
+                WidgetFlags.KEY_MAGNIFIER_ZOOM_FACTOR, float.class,
+                WidgetFlags.MAGNIFIER_ZOOM_FACTOR_DEFAULT));
+        sDeviceConfigEntries.add(new DeviceConfigEntry<Float>(
                 DeviceConfig.NAMESPACE_WIDGET, WidgetFlags.MAGNIFIER_ASPECT_RATIO,
-                WidgetFlags.KEY_MAGNIFIER_ASPECT_RATIO, float.class));
+                WidgetFlags.KEY_MAGNIFIER_ASPECT_RATIO, float.class,
+                WidgetFlags.MAGNIFIER_ASPECT_RATIO_DEFAULT));
         // add other device configs here...
     }
 
@@ -216,23 +232,29 @@
         }
     }
 
+    @SuppressWarnings("unchecked")
     private void populateSettingsFromDeviceConfig() {
-        for (DeviceConfigEntry entry : sDeviceConfigEntries) {
+        for (DeviceConfigEntry<?> entry : sDeviceConfigEntries) {
             if (entry.type == String.class) {
+                String defaultValue = ((DeviceConfigEntry<String>) entry).defaultValue;
                 mCoreSettings.putString(entry.coreSettingKey,
-                        DeviceConfig.getString(entry.namespace, entry.flag, ""));
+                        DeviceConfig.getString(entry.namespace, entry.flag, defaultValue));
             } else if (entry.type == int.class) {
+                int defaultValue = ((DeviceConfigEntry<Integer>) entry).defaultValue;
                 mCoreSettings.putInt(entry.coreSettingKey,
-                        DeviceConfig.getInt(entry.namespace, entry.flag, 0));
+                        DeviceConfig.getInt(entry.namespace, entry.flag, defaultValue));
             } else if (entry.type == float.class) {
+                float defaultValue = ((DeviceConfigEntry<Float>) entry).defaultValue;
                 mCoreSettings.putFloat(entry.coreSettingKey,
-                        DeviceConfig.getFloat(entry.namespace, entry.flag, 0));
+                        DeviceConfig.getFloat(entry.namespace, entry.flag, defaultValue));
             } else if (entry.type == long.class) {
+                long defaultValue = ((DeviceConfigEntry<Long>) entry).defaultValue;
                 mCoreSettings.putLong(entry.coreSettingKey,
-                        DeviceConfig.getLong(entry.namespace, entry.flag, 0));
+                        DeviceConfig.getLong(entry.namespace, entry.flag, defaultValue));
             } else if (entry.type == boolean.class) {
+                boolean defaultValue = ((DeviceConfigEntry<Boolean>) entry).defaultValue;
                 mCoreSettings.putInt(entry.coreSettingKey,
-                        DeviceConfig.getBoolean(entry.namespace, entry.flag, false) ? 1 : 0);
+                        DeviceConfig.getBoolean(entry.namespace, entry.flag, defaultValue) ? 1 : 0);
             }
         }
     }
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index a2ae678..c239feb1 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -1128,6 +1128,7 @@
             app.setCurRawAdj(app.maxAdj);
             app.setHasForegroundActivities(false);
             app.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_DEFAULT);
+            app.curCapability = PROCESS_CAPABILITY_ALL;
             app.setCurProcState(ActivityManager.PROCESS_STATE_PERSISTENT);
             // System processes can do UI, and when they do we want to have
             // them trim their memory after the user leaves the UI.  To
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 0dc44f7..22559c4 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -345,6 +345,14 @@
     @EnabledAfter(targetSdkVersion = VersionCodes.Q)
     private static final long NATIVE_HEAP_POINTER_TAGGING = 135754954; // This is a bug id.
 
+    /**
+     * Apps have no access to the private data directories of any other app, even if the other
+     * app has made them world-readable.
+     */
+    @ChangeId
+    @EnabledAfter(targetSdkVersion = VersionCodes.Q)
+    private static final long APP_DATA_DIRECTORY_ISOLATION = 143937733; // See b/143937733
+
     ActivityManagerService mService = null;
 
     // To kill process groups asynchronously
@@ -2070,7 +2078,14 @@
         }
         final int minTargetSdk = DeviceConfig.getInt(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
                 ANDROID_APP_DATA_ISOLATION_MIN_SDK, Build.VERSION_CODES.R);
-        return app.info.targetSdkVersion >= minTargetSdk;
+        if (app.info.targetSdkVersion < minTargetSdk) {
+            return false;
+        }
+
+        // TODO(b/147266020): Remove non-standard gating above & switch to isChangeEnabled.
+        mPlatformCompat.reportChange(APP_DATA_DIRECTORY_ISOLATION, app.info);
+
+        return true;
     }
 
     private Map<String, Pair<String, Long>> getPackageAppDataInfoMap(PackageManagerInternal pmInt,
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index 5d8a0f6..4670d58 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -401,10 +401,10 @@
             pw.print(prefix); pw.print("hasStartedWhitelistingBgActivityStarts=");
             pw.println(mHasStartedWhitelistingBgActivityStarts);
         }
-        if (mAllowWhileInUsePermissionInFgs) {
-            pw.print(prefix); pw.print("allowWhileInUsePermissionInFgs=");
-            pw.println(mAllowWhileInUsePermissionInFgs);
-        }
+        pw.print(prefix); pw.print("allowWhileInUsePermissionInFgs=");
+                pw.println(mAllowWhileInUsePermissionInFgs);
+        pw.print(prefix); pw.print("recentCallingPackage=");
+                pw.println(mRecentCallingPackage);
         if (delayed) {
             pw.print(prefix); pw.print("delayed="); pw.println(delayed);
         }
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 40acfe1..7462f7f 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -98,8 +98,7 @@
 import android.content.pm.PackageManagerInternal;
 import android.content.pm.PermissionInfo;
 import android.content.pm.UserInfo;
-import android.content.pm.parsing.AndroidPackage;
-import android.content.pm.parsing.ComponentParseUtils.ParsedFeature;
+import android.content.pm.parsing.component.ParsedFeature;
 import android.database.ContentObserver;
 import android.hardware.camera2.CameraDevice.CAMERA_AUDIO_RESTRICTION;
 import android.net.Uri;
@@ -156,6 +155,7 @@
 import com.android.server.LockGuard;
 import com.android.server.SystemServerInitThreadPool;
 import com.android.server.pm.PackageList;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
 
 import libcore.util.EmptyArray;
 
diff --git a/services/core/java/com/android/server/biometrics/AuthService.java b/services/core/java/com/android/server/biometrics/AuthService.java
index 204f072..8ed221d 100644
--- a/services/core/java/com/android/server/biometrics/AuthService.java
+++ b/services/core/java/com/android/server/biometrics/AuthService.java
@@ -311,6 +311,7 @@
                 }
 
                 authenticator = new FingerprintAuthenticator(fingerprintService);
+                fingerprintService.initConfiguredStrength(config.mStrength);
                 break;
 
             case TYPE_FACE:
@@ -322,6 +323,7 @@
                 }
 
                 authenticator = new FaceAuthenticator(faceService);
+                faceService.initConfiguredStrength(config.mStrength);
                 break;
 
             case TYPE_IRIS:
@@ -333,6 +335,7 @@
                 }
 
                 authenticator = new IrisAuthenticator(irisService);
+                irisService.initConfiguredStrength(config.mStrength);
                 break;
 
             default:
diff --git a/services/core/java/com/android/server/biometrics/BiometricServiceBase.java b/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
index 0e70994..74c70df 100644
--- a/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
+++ b/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
@@ -31,6 +31,7 @@
 import android.content.pm.UserInfo;
 import android.hardware.biometrics.BiometricAuthenticator;
 import android.hardware.biometrics.BiometricConstants;
+import android.hardware.biometrics.BiometricManager;
 import android.hardware.biometrics.BiometricsProtoEnums;
 import android.hardware.biometrics.IBiometricNativeHandle;
 import android.hardware.biometrics.IBiometricService;
@@ -106,6 +107,7 @@
     private PerformanceStats mPerformanceStats;
     protected int mCurrentUserId = UserHandle.USER_NULL;
     protected long mHalDeviceId;
+    private int mOEMStrength; // Tracks the OEM configured biometric modality strength
     // Tracks if the current authentication makes use of CryptoObjects.
     protected boolean mIsCrypto;
     // Normal authentications are tracked by mPerformanceMap.
@@ -681,6 +683,20 @@
                 statsModality(), BiometricsProtoEnums.ISSUE_HAL_DEATH);
     }
 
+    protected void initConfiguredStrengthInternal(int strength) {
+        if (DEBUG) {
+            Slog.d(getTag(), "initConfiguredStrengthInternal(" + strength + ")");
+        }
+        mOEMStrength = strength;
+    }
+
+    protected boolean isStrongBiometric() {
+        // TODO(b/141025588): need to calculate actual strength when downgrading tiers
+        final int biometricBits = mOEMStrength
+                & BiometricManager.Authenticators.BIOMETRIC_MIN_STRENGTH;
+        return biometricBits == BiometricManager.Authenticators.BIOMETRIC_STRONG;
+    }
+
     protected ClientMonitor getCurrentClient() {
         return mCurrentClient;
     }
diff --git a/services/core/java/com/android/server/biometrics/face/FaceService.java b/services/core/java/com/android/server/biometrics/face/FaceService.java
index 31c3d4d..a87a455 100644
--- a/services/core/java/com/android/server/biometrics/face/FaceService.java
+++ b/services/core/java/com/android/server/biometrics/face/FaceService.java
@@ -740,6 +740,12 @@
             }
             return 0;
         }
+
+        @Override // Binder call
+        public void initConfiguredStrength(int strength) {
+            checkPermission(USE_BIOMETRIC_INTERNAL);
+            initConfiguredStrengthInternal(strength);
+        }
     }
 
     /**
@@ -809,7 +815,7 @@
             if (mFaceServiceReceiver != null) {
                 if (biometric == null || biometric instanceof Face) {
                     mFaceServiceReceiver.onAuthenticationSucceeded(deviceId, (Face) biometric,
-                            userId);
+                            userId, isStrongBiometric());
                 } else {
                     Slog.e(TAG, "onAuthenticationSucceeded received non-face biometric");
                 }
diff --git a/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
index 0a61988..83aa9cf 100644
--- a/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
@@ -21,6 +21,7 @@
 import static android.Manifest.permission.MANAGE_FINGERPRINT;
 import static android.Manifest.permission.RESET_FINGERPRINT_LOCKOUT;
 import static android.Manifest.permission.USE_BIOMETRIC;
+import static android.Manifest.permission.USE_BIOMETRIC_INTERNAL;
 import static android.Manifest.permission.USE_FINGERPRINT;
 import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT;
 
@@ -462,6 +463,12 @@
             checkPermission(MANAGE_FINGERPRINT);
             mClientActiveCallbacks.remove(callback);
         }
+
+        @Override // Binder call
+        public void initConfiguredStrength(int strength) {
+            checkPermission(USE_BIOMETRIC_INTERNAL);
+            initConfiguredStrengthInternal(strength);
+        }
     }
 
     /**
@@ -526,8 +533,8 @@
                 throws RemoteException {
             if (mFingerprintServiceReceiver != null) {
                 if (biometric == null || biometric instanceof Fingerprint) {
-                    mFingerprintServiceReceiver
-                            .onAuthenticationSucceeded(deviceId, (Fingerprint) biometric, userId);
+                    mFingerprintServiceReceiver.onAuthenticationSucceeded(deviceId,
+                            (Fingerprint) biometric, userId, isStrongBiometric());
                 } else {
                     Slog.e(TAG, "onAuthenticationSucceeded received non-fingerprint biometric");
                 }
diff --git a/services/core/java/com/android/server/biometrics/iris/IrisService.java b/services/core/java/com/android/server/biometrics/iris/IrisService.java
index 2817315..903ae6b 100644
--- a/services/core/java/com/android/server/biometrics/iris/IrisService.java
+++ b/services/core/java/com/android/server/biometrics/iris/IrisService.java
@@ -16,9 +16,12 @@
 
 package com.android.server.biometrics.iris;
 
+import static android.Manifest.permission.USE_BIOMETRIC_INTERNAL;
+
 import android.content.Context;
 import android.hardware.biometrics.BiometricAuthenticator;
 import android.hardware.biometrics.BiometricsProtoEnums;
+import android.hardware.iris.IIrisService;
 
 import com.android.server.biometrics.AuthenticationClient;
 import com.android.server.biometrics.BiometricServiceBase;
@@ -42,6 +45,17 @@
     private static final String TAG = "IrisService";
 
     /**
+     * Receives the incoming binder calls from IrisManager.
+     */
+    private final class IrisServiceWrapper extends IIrisService.Stub {
+        @Override // Binder call
+        public void initConfiguredStrength(int strength) {
+            checkPermission(USE_BIOMETRIC_INTERNAL);
+            initConfiguredStrengthInternal(strength);
+        }
+    }
+
+    /**
      * Initializes the system service.
      * <p>
      * Subclasses must define a single argument constructor that accepts the context
@@ -57,6 +71,7 @@
     @Override
     public void onStart() {
         super.onStart();
+        publishBinderService(Context.IRIS_SERVICE, new IrisServiceWrapper());
     }
 
     @Override
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 3138639..e484ca0 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -690,13 +690,14 @@
             // Prefer VPN profiles, if any exist.
             VpnProfile profile = getVpnProfilePrivileged(alwaysOnPackage, keyStore);
             if (profile != null) {
-                startVpnProfilePrivileged(profile, alwaysOnPackage);
+                startVpnProfilePrivileged(profile, alwaysOnPackage,
+                        null /* keyStore for private key retrieval - unneeded */);
 
                 // If the above startVpnProfilePrivileged() call returns, the Ikev2VpnProfile was
                 // correctly parsed, and the VPN has started running in a different thread. The only
                 // other possibility is that the above call threw an exception, which will be
                 // caught below, and returns false (clearing the always-on VPN). Once started, the
-                // Platform VPN cannot permanantly fail, and is resiliant to temporary failures. It
+                // Platform VPN cannot permanently fail, and is resilient to temporary failures. It
                 // will continue retrying until shut down by the user, or always-on is toggled off.
                 return true;
             }
@@ -818,6 +819,7 @@
     }
 
     /** Prepare the VPN for the given package. Does not perform permission checks. */
+    @GuardedBy("this")
     private void prepareInternal(String newPackage) {
         long token = Binder.clearCallingIdentity();
         try {
@@ -1943,6 +1945,27 @@
         // Prepare arguments for racoon.
         String[] racoon = null;
         switch (profile.type) {
+            case VpnProfile.TYPE_IKEV2_IPSEC_RSA:
+                // Secret key is still just the alias (not the actual private key). The private key
+                // is retrieved from the KeyStore during conversion of the VpnProfile to an
+                // Ikev2VpnProfile.
+                profile.ipsecSecret = Ikev2VpnProfile.PREFIX_KEYSTORE_ALIAS + privateKey;
+                profile.ipsecUserCert = userCert;
+                // Fallthrough
+            case VpnProfile.TYPE_IKEV2_IPSEC_USER_PASS:
+                profile.ipsecCaCert = caCert;
+
+                // Start VPN profile
+                startVpnProfilePrivileged(profile, VpnConfig.LEGACY_VPN, keyStore);
+                return;
+            case VpnProfile.TYPE_IKEV2_IPSEC_PSK:
+                // Ikev2VpnProfiles expect a base64-encoded preshared key.
+                profile.ipsecSecret =
+                        Ikev2VpnProfile.encodeForIpsecSecret(profile.ipsecSecret.getBytes());
+
+                // Start VPN profile
+                startVpnProfilePrivileged(profile, VpnConfig.LEGACY_VPN, keyStore);
+                return;
             case VpnProfile.TYPE_L2TP_IPSEC_PSK:
                 racoon = new String[] {
                     iface, profile.server, "udppsk", profile.ipsecIdentifier,
@@ -2949,24 +2972,35 @@
                         throw new IllegalArgumentException("No profile found for " + packageName);
                     }
 
-                    startVpnProfilePrivileged(profile, packageName);
+                    startVpnProfilePrivileged(profile, packageName,
+                            null /* keyStore for private key retrieval - unneeded */);
                 });
     }
 
-    private void startVpnProfilePrivileged(
-            @NonNull VpnProfile profile, @NonNull String packageName) {
-        // Ensure that no other previous instance is running.
-        if (mVpnRunner != null) {
-            mVpnRunner.exit();
-            mVpnRunner = null;
-        }
+    private synchronized void startVpnProfilePrivileged(
+            @NonNull VpnProfile profile, @NonNull String packageName, @Nullable KeyStore keyStore) {
+        // Make sure VPN is prepared. This method can be called by user apps via startVpnProfile(),
+        // by the Setting app via startLegacyVpn(), or by ConnectivityService via
+        // startAlwaysOnVpn(), so this is the common place to prepare the VPN. This also has the
+        // nice property of ensuring there are no other VpnRunner instances running.
+        prepareInternal(packageName);
         updateState(DetailedState.CONNECTING, "startPlatformVpn");
 
         try {
             // Build basic config
             mConfig = new VpnConfig();
-            mConfig.user = packageName;
-            mConfig.isMetered = profile.isMetered;
+            if (VpnConfig.LEGACY_VPN.equals(packageName)) {
+                mConfig.legacy = true;
+                mConfig.session = profile.name;
+                mConfig.user = profile.key;
+
+                // TODO: Add support for configuring meteredness via Settings. Until then, use a
+                // safe default.
+                mConfig.isMetered = true;
+            } else {
+                mConfig.user = packageName;
+                mConfig.isMetered = profile.isMetered;
+            }
             mConfig.startTime = SystemClock.elapsedRealtime();
             mConfig.proxyInfo = profile.proxy;
 
@@ -2974,7 +3008,8 @@
                 case VpnProfile.TYPE_IKEV2_IPSEC_USER_PASS:
                 case VpnProfile.TYPE_IKEV2_IPSEC_PSK:
                 case VpnProfile.TYPE_IKEV2_IPSEC_RSA:
-                    mVpnRunner = new IkeV2VpnRunner(Ikev2VpnProfile.fromVpnProfile(profile));
+                    mVpnRunner =
+                            new IkeV2VpnRunner(Ikev2VpnProfile.fromVpnProfile(profile, keyStore));
                     mVpnRunner.start();
                     break;
                 default:
diff --git a/services/core/java/com/android/server/display/DisplayModeDirector.java b/services/core/java/com/android/server/display/DisplayModeDirector.java
index 8bbeabf..7cb8458 100644
--- a/services/core/java/com/android/server/display/DisplayModeDirector.java
+++ b/services/core/java/com/android/server/display/DisplayModeDirector.java
@@ -73,7 +73,7 @@
     private static final int GLOBAL_ID = -1;
 
     // The tolerance within which we consider something approximately equals.
-    private static final float EPSILON = 0.01f;
+    private static final float FLOAT_TOLERANCE = 0.01f;
 
     private final Object mLock = new Object();
     private final Context mContext;
@@ -267,8 +267,8 @@
             // Some refresh rates are calculated based on frame timings, so they aren't *exactly*
             // equal to expected refresh rate. Given that, we apply a bit of tolerance to this
             // comparison.
-            if (refreshRate < (minRefreshRate - EPSILON)
-                    || refreshRate > (maxRefreshRate + EPSILON)) {
+            if (refreshRate < (minRefreshRate - FLOAT_TOLERANCE)
+                    || refreshRate > (maxRefreshRate + FLOAT_TOLERANCE)) {
                 if (DEBUG) {
                     Slog.w(TAG, "Discarding mode " + mode.getModeId()
                             + ", outside refresh rate bounds"
@@ -487,12 +487,18 @@
         public RefreshRateRange() {}
 
         public RefreshRateRange(float min, float max) {
-            if (min < 0 || max < 0 || min > max) {
+            if (min < 0 || max < 0 || min > max + FLOAT_TOLERANCE) {
                 Slog.e(TAG, "Wrong values for min and max when initializing RefreshRateRange : "
                         + min + " " + max);
                 this.min = this.max = 0;
                 return;
             }
+            if (min > max) {
+                // Min and max are within epsilon of each other, but in the wrong order.
+                float t = min;
+                min = max;
+                max = t;
+            }
             this.min = min;
             this.max = max;
         }
diff --git a/services/core/java/com/android/server/firewall/IntentFirewall.java b/services/core/java/com/android/server/firewall/IntentFirewall.java
index c2af29c..1139d28 100644
--- a/services/core/java/com/android/server/firewall/IntentFirewall.java
+++ b/services/core/java/com/android/server/firewall/IntentFirewall.java
@@ -16,6 +16,7 @@
 
 package com.android.server.firewall;
 
+import android.annotation.NonNull;
 import android.app.AppGlobals;
 import android.content.ComponentName;
 import android.content.Intent;
@@ -521,6 +522,11 @@
             return;
         }
 
+        @Override
+        protected IntentFilter getIntentFilter(@NonNull FirewallIntentFilter input) {
+            return input;
+        }
+
         public void queryByComponent(ComponentName componentName, List<Rule> candidateRules) {
             Rule[] rules = mRulesByComponent.get(componentName);
             if (rules != null) {
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java
index 9f76e1e..eac2d24 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java
@@ -18,12 +18,11 @@
 
 import android.annotation.NonNull;
 import android.annotation.UserIdInt;
-import android.content.ComponentName;
-import android.view.autofill.AutofillId;
 import android.view.inputmethod.InlineSuggestionsRequest;
 import android.view.inputmethod.InputMethodInfo;
 
 import com.android.internal.view.IInlineSuggestionsRequestCallback;
+import com.android.internal.view.InlineSuggestionsRequestInfo;
 import com.android.server.LocalServices;
 
 import java.util.Collections;
@@ -74,13 +73,11 @@
      * Called by the Autofill Frameworks to request an {@link InlineSuggestionsRequest} from
      * the input method.
      *
-     * @param componentName {@link ComponentName} of current app/activity.
-     * @param autofillId {@link AutofillId} of currently focused field.
+     * @param requestInfo information needed to create an {@link InlineSuggestionsRequest}.
      * @param cb {@link IInlineSuggestionsRequestCallback} used to pass back the request object.
      */
     public abstract void onCreateInlineSuggestionsRequest(@UserIdInt int userId,
-            ComponentName componentName, AutofillId autofillId,
-            IInlineSuggestionsRequestCallback cb);
+            InlineSuggestionsRequestInfo requestInfo, IInlineSuggestionsRequestCallback cb);
 
     /**
      * Force switch to the enabled input method by {@code imeId} for current user. If the input
@@ -124,7 +121,7 @@
 
                 @Override
                 public void onCreateInlineSuggestionsRequest(int userId,
-                        ComponentName componentName, AutofillId autofillId,
+                        InlineSuggestionsRequestInfo requestInfo,
                         IInlineSuggestionsRequestCallback cb) {
                 }
 
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 47622f3..87262a8 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -109,7 +109,6 @@
 import android.view.Window;
 import android.view.WindowManager.LayoutParams;
 import android.view.WindowManager.LayoutParams.SoftInputModeFlags;
-import android.view.autofill.AutofillId;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InlineSuggestionsRequest;
 import android.view.inputmethod.InputBinding;
@@ -150,6 +149,7 @@
 import com.android.internal.view.IInputMethodManager;
 import com.android.internal.view.IInputMethodSession;
 import com.android.internal.view.IInputSessionCallback;
+import com.android.internal.view.InlineSuggestionsRequestInfo;
 import com.android.internal.view.InputBindResult;
 import com.android.server.EventLogTags;
 import com.android.server.LocalServices;
@@ -1388,6 +1388,44 @@
         }
     }
 
+    private static final class UserSwitchHandlerTask implements Runnable {
+        final InputMethodManagerService mService;
+
+        @UserIdInt
+        final int mToUserId;
+
+        @Nullable
+        IInputMethodClient mClientToBeReset;
+
+        UserSwitchHandlerTask(InputMethodManagerService service, @UserIdInt int toUserId,
+                @Nullable IInputMethodClient clientToBeReset) {
+            mService = service;
+            mToUserId = toUserId;
+            mClientToBeReset = clientToBeReset;
+        }
+
+        @Override
+        public void run() {
+            synchronized (mService.mMethodMap) {
+                if (mService.mUserSwitchHandlerTask != this) {
+                    // This task was already canceled before it is handled here. So do nothing.
+                    return;
+                }
+                mService.switchUserOnHandlerLocked(mService.mUserSwitchHandlerTask.mToUserId,
+                        mClientToBeReset);
+                mService.mUserSwitchHandlerTask = null;
+            }
+        }
+    }
+
+    /**
+     * When non-{@code null}, this represents pending user-switch task, which is to be executed as
+     * a handler callback.  This needs to be set and unset only within the lock.
+     */
+    @Nullable
+    @GuardedBy("mMethodMap")
+    private UserSwitchHandlerTask mUserSwitchHandlerTask;
+
     public static final class Lifecycle extends SystemService {
         private InputMethodManagerService mService;
 
@@ -1406,8 +1444,9 @@
         @Override
         public void onSwitchUser(@UserIdInt int userHandle) {
             // Called on ActivityManager thread.
-            // TODO: Dispatch this to a worker thread as needed.
-            mService.onSwitchUser(userHandle);
+            synchronized (mService.mMethodMap) {
+                mService.scheduleSwitchUserTaskLocked(userHandle, null /* clientToBeReset */);
+            }
         }
 
         @Override
@@ -1447,10 +1486,20 @@
         }
     }
 
-    void onSwitchUser(@UserIdInt int userId) {
-        synchronized (mMethodMap) {
-            switchUserLocked(userId);
+    @GuardedBy("mMethodMap")
+    void scheduleSwitchUserTaskLocked(@UserIdInt int userId,
+            @Nullable IInputMethodClient clientToBeReset) {
+        if (mUserSwitchHandlerTask != null) {
+            if (mUserSwitchHandlerTask.mToUserId == userId) {
+                mUserSwitchHandlerTask.mClientToBeReset = clientToBeReset;
+                return;
+            }
+            mHandler.removeCallbacks(mUserSwitchHandlerTask);
         }
+        final UserSwitchHandlerTask task = new UserSwitchHandlerTask(this, userId,
+                clientToBeReset);
+        mUserSwitchHandlerTask = task;
+        mHandler.post(task);
     }
 
     public InputMethodManagerService(Context context) {
@@ -1538,7 +1587,8 @@
     }
 
     @GuardedBy("mMethodMap")
-    private void switchUserLocked(int newUserId) {
+    private void switchUserOnHandlerLocked(@UserIdInt int newUserId,
+            IInputMethodClient clientToBeReset) {
         if (DEBUG) Slog.d(TAG, "Switching user stage 1/3. newUserId=" + newUserId
                 + " currentUserId=" + mSettings.getCurrentUserId());
 
@@ -1589,6 +1639,18 @@
                 + " selectedIme=" + mSettings.getSelectedInputMethod());
 
         mLastSwitchUserId = newUserId;
+
+        if (mIsInteractive && clientToBeReset != null) {
+            final ClientState cs = mClients.get(clientToBeReset.asBinder());
+            if (cs == null) {
+                // The client is already gone.
+                return;
+            }
+            try {
+                cs.client.scheduleStartInputIfNecessary(mInFullscreenMode);
+            } catch (RemoteException e) {
+            }
+        }
     }
 
     void updateCurrentProfileIds() {
@@ -1812,16 +1874,14 @@
 
     @GuardedBy("mMethodMap")
     private void onCreateInlineSuggestionsRequestLocked(@UserIdInt int userId,
-            ComponentName componentName, AutofillId autofillId,
-            IInlineSuggestionsRequestCallback callback) {
+            InlineSuggestionsRequestInfo requestInfo, IInlineSuggestionsRequestCallback callback) {
         final InputMethodInfo imi = mMethodMap.get(mCurMethodId);
         try {
             if (userId == mSettings.getCurrentUserId() && imi != null
                     && imi.isInlineSuggestionsEnabled() && mCurMethod != null) {
                 executeOrSendMessage(mCurMethod,
-                        mCaller.obtainMessageOOOO(MSG_INLINE_SUGGESTIONS_REQUEST, mCurMethod,
-                                componentName, autofillId,
-                                new InlineSuggestionsRequestCallbackDecorator(callback,
+                        mCaller.obtainMessageOOO(MSG_INLINE_SUGGESTIONS_REQUEST, mCurMethod,
+                                requestInfo, new InlineSuggestionsRequestCallbackDecorator(callback,
                                         imi.getPackageName())));
             } else {
                 callback.onInlineSuggestionsUnsupported();
@@ -3074,6 +3134,22 @@
             return InputBindResult.NOT_IME_TARGET_WINDOW;
         }
 
+        if (mUserSwitchHandlerTask != null) {
+            // There is already an on-going pending user switch task.
+            final int nextUserId = mUserSwitchHandlerTask.mToUserId;
+            if (userId == nextUserId) {
+                scheduleSwitchUserTaskLocked(userId, cs.client);
+                return InputBindResult.USER_SWITCHING;
+            }
+            for (int profileId : mUserManager.getProfileIdsWithDisabled(nextUserId)) {
+                if (profileId == userId) {
+                    scheduleSwitchUserTaskLocked(userId, cs.client);
+                    return InputBindResult.USER_SWITCHING;
+                }
+            }
+            return InputBindResult.INVALID_USER;
+        }
+
         // cross-profile access is always allowed here to allow profile-switching.
         if (!mSettings.isCurrentProfile(userId)) {
             Slog.w(TAG, "A background user is requesting window. Hiding IME.");
@@ -3085,8 +3161,10 @@
         }
 
         if (userId != mSettings.getCurrentUserId()) {
-            switchUserLocked(userId);
+            scheduleSwitchUserTaskLocked(userId, cs.client);
+            return InputBindResult.USER_SWITCHING;
         }
+
         // Master feature flag that overrides other conditions and forces IME preRendering.
         if (DEBUG) {
             Slog.v(TAG, "IME PreRendering MASTER flag: "
@@ -3972,13 +4050,13 @@
             // ---------------------------------------------------------------
             case MSG_INLINE_SUGGESTIONS_REQUEST:
                 args = (SomeArgs) msg.obj;
-                final ComponentName componentName = (ComponentName) args.arg2;
-                final AutofillId autofillId = (AutofillId) args.arg3;
+                final InlineSuggestionsRequestInfo requestInfo =
+                        (InlineSuggestionsRequestInfo) args.arg2;
                 final IInlineSuggestionsRequestCallback callback =
-                        (IInlineSuggestionsRequestCallback) args.arg4;
+                        (IInlineSuggestionsRequestCallback) args.arg3;
                 try {
-                    ((IInputMethod) args.arg1).onCreateInlineSuggestionsRequest(componentName,
-                            autofillId, callback);
+                    ((IInputMethod) args.arg1).onCreateInlineSuggestionsRequest(requestInfo,
+                            callback);
                 } catch (RemoteException e) {
                     Slog.w(TAG, "RemoteException calling onCreateInlineSuggestionsRequest(): " + e);
                 }
@@ -4549,10 +4627,10 @@
     }
 
     private void onCreateInlineSuggestionsRequest(@UserIdInt int userId,
-            ComponentName componentName, AutofillId autofillId,
+            InlineSuggestionsRequestInfo requestInfo,
             IInlineSuggestionsRequestCallback callback) {
         synchronized (mMethodMap) {
-            onCreateInlineSuggestionsRequestLocked(userId, componentName, autofillId, callback);
+            onCreateInlineSuggestionsRequestLocked(userId, requestInfo, callback);
         }
     }
 
@@ -4620,9 +4698,9 @@
         }
 
         @Override
-        public void onCreateInlineSuggestionsRequest(int userId, ComponentName componentName,
-                AutofillId autofillId, IInlineSuggestionsRequestCallback cb) {
-            mService.onCreateInlineSuggestionsRequest(userId, componentName, autofillId, cb);
+        public void onCreateInlineSuggestionsRequest(int userId,
+                InlineSuggestionsRequestInfo requestInfo, IInlineSuggestionsRequestCallback cb) {
+            mService.onCreateInlineSuggestionsRequest(userId, requestInfo, cb);
         }
 
         @Override
diff --git a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
index 54af694..4904061 100644
--- a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
@@ -63,7 +63,6 @@
 import android.util.SparseArray;
 import android.view.InputChannel;
 import android.view.WindowManager.LayoutParams.SoftInputModeFlags;
-import android.view.autofill.AutofillId;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputConnectionInspector.MissingMethodFlags;
 import android.view.inputmethod.InputMethodInfo;
@@ -88,6 +87,7 @@
 import com.android.internal.view.IInputMethodClient;
 import com.android.internal.view.IInputMethodManager;
 import com.android.internal.view.IInputMethodSession;
+import com.android.internal.view.InlineSuggestionsRequestInfo;
 import com.android.internal.view.InputBindResult;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
@@ -192,7 +192,7 @@
 
                         @Override
                         public void onCreateInlineSuggestionsRequest(int userId,
-                                ComponentName componentName, AutofillId autofillId,
+                                InlineSuggestionsRequestInfo requestInfo,
                                 IInlineSuggestionsRequestCallback cb) {
                             try {
                                 //TODO(b/137800469): support multi client IMEs.
diff --git a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
index b9a30bb..63054cf 100644
--- a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
+++ b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
@@ -45,9 +45,7 @@
 import android.content.pm.ParceledListSlice;
 import android.content.pm.Signature;
 import android.content.pm.SigningInfo;
-import android.content.pm.parsing.ApkParseUtils;
-import android.content.pm.parsing.PackageInfoUtils;
-import android.content.pm.parsing.ParsedPackage;
+import android.content.pm.parsing.ParsingPackageUtils;
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Bundle;
@@ -64,6 +62,9 @@
 import com.android.server.integrity.engine.RuleEvaluationEngine;
 import com.android.server.integrity.model.IntegrityCheckResult;
 import com.android.server.integrity.model.RuleMetadata;
+import com.android.server.pm.parsing.PackageInfoUtils;
+import com.android.server.pm.parsing.PackageParser2;
+import com.android.server.pm.parsing.pkg.ParsedPackage;
 
 import java.io.ByteArrayInputStream;
 import java.io.File;
@@ -508,13 +509,13 @@
             throw new IllegalArgumentException("Installation path is null, package not found");
         }
 
-        PackageParser parser = new PackageParser();
+        PackageParser2 parser = new PackageParser2(null, false, null, null, null);
         try {
-            ParsedPackage pkg = parser.parseParsedPackage(installationPath, 0, false);
+            ParsedPackage pkg = parser.parsePackage(installationPath, 0, false);
             int flags = PackageManager.GET_SIGNING_CERTIFICATES | PackageManager.GET_META_DATA;
-            ApkParseUtils.collectCertificates(pkg, false);
+            pkg.setSigningDetails(ParsingPackageUtils.collectCertificates(pkg, false));
             return PackageInfoUtils.generate(pkg, null, flags, 0, 0, null, new PackageUserState(),
-                    UserHandle.getCallingUserId());
+                    UserHandle.getCallingUserId(), null);
         } catch (Exception e) {
             throw new IllegalArgumentException("Exception reading " + dataUri, e);
         }
diff --git a/services/core/java/com/android/server/integrity/engine/RuleLoader.java b/services/core/java/com/android/server/integrity/engine/RuleLoader.java
deleted file mode 100644
index 4ba2bfb..0000000
--- a/services/core/java/com/android/server/integrity/engine/RuleLoader.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.integrity.engine;
-
-import android.content.integrity.Rule;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * A helper class for loading rules to the rule evaluation engine.
- *
- * <p>Expose fine-grained APIs for loading rules to be passed to the rule evaluation engine.
- *
- * <p>It supports:
- * <ul>
- *     <li>Loading rules based on some keys, such as PACKAGE_NAME and APP_CERT.</li>
- * </ul>
- *
- * <p>It does NOT support:
- * <ul>
- *     <li>Loading the list of all rules.</li>
- *     <li>Merging rules resulting from different APIs.</li>
- * </ul>
- */
-final class RuleLoader {
-
-    List<Rule> loadRulesByPackageName(String packageName) {
-        // TODO: Add logic based on rule storage.
-        return new ArrayList<>();
-    }
-
-    List<Rule> loadRulesByAppCertificate(String appCertificate) {
-        // TODO: Add logic based on rule storage.
-        return new ArrayList<>();
-    }
-
-    List<Rule> loadRulesByInstallerName(String installerName) {
-        // TODO: Add logic based on rule storage.
-        return new ArrayList<>();
-    }
-
-    List<Rule> loadRulesByInstallerCertificate(String installerCertificate) {
-        // TODO: Add logic based on rule storage.
-        return new ArrayList<>();
-    }
-}
diff --git a/services/core/java/com/android/server/integrity/parser/RuleBinaryParser.java b/services/core/java/com/android/server/integrity/parser/RuleBinaryParser.java
index 11e8d91..a290eb3 100644
--- a/services/core/java/com/android/server/integrity/parser/RuleBinaryParser.java
+++ b/services/core/java/com/android/server/integrity/parser/RuleBinaryParser.java
@@ -68,8 +68,7 @@
     }
 
     private List<Rule> parseRules(
-            RandomAccessInputStream randomAccessInputStream,
-            List<RuleIndexRange> indexRanges)
+            RandomAccessInputStream randomAccessInputStream, List<RuleIndexRange> indexRanges)
             throws IOException {
 
         // Read the rule binary file format version.
@@ -96,8 +95,7 @@
     }
 
     private List<Rule> parseIndexedRules(
-            RandomAccessInputStream randomAccessInputStream,
-            List<RuleIndexRange> indexRanges)
+            RandomAccessInputStream randomAccessInputStream, List<RuleIndexRange> indexRanges)
             throws IOException {
         List<Rule> parsedRules = new ArrayList<>();
 
@@ -172,6 +170,7 @@
             case AtomicFormula.APP_CERTIFICATE:
             case AtomicFormula.INSTALLER_NAME:
             case AtomicFormula.INSTALLER_CERTIFICATE:
+            case AtomicFormula.STAMP_CERTIFICATE_HASH:
                 boolean isHashedValue = bitInputStream.getNext(IS_HASHED_BITS) == 1;
                 int valueSize = bitInputStream.getNext(VALUE_SIZE_BITS);
                 String stringValue = getStringValue(bitInputStream, valueSize, isHashedValue);
@@ -183,6 +182,7 @@
                 long longValue = (upper << 32) | lower;
                 return new AtomicFormula.LongAtomicFormula(key, operator, longValue);
             case AtomicFormula.PRE_INSTALLED:
+            case AtomicFormula.STAMP_TRUSTED:
                 boolean booleanValue = getBooleanValue(bitInputStream);
                 return new AtomicFormula.BooleanAtomicFormula(key, booleanValue);
             default:
diff --git a/services/core/java/com/android/server/location/AbstractLocationProvider.java b/services/core/java/com/android/server/location/AbstractLocationProvider.java
index 433ec43..e9d94a5 100644
--- a/services/core/java/com/android/server/location/AbstractLocationProvider.java
+++ b/services/core/java/com/android/server/location/AbstractLocationProvider.java
@@ -366,21 +366,6 @@
     protected abstract void onExtraCommand(int uid, int pid, String command, Bundle extras);
 
     /**
-     * Requests a provider to enable itself for the given user id.
-     */
-    public final void requestSetAllowed(boolean allowed) {
-        // all calls into the provider must be moved onto the provider thread to prevent deadlock
-        mExecutor.execute(
-                obtainRunnable(AbstractLocationProvider::onRequestSetAllowed, this, allowed)
-                        .recycleOnUse());
-    }
-
-    /**
-     * Always invoked on the provider executor.
-     */
-    protected abstract void onRequestSetAllowed(boolean allowed);
-
-    /**
      * Dumps debug or log information. May be invoked from any thread.
      */
     public abstract void dump(FileDescriptor fd, PrintWriter pw, String[] args);
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index 5f44e04..685fb9e 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -1229,11 +1229,6 @@
         }
     }
 
-    @Override
-    protected void onRequestSetAllowed(boolean allowed) {
-        // do nothing - the gnss provider is always allowed
-    }
-
     private void deleteAidingData(Bundle extras) {
         int flags;
 
diff --git a/services/core/java/com/android/server/location/LocationProviderProxy.java b/services/core/java/com/android/server/location/LocationProviderProxy.java
index 96ffaa6..87208a7 100644
--- a/services/core/java/com/android/server/location/LocationProviderProxy.java
+++ b/services/core/java/com/android/server/location/LocationProviderProxy.java
@@ -205,14 +205,6 @@
     }
 
     @Override
-    public void onRequestSetAllowed(boolean allowed) {
-        mServiceWatcher.runOnBinder(binder -> {
-            ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
-            service.requestSetAllowed(allowed);
-        });
-    }
-
-    @Override
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         mServiceWatcher.dump(fd, pw, args);
     }
diff --git a/services/core/java/com/android/server/location/MockProvider.java b/services/core/java/com/android/server/location/MockProvider.java
index b45b660..5ec06ca 100644
--- a/services/core/java/com/android/server/location/MockProvider.java
+++ b/services/core/java/com/android/server/location/MockProvider.java
@@ -64,11 +64,6 @@
     protected void onExtraCommand(int uid, int pid, String command, Bundle extras) {}
 
     @Override
-    protected void onRequestSetAllowed(boolean allowed) {
-        setAllowed(allowed);
-    }
-
-    @Override
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         pw.println("last mock location=" + mLocation);
     }
diff --git a/services/core/java/com/android/server/location/MockableLocationProvider.java b/services/core/java/com/android/server/location/MockableLocationProvider.java
index f43669e..0f358e9 100644
--- a/services/core/java/com/android/server/location/MockableLocationProvider.java
+++ b/services/core/java/com/android/server/location/MockableLocationProvider.java
@@ -224,15 +224,6 @@
         }
     }
 
-    @Override
-    protected void onRequestSetAllowed(boolean allowed) {
-        synchronized (mOwnerLock) {
-            if (mProvider != null) {
-                mProvider.onRequestSetAllowed(allowed);
-            }
-        }
-    }
-
     /**
      * Dumps the current provider implementation.
      */
diff --git a/services/core/java/com/android/server/location/PassiveProvider.java b/services/core/java/com/android/server/location/PassiveProvider.java
index 54dffff..1ba38cc 100644
--- a/services/core/java/com/android/server/location/PassiveProvider.java
+++ b/services/core/java/com/android/server/location/PassiveProvider.java
@@ -79,10 +79,5 @@
     protected void onExtraCommand(int uid, int pid, String command, Bundle extras) {}
 
     @Override
-    protected void onRequestSetAllowed(boolean allowed) {
-        // do nothing - the passive provider is always allowed
-    }
-
-    @Override
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {}
 }
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 1f4048f..15dfab9 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -17,6 +17,7 @@
 package com.android.server.locksettings;
 
 import static android.Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE;
+import static android.Manifest.permission.MANAGE_BIOMETRIC;
 import static android.Manifest.permission.READ_CONTACTS;
 import static android.content.Context.KEYGUARD_SERVICE;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
@@ -178,6 +179,7 @@
 public class LockSettingsService extends ILockSettings.Stub {
     private static final String TAG = "LockSettingsService";
     private static final String PERMISSION = ACCESS_KEYGUARD_SECURE_STORAGE;
+    private static final String BIOMETRIC_PERMISSION = MANAGE_BIOMETRIC;
     private static final boolean DEBUG = false;
 
     private static final int PROFILE_KEY_IV_SIZE = 12;
@@ -1050,6 +1052,10 @@
         }
     }
 
+    private final void checkBiometricPermission() {
+        mContext.enforceCallingOrSelfPermission(BIOMETRIC_PERMISSION, "LockSettingsBiometric");
+    }
+
     @Override
     public boolean hasSecureLockScreen() {
         return mHasSecureLockScreen;
@@ -2304,6 +2310,18 @@
     }
 
     @Override
+    public void reportSuccessfulBiometricUnlock(boolean isStrongBiometric, int userId) {
+        checkBiometricPermission();
+        mStrongAuth.reportSuccessfulBiometricUnlock(isStrongBiometric, userId);
+    }
+
+    @Override
+    public void scheduleNonStrongBiometricIdleTimeout(int userId) {
+        checkBiometricPermission();
+        mStrongAuth.scheduleNonStrongBiometricIdleTimeout(userId);
+    }
+
+    @Override
     public void userPresent(int userId) {
         checkWritePermission(userId);
         mStrongAuth.reportUnlock(userId);
@@ -3191,6 +3209,12 @@
         mStorage.dump(pw);
         pw.println();
         pw.decreaseIndent();
+
+        pw.println("StrongAuth:");
+        pw.increaseIndent();
+        mStrongAuth.dump(pw);
+        pw.println();
+        pw.decreaseIndent();
     }
 
     /**
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsStrongAuth.java b/services/core/java/com/android/server/locksettings/LockSettingsStrongAuth.java
index 91cf53e..fbee6f4 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsStrongAuth.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsStrongAuth.java
@@ -17,6 +17,7 @@
 package com.android.server.locksettings;
 
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED;
+import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_NON_STRONG_BIOMETRICS_TIMEOUT;
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_TIMEOUT;
 
 import android.app.AlarmManager;
@@ -32,8 +33,10 @@
 import android.os.UserHandle;
 import android.util.ArrayMap;
 import android.util.Slog;
+import android.util.SparseBooleanArray;
 import android.util.SparseIntArray;
 
+import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.widget.LockPatternUtils.StrongAuthTracker;
 
 /**
@@ -42,6 +45,7 @@
 public class LockSettingsStrongAuth {
 
     private static final String TAG = "LockSettings";
+    private static final boolean DEBUG = false;
 
     private static final int MSG_REQUIRE_STRONG_AUTH = 1;
     private static final int MSG_REGISTER_TRACKER = 2;
@@ -49,15 +53,40 @@
     private static final int MSG_REMOVE_USER = 4;
     private static final int MSG_SCHEDULE_STRONG_AUTH_TIMEOUT = 5;
     private static final int MSG_NO_LONGER_REQUIRE_STRONG_AUTH = 6;
+    private static final int MSG_SCHEDULE_NON_STRONG_BIOMETRIC_TIMEOUT = 7;
+    private static final int MSG_STRONG_BIOMETRIC_UNLOCK = 8;
+    private static final int MSG_SCHEDULE_NON_STRONG_BIOMETRIC_IDLE_TIMEOUT = 9;
 
     private static final String STRONG_AUTH_TIMEOUT_ALARM_TAG =
             "LockSettingsStrongAuth.timeoutForUser";
+    private static final String NON_STRONG_BIOMETRIC_TIMEOUT_ALARM_TAG =
+            "LockSettingsPrimaryAuth.nonStrongBiometricTimeoutForUser";
+    private static final String NON_STRONG_BIOMETRIC_IDLE_TIMEOUT_ALARM_TAG =
+            "LockSettingsPrimaryAuth.nonStrongBiometricIdleTimeoutForUser";
+
+    /**
+     * Default and maximum timeout in milliseconds after which unlocking with weak auth times out,
+     * i.e. the user has to use a strong authentication method like password, PIN or pattern.
+     */
+    public static final long DEFAULT_NON_STRONG_BIOMETRIC_TIMEOUT_MS = 24 * 60 * 60 * 1000; // 24h
+    public static final long DEFAULT_NON_STRONG_BIOMETRIC_IDLE_TIMEOUT_MS =
+            4 * 60 * 60 * 1000; // 4h
 
     private final RemoteCallbackList<IStrongAuthTracker> mTrackers = new RemoteCallbackList<>();
     private final SparseIntArray mStrongAuthForUser = new SparseIntArray();
+    private final SparseBooleanArray mIsNonStrongBiometricAllowedForUser = new SparseBooleanArray();
     private final ArrayMap<Integer, StrongAuthTimeoutAlarmListener>
             mStrongAuthTimeoutAlarmListenerForUser = new ArrayMap<>();
+    // Track non-strong biometric timeout
+    private final ArrayMap<Integer, NonStrongBiometricTimeoutAlarmListener>
+            mNonStrongBiometricTimeoutAlarmListener = new ArrayMap<>();
+    // Track non-strong biometric idle timeout
+    private final ArrayMap<Integer, NonStrongBiometricIdleTimeoutAlarmListener>
+            mNonStrongBiometricIdleTimeoutAlarmListener = new ArrayMap<>();
+
     private final int mDefaultStrongAuthFlags;
+    private final boolean mDefaultIsNonStrongBiometricAllowed = true;
+
     private final Context mContext;
 
     private AlarmManager mAlarmManager;
@@ -80,6 +109,17 @@
                 Slog.e(TAG, "Exception while adding StrongAuthTracker.", e);
             }
         }
+
+        for (int i = 0; i < mIsNonStrongBiometricAllowedForUser.size(); i++) {
+            int key = mIsNonStrongBiometricAllowedForUser.keyAt(i);
+            boolean value = mIsNonStrongBiometricAllowedForUser.valueAt(i);
+            try {
+                tracker.onIsNonStrongBiometricAllowedChanged(value, key);
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Exception while adding StrongAuthTracker: "
+                        + "IsNonStrongBiometricAllowedChanged.", e);
+            }
+        }
     }
 
     private void handleRemoveStrongAuthTracker(IStrongAuthTracker tracker) {
@@ -134,6 +174,13 @@
             mStrongAuthForUser.removeAt(index);
             notifyStrongAuthTrackers(mDefaultStrongAuthFlags, userId);
         }
+
+        index = mIsNonStrongBiometricAllowedForUser.indexOfKey(userId);
+        if (index >= 0) {
+            mIsNonStrongBiometricAllowedForUser.removeAt(index);
+            notifyStrongAuthTrackersForIsNonStrongBiometricAllowed(
+                    mDefaultIsNonStrongBiometricAllowed, userId);
+        }
     }
 
     private void handleScheduleStrongAuthTimeout(int userId) {
@@ -151,6 +198,125 @@
         // schedule a new alarm listener for the user
         mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, when, STRONG_AUTH_TIMEOUT_ALARM_TAG,
                 alarm, mHandler);
+
+        // cancel current non-strong biometric alarm listener for the user (if there was one)
+        cancelNonStrongBiometricAlarmListener(userId);
+        // cancel current non-strong biometric idle alarm listener for the user (if there was one)
+        cancelNonStrongBiometricIdleAlarmListener(userId);
+        // re-allow unlock with non-strong biometrics
+        setIsNonStrongBiometricAllowed(true, userId);
+    }
+
+    private void handleScheduleNonStrongBiometricTimeout(int userId) {
+        if (DEBUG) Slog.d(TAG, "handleScheduleNonStrongBiometricTimeout for userId=" + userId);
+        long when = SystemClock.elapsedRealtime() + DEFAULT_NON_STRONG_BIOMETRIC_TIMEOUT_MS;
+        NonStrongBiometricTimeoutAlarmListener alarm = mNonStrongBiometricTimeoutAlarmListener
+                .get(userId);
+        if (alarm != null) {
+            // Unlock with non-strong biometric will not affect the existing non-strong biometric
+            // timeout alarm
+            if (DEBUG) {
+                Slog.d(TAG, "There is an existing alarm for non-strong biometric"
+                        + " fallback timeout, so do not re-schedule");
+            }
+        } else {
+            if (DEBUG) {
+                Slog.d(TAG, "Schedule a new alarm for non-strong biometric fallback timeout");
+            }
+            alarm = new NonStrongBiometricTimeoutAlarmListener(userId);
+            mNonStrongBiometricTimeoutAlarmListener.put(userId, alarm);
+            // schedule a new alarm listener for the user
+            mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, when,
+                    NON_STRONG_BIOMETRIC_TIMEOUT_ALARM_TAG, alarm, mHandler);
+        }
+
+        // cancel current non-strong biometric idle alarm listener for the user (if there was one)
+        cancelNonStrongBiometricIdleAlarmListener(userId);
+    }
+
+    private void handleStrongBiometricUnlock(int userId) {
+        if (DEBUG) Slog.d(TAG, "handleStrongBiometricUnlock for userId=" + userId);
+        // cancel current non-strong biometric alarm listener for the user (if there was one)
+        cancelNonStrongBiometricAlarmListener(userId);
+        // cancel current non-strong biometric idle alarm listener for the user (if there was one)
+        cancelNonStrongBiometricIdleAlarmListener(userId);
+        // re-allow unlock with non-strong biometrics
+        setIsNonStrongBiometricAllowed(true, userId);
+    }
+
+    private void cancelNonStrongBiometricAlarmListener(int userId) {
+        if (DEBUG) Slog.d(TAG, "cancelNonStrongBiometricAlarmListener for userId=" + userId);
+        NonStrongBiometricTimeoutAlarmListener alarm = mNonStrongBiometricTimeoutAlarmListener
+                .get(userId);
+        if (alarm != null) {
+            if (DEBUG) Slog.d(TAG, "Cancel alarm for non-strong biometric fallback timeout");
+            mAlarmManager.cancel(alarm);
+            // need to remove the alarm when cancelled by primary auth or strong biometric
+            mNonStrongBiometricTimeoutAlarmListener.remove(userId);
+        }
+    }
+
+    private void cancelNonStrongBiometricIdleAlarmListener(int userId) {
+        if (DEBUG) Slog.d(TAG, "cancelNonStrongBiometricIdleAlarmListener for userId=" + userId);
+        // cancel idle alarm listener by any unlocks (i.e. primary auth, strong biometric,
+        // non-strong biometric)
+        NonStrongBiometricIdleTimeoutAlarmListener alarm =
+                mNonStrongBiometricIdleTimeoutAlarmListener.get(userId);
+        if (alarm != null) {
+            if (DEBUG) Slog.d(TAG, "Cancel alarm for non-strong biometric idle timeout");
+            mAlarmManager.cancel(alarm);
+        }
+    }
+
+    private void setIsNonStrongBiometricAllowed(boolean allowed, int userId) {
+        if (DEBUG) {
+            Slog.d(TAG, "setIsNonStrongBiometricAllowed for allowed=" + allowed
+                    + ", userId=" + userId);
+        }
+        if (userId == UserHandle.USER_ALL) {
+            for (int i = 0; i < mIsNonStrongBiometricAllowedForUser.size(); i++) {
+                int key = mIsNonStrongBiometricAllowedForUser.keyAt(i);
+                setIsNonStrongBiometricAllowedOneUser(allowed, key);
+            }
+        } else {
+            setIsNonStrongBiometricAllowedOneUser(allowed, userId);
+        }
+    }
+
+    private void setIsNonStrongBiometricAllowedOneUser(boolean allowed, int userId) {
+        if (DEBUG) {
+            Slog.d(TAG, "setIsNonStrongBiometricAllowedOneUser for allowed=" + allowed
+                    + ", userId=" + userId);
+        }
+        boolean oldValue = mIsNonStrongBiometricAllowedForUser.get(userId,
+                mDefaultIsNonStrongBiometricAllowed);
+        if (allowed != oldValue) {
+            if (DEBUG) {
+                Slog.d(TAG, "mIsNonStrongBiometricAllowedForUser value changed:"
+                        + " oldValue=" + oldValue + ", allowed=" + allowed);
+            }
+            mIsNonStrongBiometricAllowedForUser.put(userId, allowed);
+            notifyStrongAuthTrackersForIsNonStrongBiometricAllowed(allowed, userId);
+        }
+    }
+
+    private void handleScheduleNonStrongBiometricIdleTimeout(int userId) {
+        if (DEBUG) Slog.d(TAG, "handleScheduleNonStrongBiometricIdleTimeout for userId=" + userId);
+        long when = SystemClock.elapsedRealtime() + DEFAULT_NON_STRONG_BIOMETRIC_IDLE_TIMEOUT_MS;
+        // cancel current alarm listener for the user (if there was one)
+        NonStrongBiometricIdleTimeoutAlarmListener alarm =
+                mNonStrongBiometricIdleTimeoutAlarmListener.get(userId);
+        if (alarm != null) {
+            if (DEBUG) Slog.d(TAG, "Cancel existing alarm for non-strong biometric idle timeout");
+            mAlarmManager.cancel(alarm);
+        } else {
+            alarm = new NonStrongBiometricIdleTimeoutAlarmListener(userId);
+            mNonStrongBiometricIdleTimeoutAlarmListener.put(userId, alarm);
+        }
+        // schedule a new alarm listener for the user
+        if (DEBUG) Slog.d(TAG, "Schedule a new alarm for non-strong biometric idle timeout");
+        mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, when,
+                NON_STRONG_BIOMETRIC_IDLE_TIMEOUT_ALARM_TAG, alarm, mHandler);
     }
 
     private void notifyStrongAuthTrackers(int strongAuthReason, int userId) {
@@ -170,6 +336,29 @@
         }
     }
 
+    private void notifyStrongAuthTrackersForIsNonStrongBiometricAllowed(boolean allowed,
+            int userId) {
+        if (DEBUG) {
+            Slog.d(TAG, "notifyStrongAuthTrackersForIsNonStrongBiometricAllowed"
+                    + " for allowed=" + allowed + ", userId=" + userId);
+        }
+        int i = mTrackers.beginBroadcast();
+        try {
+            while (i > 0) {
+                i--;
+                try {
+                    mTrackers.getBroadcastItem(i).onIsNonStrongBiometricAllowedChanged(
+                            allowed, userId);
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Exception while notifying StrongAuthTracker: "
+                            + "IsNonStrongBiometricAllowedChanged.", e);
+                }
+            }
+        } finally {
+            mTrackers.finishBroadcast();
+        }
+    }
+
     public void registerStrongAuthTracker(IStrongAuthTracker tracker) {
         mHandler.obtainMessage(MSG_REGISTER_TRACKER, tracker).sendToTarget();
     }
@@ -207,11 +396,45 @@
         requireStrongAuth(STRONG_AUTH_NOT_REQUIRED, userId);
     }
 
+    /**
+     * Report successful unlocking with primary auth
+     */
     public void reportSuccessfulStrongAuthUnlock(int userId) {
         final int argNotUsed = 0;
         mHandler.obtainMessage(MSG_SCHEDULE_STRONG_AUTH_TIMEOUT, userId, argNotUsed).sendToTarget();
     }
 
+    /**
+     * Report successful unlocking with biometric
+     */
+    public void reportSuccessfulBiometricUnlock(boolean isStrongBiometric, int userId) {
+        if (DEBUG) {
+            Slog.d(TAG, "reportSuccessfulBiometricUnlock for isStrongBiometric="
+                    + isStrongBiometric + ", userId=" + userId);
+        }
+        final int argNotUsed = 0;
+        if (isStrongBiometric) { // unlock with strong biometric
+            mHandler.obtainMessage(MSG_STRONG_BIOMETRIC_UNLOCK, userId, argNotUsed)
+                    .sendToTarget();
+        } else { // unlock with non-strong biometric (i.e. weak or convenience)
+            mHandler.obtainMessage(MSG_SCHEDULE_NON_STRONG_BIOMETRIC_TIMEOUT, userId, argNotUsed)
+                    .sendToTarget();
+        }
+    }
+
+    /**
+     * Schedule idle timeout for non-strong biometric (i.e. weak or convenience)
+     */
+    public void scheduleNonStrongBiometricIdleTimeout(int userId) {
+        if (DEBUG) Slog.d(TAG, "scheduleNonStrongBiometricIdleTimeout for userId=" + userId);
+        final int argNotUsed = 0;
+        mHandler.obtainMessage(MSG_SCHEDULE_NON_STRONG_BIOMETRIC_IDLE_TIMEOUT, userId, argNotUsed)
+                .sendToTarget();
+    }
+
+    /**
+     * Alarm of fallback timeout for primary auth
+     */
     private class StrongAuthTimeoutAlarmListener implements OnAlarmListener {
 
         private final int mUserId;
@@ -226,6 +449,41 @@
         }
     }
 
+    /**
+     * Alarm of fallback timeout for non-strong biometric (i.e. weak or convenience)
+     */
+    private class NonStrongBiometricTimeoutAlarmListener implements OnAlarmListener {
+
+        private final int mUserId;
+
+        NonStrongBiometricTimeoutAlarmListener(int userId) {
+            mUserId = userId;
+        }
+
+        @Override
+        public void onAlarm() {
+            requireStrongAuth(STRONG_AUTH_REQUIRED_AFTER_NON_STRONG_BIOMETRICS_TIMEOUT, mUserId);
+        }
+    }
+
+    /**
+     * Alarm of idle timeout for non-strong biometric (i.e. weak or convenience biometric)
+     */
+    private class NonStrongBiometricIdleTimeoutAlarmListener implements OnAlarmListener {
+
+        private final int mUserId;
+
+        NonStrongBiometricIdleTimeoutAlarmListener(int userId) {
+            mUserId = userId;
+        }
+
+        @Override
+        public void onAlarm() {
+            // disallow unlock with non-strong biometrics
+            setIsNonStrongBiometricAllowed(false, mUserId);
+        }
+    }
+
     private final Handler mHandler = new Handler() {
         @Override
         public void handleMessage(Message msg) {
@@ -248,8 +506,38 @@
                 case MSG_NO_LONGER_REQUIRE_STRONG_AUTH:
                     handleNoLongerRequireStrongAuth(msg.arg1, msg.arg2);
                     break;
+                case MSG_SCHEDULE_NON_STRONG_BIOMETRIC_TIMEOUT:
+                    handleScheduleNonStrongBiometricTimeout(msg.arg1);
+                    break;
+                case MSG_STRONG_BIOMETRIC_UNLOCK:
+                    handleStrongBiometricUnlock(msg.arg1);
+                    break;
+                case MSG_SCHEDULE_NON_STRONG_BIOMETRIC_IDLE_TIMEOUT:
+                    handleScheduleNonStrongBiometricIdleTimeout(msg.arg1);
+                    break;
             }
         }
     };
 
+    public void dump(IndentingPrintWriter pw) {
+        pw.println("PrimaryAuthFlags state:");
+        pw.increaseIndent();
+        for (int i = 0; i < mStrongAuthForUser.size(); i++) {
+            final int key = mStrongAuthForUser.keyAt(i);
+            final int value = mStrongAuthForUser.valueAt(i);
+            pw.println("userId=" + key + ", primaryAuthFlags=" + Integer.toHexString(value));
+        }
+        pw.println();
+        pw.decreaseIndent();
+
+        pw.println("NonStrongBiometricAllowed state:");
+        pw.increaseIndent();
+        for (int i = 0; i < mIsNonStrongBiometricAllowedForUser.size(); i++) {
+            final int key = mIsNonStrongBiometricAllowedForUser.keyAt(i);
+            final boolean value = mIsNonStrongBiometricAllowedForUser.valueAt(i);
+            pw.println("userId=" + key + ", allowed=" + value);
+        }
+        pw.println();
+        pw.decreaseIndent();
+    }
 }
diff --git a/services/core/java/com/android/server/media/BluetoothRouteProvider.java b/services/core/java/com/android/server/media/BluetoothRouteProvider.java
index 33e01bd..265b9ad 100644
--- a/services/core/java/com/android/server/media/BluetoothRouteProvider.java
+++ b/services/core/java/com/android/server/media/BluetoothRouteProvider.java
@@ -213,7 +213,8 @@
                 .setConnectionState(MediaRoute2Info.CONNECTION_STATE_DISCONNECTED)
                 .setDescription(mContext.getResources().getText(
                         R.string.bluetooth_a2dp_audio_route_name).toString())
-                .setDeviceType(MediaRoute2Info.DEVICE_TYPE_BLUETOOTH)
+                //TODO: Set type correctly (BLUETOOTH_A2DP or HEARING_AID)
+                .setType(MediaRoute2Info.TYPE_BLUETOOTH_A2DP)
                 .setVolumeHandling(MediaRoute2Info.PLAYBACK_VOLUME_VARIABLE)
                 .build();
         newBtRoute.connectedProfiles = new SparseBooleanArray();
diff --git a/services/core/java/com/android/server/media/MediaRoute2Provider.java b/services/core/java/com/android/server/media/MediaRoute2Provider.java
index 9b1824f..f144405 100644
--- a/services/core/java/com/android/server/media/MediaRoute2Provider.java
+++ b/services/core/java/com/android/server/media/MediaRoute2Provider.java
@@ -53,15 +53,15 @@
 
     public abstract void requestCreateSession(String packageName, String routeId, long requestId,
             @Nullable Bundle sessionHints);
-    public abstract void releaseSession(String sessionId);
+    public abstract void releaseSession(String sessionId, long requestId);
     public abstract void updateDiscoveryPreference(RouteDiscoveryPreference discoveryPreference);
 
-    public abstract void selectRoute(String sessionId, String routeId);
-    public abstract void deselectRoute(String sessionId, String routeId);
-    public abstract void transferToRoute(String sessionId, String routeId);
+    public abstract void selectRoute(String sessionId, String routeId, long requestId);
+    public abstract void deselectRoute(String sessionId, String routeId, long requestId);
+    public abstract void transferToRoute(String sessionId, String routeId, long requestId);
 
-    public abstract void setRouteVolume(String routeId, int volume);
-    public abstract void setSessionVolume(String sessionId, int volume);
+    public abstract void setRouteVolume(String routeId, int volume, long requestId);
+    public abstract void setSessionVolume(String sessionId, int volume, long requestId);
 
     @NonNull
     public String getUniqueId() {
@@ -116,5 +116,6 @@
                 @NonNull RoutingSessionInfo sessionInfo);
         void onSessionReleased(@NonNull MediaRoute2Provider provider,
                 @NonNull RoutingSessionInfo sessionInfo);
+        void onRequestFailed(@NonNull MediaRoute2Provider provider, long requestId, int reason);
     }
 }
diff --git a/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java b/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
index 60934e0..e64776c 100644
--- a/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
+++ b/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
@@ -87,9 +87,9 @@
     }
 
     @Override
-    public void releaseSession(String sessionId) {
+    public void releaseSession(String sessionId, long requestId) {
         if (mConnectionReady) {
-            mActiveConnection.releaseSession(sessionId);
+            mActiveConnection.releaseSession(sessionId, requestId);
             updateBinding();
         }
     }
@@ -103,38 +103,38 @@
     }
 
     @Override
-    public void selectRoute(String sessionId, String routeId) {
+    public void selectRoute(String sessionId, String routeId, long requestId) {
         if (mConnectionReady) {
-            mActiveConnection.selectRoute(sessionId, routeId);
+            mActiveConnection.selectRoute(sessionId, routeId, requestId);
         }
     }
 
     @Override
-    public void deselectRoute(String sessionId, String routeId) {
+    public void deselectRoute(String sessionId, String routeId, long requestId) {
         if (mConnectionReady) {
-            mActiveConnection.deselectRoute(sessionId, routeId);
+            mActiveConnection.deselectRoute(sessionId, routeId, requestId);
         }
     }
 
     @Override
-    public void transferToRoute(String sessionId, String routeId) {
+    public void transferToRoute(String sessionId, String routeId, long requestId) {
         if (mConnectionReady) {
-            mActiveConnection.transferToRoute(sessionId, routeId);
+            mActiveConnection.transferToRoute(sessionId, routeId, requestId);
         }
     }
 
     @Override
-    public void setRouteVolume(String routeId, int volume) {
+    public void setRouteVolume(String routeId, int volume, long requestId) {
         if (mConnectionReady) {
-            mActiveConnection.setRouteVolume(routeId, volume);
+            mActiveConnection.setRouteVolume(routeId, volume, requestId);
             updateBinding();
         }
     }
 
     @Override
-    public void setSessionVolume(String sessionId, int volume) {
+    public void setSessionVolume(String sessionId, int volume, long requestId) {
         if (mConnectionReady) {
-            mActiveConnection.setSessionVolume(sessionId, volume);
+            mActiveConnection.setSessionVolume(sessionId, volume, requestId);
             updateBinding();
         }
     }
@@ -333,8 +333,8 @@
             return;
         }
 
-        if (requestId == MediaRoute2ProviderService.REQUEST_ID_UNKNOWN) {
-            Slog.w(TAG, "onSessionCreationFailed: Ignoring requestId REQUEST_ID_UNKNOWN");
+        if (requestId == MediaRoute2ProviderService.REQUEST_ID_NONE) {
+            Slog.w(TAG, "onSessionCreationFailed: Ignoring requestId REQUEST_ID_NONE");
             return;
         }
 
@@ -406,6 +406,19 @@
         mCallback.onSessionReleased(this, sessionInfo);
     }
 
+    private void onRequestFailed(Connection connection, long requestId, int reason) {
+        if (mActiveConnection != connection) {
+            return;
+        }
+
+        if (requestId == MediaRoute2ProviderService.REQUEST_ID_NONE) {
+            Slog.w(TAG, "onRequestFailed: Ignoring requestId REQUEST_ID_NONE");
+            return;
+        }
+
+        mCallback.onRequestFailed(this, requestId, reason);
+    }
+
     private void disconnect() {
         if (mActiveConnection != null) {
             mConnectionReady = false;
@@ -461,9 +474,9 @@
             }
         }
 
-        public void releaseSession(String sessionId) {
+        public void releaseSession(String sessionId, long requestId) {
             try {
-                mService.releaseSession(sessionId);
+                mService.releaseSession(sessionId, requestId);
             } catch (RemoteException ex) {
                 Slog.e(TAG, "releaseSession: Failed to deliver request.");
             }
@@ -477,41 +490,41 @@
             }
         }
 
-        public void selectRoute(String sessionId, String routeId) {
+        public void selectRoute(String sessionId, String routeId, long requestId) {
             try {
-                mService.selectRoute(sessionId, routeId);
+                mService.selectRoute(sessionId, routeId, requestId);
             } catch (RemoteException ex) {
                 Slog.e(TAG, "selectRoute: Failed to deliver request.", ex);
             }
         }
 
-        public void deselectRoute(String sessionId, String routeId) {
+        public void deselectRoute(String sessionId, String routeId, long requestId) {
             try {
-                mService.deselectRoute(sessionId, routeId);
+                mService.deselectRoute(sessionId, routeId, requestId);
             } catch (RemoteException ex) {
                 Slog.e(TAG, "deselectRoute: Failed to deliver request.", ex);
             }
         }
 
-        public void transferToRoute(String sessionId, String routeId) {
+        public void transferToRoute(String sessionId, String routeId, long requestId) {
             try {
-                mService.transferToRoute(sessionId, routeId);
+                mService.transferToRoute(sessionId, routeId, requestId);
             } catch (RemoteException ex) {
                 Slog.e(TAG, "transferToRoute: Failed to deliver request.", ex);
             }
         }
 
-        public void setRouteVolume(String routeId, int volume) {
+        public void setRouteVolume(String routeId, int volume, long requestId) {
             try {
-                mService.setRouteVolume(routeId, volume);
+                mService.setRouteVolume(routeId, volume, requestId);
             } catch (RemoteException ex) {
                 Slog.e(TAG, "setRouteVolume: Failed to deliver request.", ex);
             }
         }
 
-        public void setSessionVolume(String sessionId, int volume) {
+        public void setSessionVolume(String sessionId, int volume, long requestId) {
             try {
-                mService.setSessionVolume(sessionId, volume);
+                mService.setSessionVolume(sessionId, volume, requestId);
             } catch (RemoteException ex) {
                 Slog.e(TAG, "setSessionVolume: Failed to deliver request.", ex);
             }
@@ -541,6 +554,10 @@
         void postSessionReleased(RoutingSessionInfo sessionInfo) {
             mHandler.post(() -> onSessionReleased(Connection.this, sessionInfo));
         }
+
+        void postSessionReleased(long requestId, int reason) {
+            mHandler.post(() -> onRequestFailed(Connection.this, requestId, reason));
+        }
     }
 
     private static final class ServiceCallbackStub extends
@@ -594,5 +611,13 @@
                 connection.postSessionReleased(sessionInfo);
             }
         }
+
+        @Override
+        public void notifyRequestFailed(long requestId, int reason) {
+            Connection connection = mConnectionRef.get();
+            if (connection != null) {
+                connection.postSessionReleased(requestId, reason);
+            }
+        }
     }
 }
diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
index 3588916..e78a35c 100644
--- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
@@ -16,6 +16,7 @@
 
 package com.android.server.media;
 
+import static android.media.MediaRoute2ProviderService.REQUEST_ID_NONE;
 import static android.media.MediaRouter2Utils.getOriginalId;
 import static android.media.MediaRouter2Utils.getProviderId;
 
@@ -30,7 +31,6 @@
 import android.media.IMediaRouter2Manager;
 import android.media.MediaRoute2Info;
 import android.media.MediaRoute2ProviderInfo;
-import android.media.MediaRoute2ProviderService;
 import android.media.RouteDiscoveryPreference;
 import android.media.RoutingSessionInfo;
 import android.os.Binder;
@@ -70,6 +70,12 @@
     private static final String TAG = "MR2ServiceImpl";
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
+    /**
+     * TODO: Change this with the real request ID from MediaRouter2 when
+     * MediaRouter2 needs to get notified for the failures.
+     */
+    private static final long DUMMY_REQUEST_ID = -1;
+
     private final Context mContext;
     private final Object mLock = new Object();
     final AtomicInteger mNextRouterOrManagerId = new AtomicInteger(1);
@@ -365,14 +371,14 @@
     }
 
     public void setRouteVolumeWithManager(IMediaRouter2Manager manager,
-            MediaRoute2Info route, int volume) {
+            MediaRoute2Info route, int volume, int requestId) {
         Objects.requireNonNull(manager, "manager must not be null");
         Objects.requireNonNull(route, "route must not be null");
 
         final long token = Binder.clearCallingIdentity();
         try {
             synchronized (mLock) {
-                setRouteVolumeWithManagerLocked(manager, route, volume);
+                setRouteVolumeWithManagerLocked(manager, route, volume, requestId);
             }
         } finally {
             Binder.restoreCallingIdentity(token);
@@ -397,7 +403,7 @@
     }
 
     public void selectRouteWithManager(IMediaRouter2Manager manager, String uniqueSessionId,
-            MediaRoute2Info route) {
+            MediaRoute2Info route, int requestId) {
         Objects.requireNonNull(manager, "manager must not be null");
         if (TextUtils.isEmpty(uniqueSessionId)) {
             throw new IllegalArgumentException("uniqueSessionId must not be empty");
@@ -407,7 +413,7 @@
         final long token = Binder.clearCallingIdentity();
         try {
             synchronized (mLock) {
-                selectRouteWithManagerLocked(manager, uniqueSessionId, route);
+                selectRouteWithManagerLocked(manager, uniqueSessionId, route, requestId);
             }
         } finally {
             Binder.restoreCallingIdentity(token);
@@ -415,7 +421,7 @@
     }
 
     public void deselectRouteWithManager(IMediaRouter2Manager manager, String uniqueSessionId,
-            MediaRoute2Info route) {
+            MediaRoute2Info route, int requestId) {
         Objects.requireNonNull(manager, "manager must not be null");
         if (TextUtils.isEmpty(uniqueSessionId)) {
             throw new IllegalArgumentException("uniqueSessionId must not be empty");
@@ -425,7 +431,7 @@
         final long token = Binder.clearCallingIdentity();
         try {
             synchronized (mLock) {
-                deselectRouteWithManagerLocked(manager, uniqueSessionId, route);
+                deselectRouteWithManagerLocked(manager, uniqueSessionId, route, requestId);
             }
         } finally {
             Binder.restoreCallingIdentity(token);
@@ -433,7 +439,7 @@
     }
 
     public void transferToRouteWithManager(IMediaRouter2Manager manager, String uniqueSessionId,
-            MediaRoute2Info route) {
+            MediaRoute2Info route, int requestId) {
         Objects.requireNonNull(manager, "manager must not be null");
         if (TextUtils.isEmpty(uniqueSessionId)) {
             throw new IllegalArgumentException("uniqueSessionId must not be empty");
@@ -443,7 +449,7 @@
         final long token = Binder.clearCallingIdentity();
         try {
             synchronized (mLock) {
-                transferToRouteWithManagerLocked(manager, uniqueSessionId, route);
+                transferToRouteWithManagerLocked(manager, uniqueSessionId, route, requestId);
             }
         } finally {
             Binder.restoreCallingIdentity(token);
@@ -451,7 +457,7 @@
     }
 
     public void setSessionVolumeWithManager(IMediaRouter2Manager manager,
-            String uniqueSessionId, int volume) {
+            String uniqueSessionId, int volume, int requestId) {
         Objects.requireNonNull(manager, "manager must not be null");
         if (TextUtils.isEmpty(uniqueSessionId)) {
             throw new IllegalArgumentException("uniqueSessionId must not be empty");
@@ -460,14 +466,15 @@
         final long token = Binder.clearCallingIdentity();
         try {
             synchronized (mLock) {
-                setSessionVolumeWithManagerLocked(manager, uniqueSessionId, volume);
+                setSessionVolumeWithManagerLocked(manager, uniqueSessionId, volume, requestId);
             }
         } finally {
             Binder.restoreCallingIdentity(token);
         }
     }
 
-    public void releaseSessionWithManager(IMediaRouter2Manager manager, String uniqueSessionId) {
+    public void releaseSessionWithManager(IMediaRouter2Manager manager, String uniqueSessionId,
+            int requestId) {
         Objects.requireNonNull(manager, "manager must not be null");
         if (TextUtils.isEmpty(uniqueSessionId)) {
             throw new IllegalArgumentException("uniqueSessionId must not be empty");
@@ -476,7 +483,7 @@
         final long token = Binder.clearCallingIdentity();
         try {
             synchronized (mLock) {
-                releaseSessionWithManagerLocked(manager, uniqueSessionId);
+                releaseSessionWithManagerLocked(manager, uniqueSessionId, requestId);
             }
         } finally {
             Binder.restoreCallingIdentity(token);
@@ -572,7 +579,7 @@
                 obtainMessage(UserHandler::notifyPreferredFeaturesChangedToManagers,
                         routerRecord.mUserRecord.mHandler, routerRecord));
         routerRecord.mUserRecord.mHandler.sendMessage(
-                obtainMessage(UserHandler::updateDiscoveryPreference,
+                obtainMessage(UserHandler::updateDiscoveryPreferenceOnHandler,
                         routerRecord.mUserRecord.mHandler));
     }
 
@@ -584,7 +591,7 @@
         if (routerRecord != null) {
             routerRecord.mUserRecord.mHandler.sendMessage(
                     obtainMessage(UserHandler::setRouteVolumeOnHandler,
-                            routerRecord.mUserRecord.mHandler, route, volume));
+                            routerRecord.mUserRecord.mHandler, route, volume, DUMMY_REQUEST_ID));
         }
     }
 
@@ -615,7 +622,8 @@
 
         routerRecord.mUserRecord.mHandler.sendMessage(
                 obtainMessage(UserHandler::selectRouteOnHandler,
-                        routerRecord.mUserRecord.mHandler, routerRecord, uniqueSessionId, route));
+                        routerRecord.mUserRecord.mHandler, routerRecord, uniqueSessionId, route,
+                        DUMMY_REQUEST_ID));
     }
 
     private void deselectRouteWithRouter2Locked(@NonNull IMediaRouter2 router,
@@ -629,7 +637,8 @@
 
         routerRecord.mUserRecord.mHandler.sendMessage(
                 obtainMessage(UserHandler::deselectRouteOnHandler,
-                        routerRecord.mUserRecord.mHandler, routerRecord, uniqueSessionId, route));
+                        routerRecord.mUserRecord.mHandler, routerRecord, uniqueSessionId, route,
+                        DUMMY_REQUEST_ID));
     }
 
     private void transferToRouteWithRouter2Locked(@NonNull IMediaRouter2 router,
@@ -643,7 +652,8 @@
 
         routerRecord.mUserRecord.mHandler.sendMessage(
                 obtainMessage(UserHandler::transferToRouteOnHandler,
-                        routerRecord.mUserRecord.mHandler, routerRecord, uniqueSessionId, route));
+                        routerRecord.mUserRecord.mHandler, routerRecord, uniqueSessionId, route,
+                        DUMMY_REQUEST_ID));
     }
 
     private void setSessionVolumeWithRouter2Locked(@NonNull IMediaRouter2 router,
@@ -657,7 +667,8 @@
 
         routerRecord.mUserRecord.mHandler.sendMessage(
                 obtainMessage(UserHandler::setSessionVolumeOnHandler,
-                        routerRecord.mUserRecord.mHandler, uniqueSessionId, volume));
+                        routerRecord.mUserRecord.mHandler, uniqueSessionId, volume,
+                        DUMMY_REQUEST_ID));
     }
 
     private void releaseSessionWithRouter2Locked(@NonNull IMediaRouter2 router,
@@ -671,7 +682,8 @@
 
         routerRecord.mUserRecord.mHandler.sendMessage(
                 obtainMessage(UserHandler::releaseSessionOnHandler,
-                        routerRecord.mUserRecord.mHandler, routerRecord, uniqueSessionId));
+                        routerRecord.mUserRecord.mHandler, routerRecord, uniqueSessionId,
+                        DUMMY_REQUEST_ID));
     }
 
     ////////////////////////////////////////////////////////////
@@ -744,16 +756,18 @@
     }
 
     private void setRouteVolumeWithManagerLocked(@NonNull IMediaRouter2Manager manager,
-            @NonNull MediaRoute2Info route, int volume) {
+            @NonNull MediaRoute2Info route, int volume, int requestId) {
         final IBinder binder = manager.asBinder();
         ManagerRecord managerRecord = mAllManagerRecords.get(binder);
 
         if (managerRecord == null) {
             return;
         }
+
+        long uniqueRequestId = toUniqueRequestId(managerRecord.mManagerId, requestId);
         managerRecord.mUserRecord.mHandler.sendMessage(
                 obtainMessage(UserHandler::setRouteVolumeOnHandler,
-                        managerRecord.mUserRecord.mHandler, route, volume));
+                        managerRecord.mUserRecord.mHandler, route, volume, uniqueRequestId));
     }
 
     private void requestCreateSessionWithManagerLocked(@NonNull IMediaRouter2Manager manager,
@@ -778,7 +792,7 @@
     }
 
     private void selectRouteWithManagerLocked(@NonNull IMediaRouter2Manager manager,
-            @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) {
+            @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route, int requestId) {
         final IBinder binder = manager.asBinder();
         ManagerRecord managerRecord = mAllManagerRecords.get(binder);
 
@@ -790,13 +804,15 @@
         RouterRecord routerRecord = managerRecord.mUserRecord.mHandler
                 .findRouterforSessionLocked(uniqueSessionId);
 
+        long uniqueRequestId = toUniqueRequestId(managerRecord.mManagerId, requestId);
         managerRecord.mUserRecord.mHandler.sendMessage(
                 obtainMessage(UserHandler::selectRouteOnHandler,
-                        managerRecord.mUserRecord.mHandler, routerRecord, uniqueSessionId, route));
+                        managerRecord.mUserRecord.mHandler, routerRecord, uniqueSessionId, route,
+                        uniqueRequestId));
     }
 
     private void deselectRouteWithManagerLocked(@NonNull IMediaRouter2Manager manager,
-            @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) {
+            @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route, int requestId) {
         final IBinder binder = manager.asBinder();
         ManagerRecord managerRecord = mAllManagerRecords.get(binder);
 
@@ -808,13 +824,15 @@
         RouterRecord routerRecord = managerRecord.mUserRecord.mHandler
                 .findRouterforSessionLocked(uniqueSessionId);
 
+        long uniqueRequestId = toUniqueRequestId(managerRecord.mManagerId, requestId);
         managerRecord.mUserRecord.mHandler.sendMessage(
                 obtainMessage(UserHandler::deselectRouteOnHandler,
-                        managerRecord.mUserRecord.mHandler, routerRecord, uniqueSessionId, route));
+                        managerRecord.mUserRecord.mHandler, routerRecord, uniqueSessionId, route,
+                        uniqueRequestId));
     }
 
     private void transferToRouteWithManagerLocked(@NonNull IMediaRouter2Manager manager,
-            @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) {
+            @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route, int requestId) {
         final IBinder binder = manager.asBinder();
         ManagerRecord managerRecord = mAllManagerRecords.get(binder);
 
@@ -826,13 +844,15 @@
         RouterRecord routerRecord = managerRecord.mUserRecord.mHandler
                 .findRouterforSessionLocked(uniqueSessionId);
 
+        long uniqueRequestId = toUniqueRequestId(managerRecord.mManagerId, requestId);
         managerRecord.mUserRecord.mHandler.sendMessage(
                 obtainMessage(UserHandler::transferToRouteOnHandler,
-                        managerRecord.mUserRecord.mHandler, routerRecord, uniqueSessionId, route));
+                        managerRecord.mUserRecord.mHandler, routerRecord, uniqueSessionId, route,
+                        uniqueRequestId));
     }
 
     private void setSessionVolumeWithManagerLocked(@NonNull IMediaRouter2Manager manager,
-            @NonNull String uniqueSessionId, int volume) {
+            @NonNull String uniqueSessionId, int volume, int requestId) {
         final IBinder binder = manager.asBinder();
         ManagerRecord managerRecord = mAllManagerRecords.get(binder);
 
@@ -840,13 +860,15 @@
             return;
         }
 
+        long uniqueRequestId = toUniqueRequestId(managerRecord.mManagerId, requestId);
         managerRecord.mUserRecord.mHandler.sendMessage(
                 obtainMessage(UserHandler::setSessionVolumeOnHandler,
-                        managerRecord.mUserRecord.mHandler, uniqueSessionId, volume));
+                        managerRecord.mUserRecord.mHandler, uniqueSessionId, volume,
+                        uniqueRequestId));
     }
 
     private void releaseSessionWithManagerLocked(@NonNull IMediaRouter2Manager manager,
-            @NonNull String uniqueSessionId) {
+            @NonNull String uniqueSessionId, int requestId) {
         final IBinder binder = manager.asBinder();
         ManagerRecord managerRecord = mAllManagerRecords.get(binder);
 
@@ -856,10 +878,15 @@
 
         RouterRecord routerRecord = managerRecord.mUserRecord.mHandler
                 .findRouterforSessionLocked(uniqueSessionId);
+        if (routerRecord == null) {
+            return;
+        }
 
+        long uniqueRequestId = toUniqueRequestId(managerRecord.mManagerId, requestId);
         managerRecord.mUserRecord.mHandler.sendMessage(
                 obtainMessage(UserHandler::releaseSessionOnHandler,
-                        managerRecord.mUserRecord.mHandler, routerRecord, uniqueSessionId));
+                        managerRecord.mUserRecord.mHandler, routerRecord, uniqueSessionId,
+                        uniqueRequestId));
     }
 
     ////////////////////////////////////////////////////////////
@@ -1100,6 +1127,13 @@
                     this, provider, sessionInfo));
         }
 
+        @Override
+        public void onRequestFailed(@NonNull MediaRoute2Provider provider, long requestId,
+                int reason) {
+            sendMessage(PooledLambda.obtainMessage(UserHandler::onRequestFailedOnHandler,
+                    this, provider, requestId, reason));
+        }
+
         @Nullable
         public RouterRecord findRouterforSessionLocked(@NonNull String uniqueSessionId) {
             return mSessionToRouterMap.get(uniqueSessionId);
@@ -1195,7 +1229,7 @@
             if (provider == null) {
                 Slog.w(TAG, "Ignoring session creation request since no provider found for"
                         + " given route=" + route);
-                notifySessionCreationFailed(routerRecord, toOriginalRequestId(requestId));
+                notifySessionCreationFailedToRouter(routerRecord, toOriginalRequestId(requestId));
                 return;
             }
 
@@ -1210,7 +1244,7 @@
 
         // routerRecord can be null if the session is system's.
         private void selectRouteOnHandler(@Nullable RouterRecord routerRecord,
-                @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) {
+                @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route, long requestId) {
             if (!checkArgumentsForSessionControl(routerRecord, uniqueSessionId, route,
                     "selecting")) {
                 return;
@@ -1222,12 +1256,12 @@
             if (provider == null) {
                 return;
             }
-            provider.selectRoute(getOriginalId(uniqueSessionId), route.getOriginalId());
+            provider.selectRoute(getOriginalId(uniqueSessionId), route.getOriginalId(), requestId);
         }
 
         // routerRecord can be null if the session is system's.
         private void deselectRouteOnHandler(@Nullable RouterRecord routerRecord,
-                @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) {
+                @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route, long requestId) {
             if (!checkArgumentsForSessionControl(routerRecord, uniqueSessionId, route,
                     "deselecting")) {
                 return;
@@ -1239,12 +1273,13 @@
             if (provider == null) {
                 return;
             }
-            provider.deselectRoute(getOriginalId(uniqueSessionId), route.getOriginalId());
+            provider.deselectRoute(getOriginalId(uniqueSessionId), route.getOriginalId(),
+                    requestId);
         }
 
         // routerRecord can be null if the session is system's.
         private void transferToRouteOnHandler(@Nullable RouterRecord routerRecord,
-                @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) {
+                @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route, long requestId) {
             if (!checkArgumentsForSessionControl(routerRecord, uniqueSessionId, route,
                     "transferring to")) {
                 return;
@@ -1256,7 +1291,8 @@
             if (provider == null) {
                 return;
             }
-            provider.transferToRoute(getOriginalId(uniqueSessionId), route.getOriginalId());
+            provider.transferToRoute(getOriginalId(uniqueSessionId), route.getOriginalId(),
+                    requestId);
         }
 
         private boolean checkArgumentsForSessionControl(@Nullable RouterRecord routerRecord,
@@ -1299,7 +1335,7 @@
         }
 
         private void releaseSessionOnHandler(@NonNull RouterRecord routerRecord,
-                @NonNull String uniqueSessionId) {
+                @NonNull String uniqueSessionId, long uniqueRequestId) {
             final RouterRecord matchingRecord = mSessionToRouterMap.get(uniqueSessionId);
             if (matchingRecord != routerRecord) {
                 Slog.w(TAG, "Ignoring releasing session from non-matching router."
@@ -1329,14 +1365,14 @@
                 return;
             }
 
-            provider.releaseSession(sessionId);
+            provider.releaseSession(sessionId, uniqueRequestId);
         }
 
         private void onSessionCreatedOnHandler(@NonNull MediaRoute2Provider provider,
                 @NonNull RoutingSessionInfo sessionInfo, long requestId) {
             notifySessionCreatedToManagers(getManagers(), sessionInfo);
 
-            if (requestId == MediaRoute2ProviderService.REQUEST_ID_UNKNOWN) {
+            if (requestId == REQUEST_ID_NONE) {
                 // The session is created without any matching request.
                 return;
             }
@@ -1362,7 +1398,7 @@
 
             if (sessionInfo == null) {
                 // Failed
-                notifySessionCreationFailed(matchingRequest.mRouterRecord,
+                notifySessionCreationFailedToRouter(matchingRequest.mRouterRecord,
                         toOriginalRequestId(requestId));
                 return;
             }
@@ -1374,13 +1410,13 @@
                 Slog.w(TAG, "Created session doesn't match the original request."
                         + " originalRouteId=" + originalRouteId
                         + ", requestId=" + requestId + ", sessionInfo=" + sessionInfo);
-                notifySessionCreationFailed(matchingRequest.mRouterRecord,
+                notifySessionCreationFailedToRouter(matchingRequest.mRouterRecord,
                         toOriginalRequestId(requestId));
                 return;
             }
 
             // Succeeded
-            notifySessionCreated(matchingRequest.mRouterRecord,
+            notifySessionCreatedToRouter(matchingRequest.mRouterRecord,
                     sessionInfo, toOriginalRequestId(requestId));
             mSessionToRouterMap.put(sessionInfo.getId(), routerRecord);
         }
@@ -1405,7 +1441,7 @@
             }
 
             mSessionCreationRequests.remove(matchingRequest);
-            notifySessionCreationFailed(matchingRequest.mRouterRecord,
+            notifySessionCreationFailedToRouter(matchingRequest.mRouterRecord,
                     toOriginalRequestId(requestId));
         }
 
@@ -1429,7 +1465,7 @@
                 Slog.w(TAG, "No matching router found for session=" + sessionInfo);
                 return;
             }
-            notifySessionInfoChanged(routerRecord, sessionInfo);
+            notifySessionInfoChangedToRouter(routerRecord, sessionInfo);
         }
 
         private void onSessionReleasedOnHandler(@NonNull MediaRoute2Provider provider,
@@ -1442,10 +1478,38 @@
                 Slog.w(TAG, "No matching router found for session=" + sessionInfo);
                 return;
             }
-            notifySessionReleased(routerRecord, sessionInfo);
+            notifySessionReleasedToRouter(routerRecord, sessionInfo);
         }
 
-        private void notifySessionCreated(@NonNull RouterRecord routerRecord,
+        private void onRequestFailedOnHandler(@NonNull MediaRoute2Provider provider,
+                long requestId, int reason) {
+            final int managerId = toRouterOrManagerId(requestId);
+
+            MediaRouter2ServiceImpl service = mServiceRef.get();
+            if (service == null) {
+                return;
+            }
+
+            ManagerRecord managerToNotifyFailure = null;
+            synchronized (service.mLock) {
+                for (ManagerRecord manager : mUserRecord.mManagerRecords) {
+                    if (manager.mManagerId == managerId) {
+                        managerToNotifyFailure = manager;
+                        break;
+                    }
+                }
+            }
+
+            if (managerToNotifyFailure == null) {
+                Slog.w(TAG, "No matching managerRecord found for managerId=" + managerId);
+                return;
+            }
+
+            notifyRequestFailedToManager(
+                    managerToNotifyFailure.mManager, toOriginalRequestId(requestId), reason);
+        }
+
+        private void notifySessionCreatedToRouter(@NonNull RouterRecord routerRecord,
                 @NonNull RoutingSessionInfo sessionInfo, int requestId) {
             try {
                 routerRecord.mRouter.notifySessionCreated(sessionInfo, requestId);
@@ -1455,7 +1519,7 @@
             }
         }
 
-        private void notifySessionCreationFailed(@NonNull RouterRecord routerRecord,
+        private void notifySessionCreationFailedToRouter(@NonNull RouterRecord routerRecord,
                 int requestId) {
             try {
                 routerRecord.mRouter.notifySessionCreated(/* sessionInfo= */ null, requestId);
@@ -1465,7 +1529,7 @@
             }
         }
 
-        private void notifySessionInfoChanged(@NonNull RouterRecord routerRecord,
+        private void notifySessionInfoChangedToRouter(@NonNull RouterRecord routerRecord,
                 @NonNull RoutingSessionInfo sessionInfo) {
             try {
                 routerRecord.mRouter.notifySessionInfoChanged(sessionInfo);
@@ -1475,7 +1539,7 @@
             }
         }
 
-        private void notifySessionReleased(@NonNull RouterRecord routerRecord,
+        private void notifySessionReleasedToRouter(@NonNull RouterRecord routerRecord,
                 @NonNull RoutingSessionInfo sessionInfo) {
             try {
                 routerRecord.mRouter.notifySessionReleased(sessionInfo);
@@ -1485,21 +1549,23 @@
             }
         }
 
-        private void setRouteVolumeOnHandler(@NonNull MediaRoute2Info route, int volume) {
+        private void setRouteVolumeOnHandler(@NonNull MediaRoute2Info route, int volume,
+                long requestId) {
             final MediaRoute2Provider provider = findProvider(route.getProviderId());
             if (provider != null) {
-                provider.setRouteVolume(route.getOriginalId(), volume);
+                provider.setRouteVolume(route.getOriginalId(), volume, requestId);
             }
         }
 
-        private void setSessionVolumeOnHandler(@NonNull String uniqueSessionId, int volume) {
+        private void setSessionVolumeOnHandler(@NonNull String uniqueSessionId, int volume,
+                long requestId) {
             final MediaRoute2Provider provider = findProvider(getProviderId(uniqueSessionId));
             if (provider == null) {
                 Slog.w(TAG, "setSessionVolume: couldn't find provider for session "
                         + "id=" + uniqueSessionId);
                 return;
             }
-            provider.setSessionVolume(getOriginalId(uniqueSessionId), volume);
+            provider.setSessionVolume(getOriginalId(uniqueSessionId), volume, requestId);
         }
 
         private List<IMediaRouter2> getRouters() {
@@ -1683,7 +1749,17 @@
             }
         }
 
-        private void updateDiscoveryPreference() {
+        private void notifyRequestFailedToManager(@NonNull IMediaRouter2Manager manager,
+                int requestId, int reason) {
+            try {
+                manager.notifyRequestFailed(requestId, reason);
+            } catch (RemoteException ex) {
+                Slog.w(TAG, "Failed to notify manager of the request failure."
+                        + " Manager probably died.", ex);
+            }
+        }
+
+        private void updateDiscoveryPreferenceOnHandler() {
             MediaRouter2ServiceImpl service = mServiceRef.get();
             if (service == null) {
                 return;
diff --git a/services/core/java/com/android/server/media/MediaRouterService.java b/services/core/java/com/android/server/media/MediaRouterService.java
index 580fc52..a13ee10 100644
--- a/services/core/java/com/android/server/media/MediaRouterService.java
+++ b/services/core/java/com/android/server/media/MediaRouterService.java
@@ -543,8 +543,8 @@
     // Binder call
     @Override
     public void setRouteVolumeWithManager(IMediaRouter2Manager manager,
-            MediaRoute2Info route, int volume) {
-        mService2.setRouteVolumeWithManager(manager, route, volume);
+            MediaRoute2Info route, int volume, int requestId) {
+        mService2.setRouteVolumeWithManager(manager, route, volume, requestId);
     }
 
     // Binder call
@@ -557,35 +557,36 @@
     // Binder call
     @Override
     public void selectRouteWithManager(IMediaRouter2Manager manager, String sessionId,
-            MediaRoute2Info route) {
-        mService2.selectRouteWithManager(manager, sessionId, route);
+            MediaRoute2Info route, int requestId) {
+        mService2.selectRouteWithManager(manager, sessionId, route, requestId);
     }
 
     // Binder call
     @Override
     public void deselectRouteWithManager(IMediaRouter2Manager manager, String sessionId,
-            MediaRoute2Info route) {
-        mService2.deselectRouteWithManager(manager, sessionId, route);
+            MediaRoute2Info route, int requestId) {
+        mService2.deselectRouteWithManager(manager, sessionId, route, requestId);
     }
 
     // Binder call
     @Override
     public void transferToRouteWithManager(IMediaRouter2Manager manager, String sessionId,
-            MediaRoute2Info route) {
-        mService2.transferToRouteWithManager(manager, sessionId, route);
+            MediaRoute2Info route, int requestId) {
+        mService2.transferToRouteWithManager(manager, sessionId, route, requestId);
     }
 
     // Binder call
     @Override
     public void setSessionVolumeWithManager(IMediaRouter2Manager manager,
-            String sessionId, int volume) {
-        mService2.setSessionVolumeWithManager(manager, sessionId, volume);
+            String sessionId, int volume, int requestId) {
+        mService2.setSessionVolumeWithManager(manager, sessionId, volume, requestId);
     }
 
     // Binder call
     @Override
-    public void releaseSessionWithManager(IMediaRouter2Manager manager, String sessionId) {
-        mService2.releaseSessionWithManager(manager, sessionId);
+    public void releaseSessionWithManager(IMediaRouter2Manager manager, String sessionId,
+            int requestId) {
+        mService2.releaseSessionWithManager(manager, sessionId, requestId);
     }
 
     void restoreBluetoothA2dp() {
diff --git a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
index f7e1398..da9c27e 100644
--- a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
+++ b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
@@ -18,6 +18,7 @@
 
 import static android.media.MediaRoute2Info.FEATURE_LIVE_AUDIO;
 import static android.media.MediaRoute2Info.FEATURE_LIVE_VIDEO;
+import static android.media.MediaRoute2Info.TYPE_BUILTIN_SPEAKER;
 
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
@@ -130,26 +131,27 @@
     }
 
     @Override
-    public void releaseSession(String sessionId) {
+    public void releaseSession(String sessionId, long requestId) {
         // Do nothing
     }
+
     @Override
     public void updateDiscoveryPreference(RouteDiscoveryPreference discoveryPreference) {
         // Do nothing
     }
 
     @Override
-    public void selectRoute(String sessionId, String routeId) {
+    public void selectRoute(String sessionId, String routeId, long requestId) {
         // Do nothing since we don't support multiple BT yet.
     }
 
     @Override
-    public void deselectRoute(String sessionId, String routeId) {
+    public void deselectRoute(String sessionId, String routeId, long requestId) {
         // Do nothing since we don't support multiple BT yet.
     }
 
     @Override
-    public void transferToRoute(String sessionId, String routeId) {
+    public void transferToRoute(String sessionId, String routeId, long requestId) {
         if (TextUtils.equals(routeId, mDefaultRoute.getId())) {
             mBtRouteProvider.transferTo(null);
         } else {
@@ -158,7 +160,7 @@
     }
 
     @Override
-    public void setRouteVolume(String routeId, int volume) {
+    public void setRouteVolume(String routeId, int volume, long requestId) {
         if (!TextUtils.equals(routeId, mSelectedRouteId)) {
             return;
         }
@@ -166,7 +168,7 @@
     }
 
     @Override
-    public void setSessionVolume(String sessionId, int volume) {
+    public void setSessionVolume(String sessionId, int volume, long requestId) {
         // Do nothing since we don't support grouping volume yet.
     }
 
@@ -192,6 +194,8 @@
                         : MediaRoute2Info.PLAYBACK_VOLUME_VARIABLE)
                 .setVolumeMax(mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC))
                 .setVolume(mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC))
+                //TODO: Guess the exact type using AudioDevice
+                .setType(TYPE_BUILTIN_SPEAKER)
                 .addFeature(FEATURE_LIVE_AUDIO)
                 .addFeature(FEATURE_LIVE_VIDEO)
                 .setConnectionState(MediaRoute2Info.CONNECTION_STATE_CONNECTED)
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index 0662400..ee5a4fe 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -1253,7 +1253,7 @@
         final NetworkStats uidSnapshot = getNetworkStatsUidDetail(INTERFACES_ALL);
         Trace.traceEnd(TRACE_TAG_NETWORK);
         Trace.traceBegin(TRACE_TAG_NETWORK, "snapshotXt");
-        final NetworkStats xtSnapshot = getNetworkStatsXt();
+        final NetworkStats xtSnapshot = readNetworkStatsSummaryXt();
         Trace.traceEnd(TRACE_TAG_NETWORK);
         Trace.traceBegin(TRACE_TAG_NETWORK, "snapshotDev");
         final NetworkStats devSnapshot = readNetworkStatsSummaryDev();
@@ -1742,18 +1742,6 @@
                 mUseBpfTrafficStats);
         uidSnapshot.combineAllValues(tetherSnapshot);
 
-        final TelephonyManager telephonyManager = (TelephonyManager) mContext.getSystemService(
-                Context.TELEPHONY_SERVICE);
-
-        // fold video calling data usage stats into uid snapshot
-        final NetworkStats vtStats = telephonyManager.getVtDataUsage(STATS_PER_UID);
-        if (vtStats != null) {
-            vtStats.filter(UID_ALL, ifaces, TAG_ALL);
-            mStatsFactory.apply464xlatAdjustments(uidSnapshot, vtStats,
-                    mUseBpfTrafficStats);
-            uidSnapshot.combineAllValues(vtStats);
-        }
-
         // get a stale copy of uid stats snapshot provided by providers.
         final NetworkStats providerStats = getNetworkStatsFromProviders(STATS_PER_UID);
         providerStats.filter(UID_ALL, ifaces, TAG_ALL);
@@ -1766,24 +1754,6 @@
     }
 
     /**
-     * Return snapshot of current XT statistics with video calling data usage statistics.
-     */
-    private NetworkStats getNetworkStatsXt() throws RemoteException {
-        final NetworkStats xtSnapshot = readNetworkStatsSummaryXt();
-
-        final TelephonyManager telephonyManager = (TelephonyManager) mContext.getSystemService(
-                Context.TELEPHONY_SERVICE);
-
-        // Merge video calling data usage into XT
-        final NetworkStats vtSnapshot = telephonyManager.getVtDataUsage(STATS_PER_IFACE);
-        if (vtSnapshot != null) {
-            xtSnapshot.combineAllValues(vtSnapshot);
-        }
-
-        return xtSnapshot;
-    }
-
-    /**
      * Return snapshot of current tethering statistics. Will return empty
      * {@link NetworkStats} if any problems are encountered.
      */
diff --git a/services/core/java/com/android/server/notification/NotificationManagerInternal.java b/services/core/java/com/android/server/notification/NotificationManagerInternal.java
index fce10e6..c301cd2 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerInternal.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerInternal.java
@@ -27,4 +27,6 @@
             String tag, int id, int userId);
 
     void removeForegroundServiceFlagFromNotification(String pkg, int notificationId, int userId);
+
+    void onConversationRemoved(String pkg, int uid, String conversationId);
 }
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 0d402e5..475f229 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -772,7 +772,7 @@
                         parser, mAllowedManagedServicePackages, forRestore, userId);
                 migratedManagedServices = true;
             } else if (mSnoozeHelper.XML_TAG_NAME.equals(parser.getName())) {
-                mSnoozeHelper.readXml(parser);
+                mSnoozeHelper.readXml(parser, System.currentTimeMillis());
             }
             if (LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_TAG.equals(parser.getName())) {
                 if (forRestore && userId != UserHandle.USER_SYSTEM) {
@@ -2322,6 +2322,8 @@
             mConditionProviders.onBootPhaseAppsCanStart();
             mHistoryManager.onBootPhaseAppsCanStart();
             registerDeviceConfigChange();
+        } else if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
+            mSnoozeHelper.scheduleRepostsForPersistedNotifications(System.currentTimeMillis());
         }
     }
 
@@ -5474,6 +5476,11 @@
             });
         }
 
+        @Override
+        public void onConversationRemoved(String pkg, int uid, String conversationId) {
+            onConversationRemovedInternal(pkg, uid, conversationId);
+        }
+
         @GuardedBy("mNotificationLock")
         private void removeForegroundServiceFlagLocked(NotificationRecord r) {
             if (r == null) {
@@ -5676,7 +5683,7 @@
         mHandler.post(new EnqueueNotificationRunnable(userId, r, isAppForeground));
     }
 
-    public void onConversationRemoved(String pkg, int uid, String conversationId) {
+    private void onConversationRemovedInternal(String pkg, int uid, String conversationId) {
         checkCallerIsSystem();
         Preconditions.checkStringNotEmpty(pkg);
         Preconditions.checkStringNotEmpty(conversationId);
diff --git a/services/core/java/com/android/server/notification/SnoozeHelper.java b/services/core/java/com/android/server/notification/SnoozeHelper.java
index bae1dd3..d60c291 100644
--- a/services/core/java/com/android/server/notification/SnoozeHelper.java
+++ b/services/core/java/com/android/server/notification/SnoozeHelper.java
@@ -36,6 +36,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto;
+import com.android.internal.util.XmlUtils;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -43,9 +44,7 @@
 
 import java.io.IOException;
 import java.io.PrintWriter;
-import java.sql.Array;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Date;
@@ -172,7 +171,7 @@
             for (int i = 0; i < allRecords.size(); i++) {
                 NotificationRecord r = allRecords.valueAt(i);
                 String currentGroupKey = r.getSbn().getGroup();
-                if (currentGroupKey.equals(groupKey)) {
+                if (Objects.equals(currentGroupKey, groupKey)) {
                     records.add(r);
                 }
             }
@@ -217,7 +216,7 @@
 
         snooze(record);
         scheduleRepost(pkg, key, userId, duration);
-        Long activateAt = System.currentTimeMillis() + duration;
+        Long activateAt = SystemClock.elapsedRealtime() + duration;
         synchronized (mPersistedSnoozedNotifications) {
             storeRecord(pkg, key, userId, mPersistedSnoozedNotifications, activateAt);
         }
@@ -244,8 +243,6 @@
         }
         storeRecord(record.getSbn().getPackageName(), record.getKey(),
                 userId, mSnoozedNotifications, record);
-        mPackages.put(record.getKey(), record.getSbn().getPackageName());
-        mUsers.put(record.getKey(), userId);
     }
 
     private <T> void storeRecord(String pkg, String key, Integer userId,
@@ -258,6 +255,8 @@
         keyToValue.put(key, object);
         targets.put(getPkgKey(userId, pkg), keyToValue);
 
+        mPackages.put(key, pkg);
+        mUsers.put(key, userId);
     }
 
     private <T> T removeRecord(String pkg, String key, Integer userId,
@@ -425,12 +424,34 @@
                 PendingIntent.FLAG_UPDATE_CURRENT);
     }
 
+    public void scheduleRepostsForPersistedNotifications(long currentTime) {
+        for (ArrayMap<String, Long> snoozed : mPersistedSnoozedNotifications.values()) {
+            for (int i = 0; i < snoozed.size(); i++) {
+                String key = snoozed.keyAt(i);
+                Long time = snoozed.valueAt(i);
+                String pkg = mPackages.get(key);
+                Integer userId = mUsers.get(key);
+                if (time == null || pkg == null || userId == null) {
+                    Slog.w(TAG, "data out of sync: " + time + "|" + pkg + "|" + userId);
+                    continue;
+                }
+                if (time != null && time > currentTime) {
+                    scheduleRepostAtTime(pkg, key, userId, time);
+                }
+            }
+
+        }
+    }
+
     private void scheduleRepost(String pkg, String key, int userId, long duration) {
+        scheduleRepostAtTime(pkg, key, userId, SystemClock.elapsedRealtime() + duration);
+    }
+
+    private void scheduleRepostAtTime(String pkg, String key, int userId, long time) {
         long identity = Binder.clearCallingIdentity();
         try {
             final PendingIntent pi = createPendingIntent(pkg, key, userId);
             mAm.cancel(pi);
-            long time = SystemClock.elapsedRealtime() + duration;
             if (DEBUG) Slog.d(TAG, "Scheduling evaluate for " + new Date(time));
             mAm.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP, time, pi);
         } finally {
@@ -496,6 +517,7 @@
     private interface Inserter<T> {
         void insert(T t) throws IOException;
     }
+
     private <T> void writeXml(XmlSerializer out,
             ArrayMap<String, ArrayMap<String, T>> targets, String tag,
             Inserter<T> attributeInserter)
@@ -503,12 +525,13 @@
         synchronized (targets) {
             final int M = targets.size();
             for (int i = 0; i < M; i++) {
-                String userIdPkgKey = targets.keyAt(i);
                 // T is a String (snoozed until context) or Long (snoozed until time)
                 ArrayMap<String, T> keyToValue = targets.valueAt(i);
                 for (int j = 0; j < keyToValue.size(); j++) {
                     String key = keyToValue.keyAt(j);
                     T value = keyToValue.valueAt(j);
+                    String pkg = mPackages.get(key);
+                    Integer userId = mUsers.get(key);
 
                     out.startTag(null, tag);
 
@@ -518,8 +541,7 @@
                             XML_SNOOZED_NOTIFICATION_VERSION);
                     out.attribute(null, XML_SNOOZED_NOTIFICATION_KEY, key);
 
-                    String pkg = mPackages.get(key);
-                    int userId = mUsers.get(key);
+
                     out.attribute(null, XML_SNOOZED_NOTIFICATION_PKG, pkg);
                     out.attribute(null, XML_SNOOZED_NOTIFICATION_USER_ID,
                             String.valueOf(userId));
@@ -530,7 +552,7 @@
         }
     }
 
-    protected void readXml(XmlPullParser parser)
+    protected void readXml(XmlPullParser parser, long currentTime)
             throws XmlPullParserException, IOException {
         int type;
         while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
@@ -547,16 +569,15 @@
                 try {
                     final String key = parser.getAttributeValue(null, XML_SNOOZED_NOTIFICATION_KEY);
                     final String pkg = parser.getAttributeValue(null, XML_SNOOZED_NOTIFICATION_PKG);
-                    final int userId = Integer.parseInt(
-                            parser.getAttributeValue(null, XML_SNOOZED_NOTIFICATION_USER_ID));
+                    final int userId = XmlUtils.readIntAttribute(
+                            parser, XML_SNOOZED_NOTIFICATION_USER_ID, UserHandle.USER_ALL);
                     if (tag.equals(XML_SNOOZED_NOTIFICATION)) {
-                        final Long time = Long.parseLong(
-                                parser.getAttributeValue(null, XML_SNOOZED_NOTIFICATION_TIME));
-                        if (time > System.currentTimeMillis()) { //only read new stuff
+                        final Long time = XmlUtils.readLongAttribute(
+                                parser, XML_SNOOZED_NOTIFICATION_TIME, 0);
+                        if (time > currentTime) { //only read new stuff
                             synchronized (mPersistedSnoozedNotifications) {
                                 storeRecord(pkg, key, userId, mPersistedSnoozedNotifications, time);
                             }
-                            scheduleRepost(pkg, key, userId, time - System.currentTimeMillis());
                         }
                     }
                     if (tag.equals(XML_SNOOZED_NOTIFICATION_CONTEXT)) {
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 3b564c3..f45e66e 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -19,6 +19,7 @@
 import static android.app.NotificationManager.AUTOMATIC_RULE_STATUS_DISABLED;
 import static android.app.NotificationManager.AUTOMATIC_RULE_STATUS_ENABLED;
 import static android.app.NotificationManager.AUTOMATIC_RULE_STATUS_REMOVED;
+import static android.app.NotificationManager.Policy.PRIORITY_SENDERS_ANY;
 
 import android.app.AppOpsManager;
 import android.app.AutomaticZenRule;
@@ -1011,21 +1012,23 @@
 
     @VisibleForTesting
     protected void applyRestrictions() {
+        final boolean zenOn = mZenMode != Global.ZEN_MODE_OFF;
         final boolean zenPriorityOnly = mZenMode == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
         final boolean zenSilence = mZenMode == Global.ZEN_MODE_NO_INTERRUPTIONS;
         final boolean zenAlarmsOnly = mZenMode == Global.ZEN_MODE_ALARMS;
-        final boolean allowCalls = mConsolidatedPolicy.allowCalls();
+        final boolean allowCalls = mConsolidatedPolicy.allowCalls()
+                && mConsolidatedPolicy.allowCallsFrom() == PRIORITY_SENDERS_ANY;
         final boolean allowRepeatCallers = mConsolidatedPolicy.allowRepeatCallers();
         final boolean allowSystem = mConsolidatedPolicy.allowSystem();
         final boolean allowMedia = mConsolidatedPolicy.allowMedia();
         final boolean allowAlarms = mConsolidatedPolicy.allowAlarms();
 
         // notification restrictions
-        final boolean muteNotifications =
-                (mSuppressedEffects & SUPPRESSED_EFFECT_NOTIFICATIONS) != 0;
+        final boolean muteNotifications = zenOn
+                || (mSuppressedEffects & SUPPRESSED_EFFECT_NOTIFICATIONS) != 0;
         // call restrictions
         final boolean muteCalls = zenAlarmsOnly
-                || (zenPriorityOnly && !allowCalls && !allowRepeatCallers)
+                || (zenPriorityOnly && !(allowCalls || allowRepeatCallers))
                 || (mSuppressedEffects & SUPPRESSED_EFFECT_CALLS) != 0;
         // alarm restrictions
         final boolean muteAlarms = zenPriorityOnly && !allowAlarms;
diff --git a/services/core/java/com/android/server/om/OverlayReferenceMapper.java b/services/core/java/com/android/server/om/OverlayReferenceMapper.java
index 8bea119..cadb8e4 100644
--- a/services/core/java/com/android/server/om/OverlayReferenceMapper.java
+++ b/services/core/java/com/android/server/om/OverlayReferenceMapper.java
@@ -18,16 +18,14 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.content.pm.parsing.AndroidPackage;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
 import android.text.TextUtils;
-import android.util.ArraySet;
 import android.util.Pair;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.CollectionUtils;
 import com.android.server.SystemConfig;
-import com.android.server.pm.PackageSetting;
 
 import java.util.Collections;
 import java.util.HashMap;
diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java
index a440c62..d12e03d 100644
--- a/services/core/java/com/android/server/pm/ApexManager.java
+++ b/services/core/java/com/android/server/pm/ApexManager.java
@@ -32,7 +32,6 @@
 import android.content.pm.PackageInstaller;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageParser;
-import android.content.pm.parsing.AndroidPackage;
 import android.os.Environment;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -47,6 +46,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.os.BackgroundThread;
 import com.android.internal.util.IndentingPrintWriter;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.utils.TimingsTraceAndSlog;
 
 import com.google.android.collect.Lists;
diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java
index a1250cb..1205a33 100644
--- a/services/core/java/com/android/server/pm/AppsFilter.java
+++ b/services/core/java/com/android/server/pm/AppsFilter.java
@@ -26,13 +26,12 @@
 import android.content.IntentFilter;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageParser;
-import android.content.pm.parsing.AndroidPackage;
-import android.content.pm.parsing.ComponentParseUtils;
-import android.content.pm.parsing.ComponentParseUtils.ParsedActivity;
-import android.content.pm.parsing.ComponentParseUtils.ParsedComponent;
-import android.content.pm.parsing.ComponentParseUtils.ParsedIntentInfo;
-import android.content.pm.parsing.ComponentParseUtils.ParsedProvider;
-import android.content.pm.parsing.ComponentParseUtils.ParsedService;
+import android.content.pm.parsing.component.ParsedActivity;
+import android.content.pm.parsing.component.ParsedComponent;
+import android.content.pm.parsing.component.ParsedInstrumentation;
+import android.content.pm.parsing.component.ParsedIntentInfo;
+import android.content.pm.parsing.component.ParsedProvider;
+import android.content.pm.parsing.component.ParsedService;
 import android.os.Binder;
 import android.os.Process;
 import android.os.Trace;
@@ -50,6 +49,7 @@
 import com.android.internal.util.ArrayUtils;
 import com.android.server.FgThread;
 import com.android.server.om.OverlayReferenceMapper;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
 
 import java.io.PrintWriter;
 import java.util.List;
@@ -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());
     }
 
@@ -261,7 +261,7 @@
     private static boolean matchesIntentFilters(Intent intent, AndroidPackage potentialTarget) {
         for (int s = ArrayUtils.size(potentialTarget.getServices()) - 1; s >= 0; s--) {
             ParsedService service = potentialTarget.getServices().get(s);
-            if (!service.exported) {
+            if (!service.isExported()) {
                 continue;
             }
             if (matchesAnyFilter(intent, service)) {
@@ -270,7 +270,7 @@
         }
         for (int a = ArrayUtils.size(potentialTarget.getActivities()) - 1; a >= 0; a--) {
             ParsedActivity activity = potentialTarget.getActivities().get(a);
-            if (!activity.exported) {
+            if (!activity.isExported()) {
                 continue;
             }
             if (matchesAnyFilter(intent, activity)) {
@@ -279,7 +279,7 @@
         }
         for (int r = ArrayUtils.size(potentialTarget.getReceivers()) - 1; r >= 0; r--) {
             ParsedActivity receiver = potentialTarget.getReceivers().get(r);
-            if (!receiver.exported) {
+            if (!receiver.isExported()) {
                 continue;
             }
             if (matchesAnyFilter(intent, receiver)) {
@@ -289,9 +289,8 @@
         return false;
     }
 
-    private static boolean matchesAnyFilter(
-            Intent intent, ParsedComponent<? extends ParsedIntentInfo> component) {
-        List<? extends ParsedIntentInfo> intents = component.intents;
+    private static boolean matchesAnyFilter(Intent intent, ParsedComponent component) {
+        List<ParsedIntentInfo> intents = component.getIntents();
         for (int i = ArrayUtils.size(intents) - 1; i >= 0; i--) {
             IntentFilter intentFilter = intents.get(i);
             if (intentFilter.match(intent.getAction(), intent.getType(), intent.getScheme(),
@@ -673,8 +672,7 @@
             String targetName) {
         try {
             Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "callingPkgInstruments");
-            final List<ComponentParseUtils.ParsedInstrumentation> inst =
-                    callingPkgSetting.pkg.getInstrumentations();
+            final List<ParsedInstrumentation> inst = callingPkgSetting.pkg.getInstrumentations();
             for (int i = ArrayUtils.size(inst) - 1; i >= 0; i--) {
                 if (Objects.equals(inst.get(i).getTargetPackage(), targetName)) {
                     if (DEBUG_LOGGING) {
diff --git a/services/core/java/com/android/server/pm/ComponentResolver.java b/services/core/java/com/android/server/pm/ComponentResolver.java
index 0dacadc..85810e3 100644
--- a/services/core/java/com/android/server/pm/ComponentResolver.java
+++ b/services/core/java/com/android/server/pm/ComponentResolver.java
@@ -22,12 +22,12 @@
 import static com.android.server.pm.PackageManagerService.DEBUG_PACKAGE_SCANNING;
 import static com.android.server.pm.PackageManagerService.DEBUG_REMOVE;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.ComponentName;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.ActivityInfo;
-import android.content.pm.ApplicationInfo;
 import android.content.pm.AuxiliaryResolveInfo;
 import android.content.pm.InstantAppResolveInfo;
 import android.content.pm.PackageManager;
@@ -37,15 +37,12 @@
 import android.content.pm.ProviderInfo;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
-import android.content.pm.parsing.AndroidPackage;
-import android.content.pm.parsing.ComponentParseUtils.ParsedActivity;
-import android.content.pm.parsing.ComponentParseUtils.ParsedActivityIntentInfo;
-import android.content.pm.parsing.ComponentParseUtils.ParsedIntentInfo;
-import android.content.pm.parsing.ComponentParseUtils.ParsedProvider;
-import android.content.pm.parsing.ComponentParseUtils.ParsedProviderIntentInfo;
-import android.content.pm.parsing.ComponentParseUtils.ParsedService;
-import android.content.pm.parsing.ComponentParseUtils.ParsedServiceIntentInfo;
-import android.content.pm.parsing.PackageInfoUtils;
+import android.content.pm.parsing.component.ParsedActivity;
+import android.content.pm.parsing.component.ParsedComponent;
+import android.content.pm.parsing.component.ParsedIntentInfo;
+import android.content.pm.parsing.component.ParsedMainComponent;
+import android.content.pm.parsing.component.ParsedProvider;
+import android.content.pm.parsing.component.ParsedService;
 import android.os.UserHandle;
 import android.util.ArrayMap;
 import android.util.ArraySet;
@@ -58,6 +55,8 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.ArrayUtils;
 import com.android.server.IntentResolver;
+import com.android.server.pm.parsing.PackageInfoUtils;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -191,8 +190,11 @@
      * of these during boot as we need to inspect at all of the intent filters on the
      * /system partition in order to know which component is the setup wizard. This can
      * only ever be non-empty if {@link #mDeferProtectedFilters} is {@code true}.
+     *
+     * This is a pair of component package name to actual filter, because we don't store the
+     * name inside the filter. It's technically independent of the component it's contained in.
      */
-    private List<ParsedActivityIntentInfo> mProtectedFilters;
+    private List<Pair<ParsedMainComponent, ParsedIntentInfo>> mProtectedFilters;
 
     ComponentResolver(UserManagerService userManager,
             PackageManagerInternal packageManagerInternal,
@@ -299,7 +301,7 @@
                     continue;
                 }
                 final ProviderInfo info = PackageInfoUtils.generateProviderInfo(
-                        pkg, p, flags, ps.readUserState(userId), userId);
+                        pkg, p, flags, ps.readUserState(userId), userId, ps);
                 if (info == null) {
                     continue;
                 }
@@ -329,7 +331,7 @@
                 return null;
             }
             return PackageInfoUtils.generateProviderInfo(pkg, p, flags,
-                    ps.readUserState(userId), userId);
+                    ps.readUserState(userId), userId, ps);
         }
     }
 
@@ -354,12 +356,12 @@
                     continue;
                 }
 
-                if (safeMode && (pkg.getFlags() & ApplicationInfo.FLAG_SYSTEM) == 0) {
+                if (safeMode && !pkg.isSystem()) {
                     continue;
                 }
                 final ProviderInfo info =
                         PackageInfoUtils.generateProviderInfo(pkg, p, 0,
-                                ps.readUserState(userId), userId);
+                                ps.readUserState(userId), userId, ps);
                 if (info == null) {
                     continue;
                 }
@@ -415,7 +417,7 @@
 
     /** Add all components defined in the given package to the internal structures. */
     void addAllComponents(AndroidPackage pkg, boolean chatty) {
-        final ArrayList<ParsedActivityIntentInfo> newIntents = new ArrayList<>();
+        final ArrayList<Pair<ParsedActivity, ParsedIntentInfo>> newIntents = new ArrayList<>();
         synchronized (mLock) {
             addActivitiesLocked(pkg, newIntents, chatty);
             addReceiversLocked(pkg, chatty);
@@ -428,14 +430,14 @@
                         PACKAGE_SETUP_WIZARD, UserHandle.USER_SYSTEM));
 
         for (int i = newIntents.size() - 1; i >= 0; --i) {
-            final ParsedActivityIntentInfo intentInfo = newIntents.get(i);
+            final Pair<ParsedActivity, ParsedIntentInfo> pair = newIntents.get(i);
             final PackageSetting disabledPkgSetting = (PackageSetting) sPackageManagerInternal
-                    .getDisabledSystemPackage(intentInfo.getPackageName());
+                    .getDisabledSystemPackage(pair.first.getPackageName());
             final AndroidPackage disabledPkg =
                     disabledPkgSetting == null ? null : disabledPkgSetting.pkg;
             final List<ParsedActivity> systemActivities =
                     disabledPkg != null ? disabledPkg.getActivities() : null;
-            adjustPriority(systemActivities, intentInfo, setupWizardPackage);
+            adjustPriority(systemActivities, pair.first, pair.second, setupWizardPackage);
         }
     }
 
@@ -459,7 +461,8 @@
         if (mProtectedFilters == null || mProtectedFilters.size() == 0) {
             return;
         }
-        final List<ParsedActivityIntentInfo> protectedFilters = mProtectedFilters;
+        final List<Pair<ParsedMainComponent, ParsedIntentInfo>> protectedFilters =
+                mProtectedFilters;
         mProtectedFilters = null;
 
         // expect single setupwizard package
@@ -472,13 +475,17 @@
                     + " All protected intents capped to priority 0");
         }
         for (int i = protectedFilters.size() - 1; i >= 0; --i) {
-            final ParsedActivityIntentInfo filter = protectedFilters.get(i);
-            if (filter.getPackageName().equals(setupWizardPackage)) {
+            final Pair<ParsedMainComponent, ParsedIntentInfo> pair = protectedFilters.get(i);
+            ParsedMainComponent component = pair.first;
+            ParsedIntentInfo filter = pair.second;
+            String packageName = component.getPackageName();
+            String className = component.getClassName();
+            if (packageName.equals(setupWizardPackage)) {
                 if (DEBUG_FILTERS) {
                     Slog.i(TAG, "Found setup wizard;"
                             + " allow priority " + filter.getPriority() + ";"
-                            + " package: " + filter.getPackageName()
-                            + " activity: " + filter.getClassName()
+                            + " package: " + packageName
+                            + " activity: " + className
                             + " priority: " + filter.getPriority());
                 }
                 // skip setup wizard; allow it to keep the high priority filter
@@ -486,8 +493,8 @@
             }
             if (DEBUG_FILTERS) {
                 Slog.i(TAG, "Protected action; cap priority to 0;"
-                        + " package: " + filter.getPackageName()
-                        + " activity: " + filter.getClassName()
+                        + " package: " + packageName
+                        + " activity: " + className
                         + " origPrio: " + filter.getPriority());
             }
             filter.setPriority(0);
@@ -540,7 +547,7 @@
                 printedSomething = true;
             }
             pw.print("  ");
-            ComponentName.printShortString(pw, p.getPackageName(), p.className);
+            ComponentName.printShortString(pw, p.getPackageName(), p.getName());
             pw.println(":");
             pw.print("    ");
             pw.println(p.toString());
@@ -575,24 +582,11 @@
         if (dumpState.onTitlePrinted()) pw.println();
         pw.println("Service permissions:");
 
-        final Iterator<ParsedServiceIntentInfo> filterIterator = mServices.filterIterator();
+        final Iterator<Pair<ParsedService, ParsedIntentInfo>> filterIterator =
+                mServices.filterIterator();
         while (filterIterator.hasNext()) {
-            final ParsedServiceIntentInfo info = filterIterator.next();
-
-            ParsedService service = null;
-
-            AndroidPackage pkg = sPackageManagerInternal.getPackage(info.getPackageName());
-            if (pkg != null && pkg.getServices() != null) {
-                for (ParsedService parsedService : pkg.getServices()) {
-                    if (Objects.equals(parsedService.className, info.getClassName())) {
-                        service = parsedService;
-                    }
-                }
-            }
-
-            if (service == null) {
-                continue;
-            }
+            final Pair<ParsedService, ParsedIntentInfo> pair = filterIterator.next();
+            ParsedService service = pair.first;
 
             final String permission = service.getPermission();
             if (permission != null) {
@@ -606,7 +600,7 @@
 
     @GuardedBy("mLock")
     private void addActivitiesLocked(AndroidPackage pkg,
-            List<ParsedActivityIntentInfo> newIntents, boolean chatty) {
+            List<Pair<ParsedActivity, ParsedIntentInfo>> newIntents, boolean chatty) {
         final int activitiesSize = ArrayUtils.size(pkg.getActivities());
         StringBuilder r = null;
         for (int i = 0; i < activitiesSize; i++) {
@@ -671,7 +665,7 @@
                         final String packageName =
                                 component != null ? component.getPackageName() : "?";
                         Slog.w(TAG, "Skipping provider name " + names[j]
-                                + " (in package " + pkg.getAppInfoPackageName() + ")"
+                                + " (in package " + pkg.getPackageName() + ")"
                                 + ": name already used by " + packageName);
                     }
                 }
@@ -736,8 +730,8 @@
      * <em>WARNING</em> for performance reasons, the passed in intentList WILL BE
      * MODIFIED. Do not pass in a list that should not be changed.
      */
-    private static <T> void getIntentListSubset(List<ParsedActivityIntentInfo> intentList,
-            Function<ParsedActivityIntentInfo, Iterator<T>> generator, Iterator<T> searchIterator) {
+    private static <T> void getIntentListSubset(List<ParsedIntentInfo> intentList,
+            Function<ParsedIntentInfo, Iterator<T>> generator, Iterator<T> searchIterator) {
         // loop through the set of actions; every one must be found in the intent filter
         while (searchIterator.hasNext()) {
             // we must have at least one filter in the list to consider a match
@@ -748,9 +742,9 @@
             final T searchAction = searchIterator.next();
 
             // loop through the set of intent filters
-            final Iterator<ParsedActivityIntentInfo> intentIter = intentList.iterator();
+            final Iterator<ParsedIntentInfo> intentIter = intentList.iterator();
             while (intentIter.hasNext()) {
-                final ParsedActivityIntentInfo intentInfo = intentIter.next();
+                final ParsedIntentInfo intentInfo = intentIter.next();
                 boolean selectionFound = false;
 
                 // loop through the intent filter's selection criteria; at least one
@@ -773,7 +767,7 @@
         }
     }
 
-    private static boolean isProtectedAction(ParsedActivityIntentInfo filter) {
+    private static boolean isProtectedAction(ParsedIntentInfo filter) {
         final Iterator<String> actionsIter = filter.actionsIterator();
         while (actionsIter != null && actionsIter.hasNext()) {
             final String filterAction = actionsIter.next();
@@ -793,14 +787,14 @@
             if (sysActivity.getName().equals(activityInfo.getName())) {
                 return sysActivity;
             }
-            if (sysActivity.getName().equals(activityInfo.targetActivity)) {
+            if (sysActivity.getName().equals(activityInfo.getTargetActivity())) {
                 return sysActivity;
             }
-            if (sysActivity.targetActivity != null) {
-                if (sysActivity.targetActivity.equals(activityInfo.getName())) {
+            if (sysActivity.getTargetActivity() != null) {
+                if (sysActivity.getTargetActivity().equals(activityInfo.getName())) {
                     return sysActivity;
                 }
-                if (sysActivity.targetActivity.equals(activityInfo.targetActivity)) {
+                if (sysActivity.getTargetActivity().equals(activityInfo.getTargetActivity())) {
                     return sysActivity;
                 }
             }
@@ -821,23 +815,24 @@
      * <em>NOTE:</em> There is one exception. For security reasons, the setup wizard is
      * allowed to obtain any priority on any action.
      */
-    private void adjustPriority(List<ParsedActivity> systemActivities,
-            ParsedActivityIntentInfo intent, String setupWizardPackage) {
+    private void adjustPriority(List<ParsedActivity> systemActivities, ParsedActivity activity,
+            ParsedIntentInfo intent, String setupWizardPackage) {
         // nothing to do; priority is fine as-is
         if (intent.getPriority() <= 0) {
             return;
         }
 
-        AndroidPackage pkg = sPackageManagerInternal.getPackage(intent.getPackageName());
+        String packageName = activity.getPackageName();
+        AndroidPackage pkg = sPackageManagerInternal.getPackage(packageName);
 
-        final boolean privilegedApp =
-                ((pkg.getPrivateFlags() & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0);
+        final boolean privilegedApp = pkg.isPrivileged();
+        String className = activity.getClassName();
         if (!privilegedApp) {
             // non-privileged applications can never define a priority >0
             if (DEBUG_FILTERS) {
                 Slog.i(TAG, "Non-privileged app; cap priority to 0;"
-                        + " package: " + pkg.getPackageName()
-                        + " activity: " + intent.getClassName()
+                        + " package: " + packageName
+                        + " activity: " + className
                         + " origPrio: " + intent.getPriority());
             }
             intent.setPriority(0);
@@ -858,11 +853,11 @@
                     if (mProtectedFilters == null) {
                         mProtectedFilters = new ArrayList<>();
                     }
-                    mProtectedFilters.add(intent);
+                    mProtectedFilters.add(Pair.create(activity, intent));
                     if (DEBUG_FILTERS) {
                         Slog.i(TAG, "Protected action; save for later;"
-                                + " package: " + pkg.getPackageName()
-                                + " activity: " + intent.getClassName()
+                                + " package: " + packageName
+                                + " activity: " + className
                                 + " origPrio: " + intent.getPriority());
                     }
                     return;
@@ -871,12 +866,12 @@
                         Slog.i(TAG, "No setup wizard;"
                                 + " All protected intents capped to priority 0");
                     }
-                    if (intent.getPackageName().equals(setupWizardPackage)) {
+                    if (packageName.equals(setupWizardPackage)) {
                         if (DEBUG_FILTERS) {
                             Slog.i(TAG, "Found setup wizard;"
                                     + " allow priority " + intent.getPriority() + ";"
-                                    + " package: " + intent.getPackageName()
-                                    + " activity: " + intent.getClassName()
+                                    + " package: " + packageName
+                                    + " activity: " + className
                                     + " priority: " + intent.getPriority());
                         }
                         // setup wizard gets whatever it wants
@@ -884,8 +879,8 @@
                     }
                     if (DEBUG_FILTERS) {
                         Slog.i(TAG, "Protected action; cap priority to 0;"
-                                + " package: " + intent.getPackageName()
-                                + " activity: " + intent.getClassName()
+                                + " package: " + packageName
+                                + " activity: " + className
                                 + " origPrio: " + intent.getPriority());
                     }
                     intent.setPriority(0);
@@ -898,27 +893,13 @@
 
         // privileged app unbundled update ... try to find the same activity
 
-        ParsedActivity foundActivity = null;
-        ParsedActivity activity = null;
-
-        if (pkg.getActivities() != null) {
-            for (ParsedActivity parsedProvider : pkg.getActivities()) {
-                if (Objects.equals(parsedProvider.className, intent.getClassName())) {
-                    activity = parsedProvider;
-                }
-            }
-        }
-
-        if (activity != null) {
-            foundActivity = findMatchingActivity(systemActivities, activity);
-        }
-
+        ParsedActivity foundActivity = findMatchingActivity(systemActivities, activity);
         if (foundActivity == null) {
             // this is a new activity; it cannot obtain >0 priority
             if (DEBUG_FILTERS) {
                 Slog.i(TAG, "New activity; cap priority to 0;"
-                        + " package: " + pkg.getPackageName()
-                        + " activity: " + intent.getClassName()
+                        + " package: " + packageName
+                        + " activity: " + className
                         + " origPrio: " + intent.getPriority());
             }
             intent.setPriority(0);
@@ -928,8 +909,8 @@
         // found activity, now check for filter equivalence
 
         // a shallow copy is enough; we modify the list, not its contents
-        final List<ParsedActivityIntentInfo> intentListCopy =
-                new ArrayList<>(foundActivity.intents);
+        final List<ParsedIntentInfo> intentListCopy =
+                new ArrayList<>(foundActivity.getIntents());
 
         // find matching action subsets
         final Iterator<String> actionsIterator = intent.actionsIterator();
@@ -939,8 +920,8 @@
                 // no more intents to match; we're not equivalent
                 if (DEBUG_FILTERS) {
                     Slog.i(TAG, "Mismatched action; cap priority to 0;"
-                            + " package: " + pkg.getPackageName()
-                            + " activity: " + intent.getClassName()
+                            + " package: " + packageName
+                            + " activity: " + className
                             + " origPrio: " + intent.getPriority());
                 }
                 intent.setPriority(0);
@@ -957,8 +938,8 @@
                 // no more intents to match; we're not equivalent
                 if (DEBUG_FILTERS) {
                     Slog.i(TAG, "Mismatched category; cap priority to 0;"
-                            + " package: " + pkg.getPackageName()
-                            + " activity: " + intent.getClassName()
+                            + " package: " + packageName
+                            + " activity: " + className
                             + " origPrio: " + intent.getPriority());
                 }
                 intent.setPriority(0);
@@ -974,8 +955,8 @@
                 // no more intents to match; we're not equivalent
                 if (DEBUG_FILTERS) {
                     Slog.i(TAG, "Mismatched scheme; cap priority to 0;"
-                            + " package: " + pkg.getPackageName()
-                            + " activity: " + intent.getClassName()
+                            + " package: " + packageName
+                            + " activity: " + className
                             + " origPrio: " + intent.getPriority());
                 }
                 intent.setPriority(0);
@@ -993,8 +974,8 @@
                 // no more intents to match; we're not equivalent
                 if (DEBUG_FILTERS) {
                     Slog.i(TAG, "Mismatched authority; cap priority to 0;"
-                            + " package: " + pkg.getPackageName()
-                            + " activity: " + intent.getClassName()
+                            + " package: " + packageName
+                            + " activity: " + className
                             + " origPrio: " + intent.getPriority());
                 }
                 intent.setPriority(0);
@@ -1011,8 +992,8 @@
             if (DEBUG_FILTERS) {
                 Slog.i(TAG, "Found matching filter(s);"
                         + " cap priority to " + cappedPriority + ";"
-                        + " package: " + pkg.getPackageName()
-                        + " activity: " + intent.getClassName()
+                        + " package: " + packageName
+                        + " activity: " + className
                         + " origPrio: " + intent.getPriority());
             }
             intent.setPriority(cappedPriority);
@@ -1146,31 +1127,34 @@
         }
     }
 
-    private abstract static class MimeGroupsAwareIntentResolver<F extends ParsedIntentInfo, R>
+    private abstract static class MimeGroupsAwareIntentResolver<F extends Pair<?
+            extends ParsedComponent, ParsedIntentInfo>, R>
             extends IntentResolver<F, R> {
         private ArrayMap<String, F[]> mMimeGroupToFilter = new ArrayMap<>();
         private boolean mIsUpdatingMimeGroup = false;
 
         @Override
         public void addFilter(F f) {
+            IntentFilter intentFilter = getIntentFilter(f);
             applyMimeGroups(f);
             super.addFilter(f);
 
             if (!mIsUpdatingMimeGroup) {
-                register_intent_filter(f, f.mimeGroupsIterator(), mMimeGroupToFilter,
+                register_intent_filter(f, intentFilter.mimeGroupsIterator(), mMimeGroupToFilter,
                         "      MimeGroup: ");
             }
         }
 
         @Override
         protected void removeFilterInternal(F f) {
+            IntentFilter intentFilter = getIntentFilter(f);
             if (!mIsUpdatingMimeGroup) {
-                unregister_intent_filter(f, f.mimeGroupsIterator(), mMimeGroupToFilter,
+                unregister_intent_filter(f, intentFilter.mimeGroupsIterator(), mMimeGroupToFilter,
                         "      MimeGroup: ");
             }
 
             super.removeFilterInternal(f);
-            f.clearDynamicDataTypes();
+            intentFilter.clearDynamicDataTypes();
         }
 
         /**
@@ -1197,10 +1181,11 @@
             return hasChanges;
         }
 
-        private boolean updateFilter(F filter) {
+        private boolean updateFilter(F f) {
+            IntentFilter filter = getIntentFilter(f);
             List<String> oldTypes = filter.dataTypes();
-            removeFilter(filter);
-            addFilter(filter);
+            removeFilter(f);
+            addFilter(f);
             List<String> newTypes = filter.dataTypes();
             return !equalLists(oldTypes, newTypes);
         }
@@ -1221,12 +1206,12 @@
             return first.equals(second);
         }
 
-        private void applyMimeGroups(F filter) {
-            String packageName = filter.getPackageName();
+        private void applyMimeGroups(F f) {
+            IntentFilter filter = getIntentFilter(f);
 
             for (int i = filter.countMimeGroups() - 1; i >= 0; i--) {
-                List<String> mimeTypes = sPackageManagerInternal.getMimeGroup(packageName,
-                        filter.getMimeGroup(i));
+                List<String> mimeTypes = sPackageManagerInternal.getMimeGroup(
+                        f.first.getPackageName(), filter.getMimeGroup(i));
 
                 for (int typeIndex = mimeTypes.size() - 1; typeIndex >= 0; typeIndex--) {
                     String mimeType = mimeTypes.get(typeIndex);
@@ -1244,7 +1229,7 @@
     }
 
     private static class ActivityIntentResolver
-            extends MimeGroupsAwareIntentResolver<ParsedActivityIntentInfo, ResolveInfo> {
+            extends MimeGroupsAwareIntentResolver<Pair<ParsedActivity, ParsedIntentInfo>, ResolveInfo> {
 
         @Override
         public List<ResolveInfo> queryIntent(Intent intent, String resolvedType,
@@ -1277,15 +1262,18 @@
             mFlags = flags;
             final boolean defaultOnly = (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0;
             final int activitiesSize = packageActivities.size();
-            ArrayList<ParsedActivityIntentInfo[]> listCut = new ArrayList<>(activitiesSize);
+            ArrayList<Pair<ParsedActivity, ParsedIntentInfo>[]> listCut =
+                    new ArrayList<>(activitiesSize);
 
-            List<ParsedActivityIntentInfo> intentFilters;
+            List<ParsedIntentInfo> intentFilters;
             for (int i = 0; i < activitiesSize; ++i) {
-                intentFilters = packageActivities.get(i).intents;
-                if (intentFilters != null && intentFilters.size() > 0) {
-                    ParsedActivityIntentInfo[] array =
-                            new ParsedActivityIntentInfo[intentFilters.size()];
-                    intentFilters.toArray(array);
+                ParsedActivity activity = packageActivities.get(i);
+                intentFilters = activity.getIntents();
+                if (!intentFilters.isEmpty()) {
+                    Pair<ParsedActivity, ParsedIntentInfo>[] array = newArray(intentFilters.size());
+                    for (int arrayIndex = 0; arrayIndex < intentFilters.size(); arrayIndex++) {
+                        array[arrayIndex] = Pair.create(activity, intentFilters.get(arrayIndex));
+                    }
                     listCut.add(array);
                 }
             }
@@ -1293,22 +1281,17 @@
         }
 
         private void addActivity(ParsedActivity a, String type,
-                List<ParsedActivityIntentInfo> newIntents) {
+                List<Pair<ParsedActivity, ParsedIntentInfo>> newIntents) {
             mActivities.put(a.getComponentName(), a);
             if (DEBUG_SHOW_INFO) {
-                final CharSequence label = a.nonLocalizedLabel != null
-                        ? a.nonLocalizedLabel
-                        : a.getName();
-                Log.v(TAG, "  " + type + " " + label + ":");
-            }
-            if (DEBUG_SHOW_INFO) {
+                Log.v(TAG, "  " + type + ":");
                 Log.v(TAG, "    Class=" + a.getName());
             }
-            final int intentsSize = a.intents.size();
+            final int intentsSize = a.getIntents().size();
             for (int j = 0; j < intentsSize; j++) {
-                ParsedActivityIntentInfo intent = a.intents.get(j);
+                ParsedIntentInfo intent = a.getIntents().get(j);
                 if (newIntents != null && "activity".equals(type)) {
-                    newIntents.add(intent);
+                    newIntents.add(Pair.create(a, intent));
                 }
                 if (DEBUG_SHOW_INFO) {
                     Log.v(TAG, "    IntentFilter:");
@@ -1317,36 +1300,34 @@
                 if (!intent.debugCheck()) {
                     Log.w(TAG, "==> For Activity " + a.getName());
                 }
-                addFilter(intent);
+                addFilter(Pair.create(a, intent));
             }
         }
 
         private void removeActivity(ParsedActivity a, String type) {
             mActivities.remove(a.getComponentName());
             if (DEBUG_SHOW_INFO) {
-                Log.v(TAG, "  " + type + " "
-                        + (a.nonLocalizedLabel != null ? a.nonLocalizedLabel
-                                : a.getName()) + ":");
+                Log.v(TAG, "  " + type + ":");
                 Log.v(TAG, "    Class=" + a.getName());
             }
-            final int intentsSize = a.intents.size();
+            final int intentsSize = a.getIntents().size();
             for (int j = 0; j < intentsSize; j++) {
-                ParsedActivityIntentInfo intent = a.intents.get(j);
+                ParsedIntentInfo intent = a.getIntents().get(j);
                 if (DEBUG_SHOW_INFO) {
                     Log.v(TAG, "    IntentFilter:");
                     intent.dump(new LogPrinter(Log.VERBOSE, TAG), "      ");
                 }
-                removeFilter(intent);
+                removeFilter(Pair.create(a, intent));
             }
         }
 
         @Override
-        protected boolean allowFilterResult(
-                ParsedActivityIntentInfo filter, List<ResolveInfo> dest) {
+        protected boolean allowFilterResult(Pair<ParsedActivity, ParsedIntentInfo> filter,
+                List<ResolveInfo> dest) {
             for (int i = dest.size() - 1; i >= 0; --i) {
                 ActivityInfo destAi = dest.get(i).activityInfo;
-                if (Objects.equals(destAi.name, filter.getClassName())
-                        && Objects.equals(destAi.packageName, filter.getPackageName())) {
+                if (Objects.equals(destAi.name, filter.first.getName())
+                        && Objects.equals(destAi.packageName, filter.first.getPackageName())) {
                     return false;
                 }
             }
@@ -1354,39 +1335,23 @@
         }
 
         @Override
-        protected ParsedActivityIntentInfo[] newArray(int size) {
-            return new ParsedActivityIntentInfo[size];
+        protected Pair<ParsedActivity, ParsedIntentInfo>[] newArray(int size) {
+            //noinspection unchecked
+            return (Pair<ParsedActivity, ParsedIntentInfo>[]) new Pair<?, ?>[size];
         }
 
         @Override
-        protected boolean isFilterStopped(ParsedActivityIntentInfo filter, int userId) {
-            if (!sUserManager.exists(userId)) return true;
-
-            AndroidPackage pkg = sPackageManagerInternal.getPackage(filter.getPackageName());
-            if (pkg == null) {
-                return false;
-            }
-
-            PackageSetting ps = (PackageSetting) sPackageManagerInternal.getPackageSetting(
-                    filter.getPackageName());
-            if (ps == null) {
-                return false;
-            }
-
-            // System apps are never considered stopped for purposes of
-            // filtering, because there may be no way for the user to
-            // actually re-launch them.
-            return (ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0
-                    && ps.getStopped(userId);
+        protected boolean isFilterStopped(Pair<ParsedActivity, ParsedIntentInfo> filter, int userId) {
+            return ComponentResolver.isFilterStopped(filter, userId);
         }
 
         @Override
         protected boolean isPackageForFilter(String packageName,
-                ParsedActivityIntentInfo info) {
-            return packageName.equals(info.getPackageName());
+                Pair<ParsedActivity, ParsedIntentInfo> info) {
+            return packageName.equals(info.first.getPackageName());
         }
 
-        private void log(String reason, ParsedActivityIntentInfo info, int match,
+        private void log(String reason, ParsedIntentInfo info, int match,
                 int userId) {
             Slog.w(TAG, reason
                     + "; match: "
@@ -1396,8 +1361,11 @@
         }
 
         @Override
-        protected ResolveInfo newResult(ParsedActivityIntentInfo info,
+        protected ResolveInfo newResult(Pair<ParsedActivity, ParsedIntentInfo> pair,
                 int match, int userId) {
+            ParsedActivity activity = pair.first;
+            ParsedIntentInfo info = pair.second;
+
             if (!sUserManager.exists(userId)) {
                 if (DEBUG) {
                     log("User doesn't exist", info, match, userId);
@@ -1405,27 +1373,11 @@
                 return null;
             }
 
-            ParsedActivity activity = null;
-
-            AndroidPackage pkg = sPackageManagerInternal.getPackage(info.getPackageName());
+            AndroidPackage pkg = sPackageManagerInternal.getPackage(activity.getPackageName());
             if (pkg == null) {
                 return null;
             }
 
-            // TODO(b/135203078): Consider more efficient ways of doing this.
-            List<ParsedActivity> activities = getResolveList(pkg);
-            if (activities != null) {
-                for (ParsedActivity parsedActivity : activities) {
-                    if (Objects.equals(parsedActivity.className, info.getClassName())) {
-                        activity = parsedActivity;
-                    }
-                }
-            }
-
-            if (activity == null) {
-                return null;
-            }
-
             if (!sPackageManagerInternal.isEnabledAndMatches(activity, mFlags, userId)) {
                 if (DEBUG) {
                     log("!PackageManagerInternal.isEnabledAndMatches; mFlags="
@@ -1435,7 +1387,7 @@
                 return null;
             }
             PackageSetting ps = (PackageSetting) sPackageManagerInternal.getPackageSetting(
-                    info.getPackageName());
+                    activity.getPackageName());
             if (ps == null) {
                 if (DEBUG) {
                     log("info.activity.owner.mExtras == null", info, match, userId);
@@ -1443,8 +1395,8 @@
                 return null;
             }
             final PackageUserState userState = ps.readUserState(userId);
-            ActivityInfo ai =
-                    PackageInfoUtils.generateActivityInfo(pkg, activity, mFlags, userState, userId);
+            ActivityInfo ai = PackageInfoUtils.generateActivityInfo(pkg, activity, mFlags,
+                    userState, userId, ps);
             if (ai == null) {
                 if (DEBUG) {
                     log("Failed to create ActivityInfo based on " + activity, info, match,
@@ -1502,19 +1454,20 @@
             }
             res.handleAllWebDataURI = info.handleAllWebDataURI();
             res.priority = info.getPriority();
-            res.preferredOrder = pkg.getPreferredOrder();
+            // TODO(b/135203078): This field was unwritten and does nothing
+//            res.preferredOrder = pkg.getPreferredOrder();
             //System.out.println("Result: " + res.activityInfo.className +
             //                   " = " + res.priority);
             res.match = match;
-            res.isDefault = info.hasDefault;
-            res.labelRes = info.labelRes;
-            res.nonLocalizedLabel = info.nonLocalizedLabel;
+            res.isDefault = info.isHasDefault();
+            res.labelRes = info.getLabelRes();
+            res.nonLocalizedLabel = info.getNonLocalizedLabel();
             if (sPackageManagerInternal.userNeedsBadging(userId)) {
                 res.noResourceId = true;
             } else {
-                res.icon = info.icon;
+                res.icon = info.getIcon();
             }
-            res.iconResourceId = info.icon;
+            res.iconResourceId = info.getIcon();
             res.system = res.activityInfo.applicationInfo.isSystemApp();
             res.isInstantAppAvailable = userState.instantApp;
             return res;
@@ -1527,43 +1480,44 @@
 
         @Override
         protected void dumpFilter(PrintWriter out, String prefix,
-                ParsedActivityIntentInfo filter) {
-            ParsedActivity activity = null;
-
-            AndroidPackage pkg = sPackageManagerInternal.getPackage(filter.getPackageName());
-            if (pkg != null && pkg.getActivities() != null) {
-                for (ParsedActivity parsedActivity : pkg.getActivities()) {
-                    if (Objects.equals(parsedActivity.className, filter.getClassName())) {
-                        activity = parsedActivity;
-                    }
-                }
-            }
+                Pair<ParsedActivity, ParsedIntentInfo> pair) {
+            ParsedActivity activity = pair.first;
+            ParsedIntentInfo filter = pair.second;
 
             out.print(prefix);
             out.print(Integer.toHexString(System.identityHashCode(activity)));
             out.print(' ');
-            ComponentName.printShortString(out, filter.getPackageName(), filter.getClassName());
+            ComponentName.printShortString(out, activity.getPackageName(),
+                    activity.getClassName());
             out.print(" filter ");
             out.println(Integer.toHexString(System.identityHashCode(filter)));
         }
 
         @Override
-        protected Object filterToLabel(ParsedActivityIntentInfo filter) {
+        protected Object filterToLabel(Pair<ParsedActivity, ParsedIntentInfo> filter) {
             return filter;
         }
 
         protected void dumpFilterLabel(PrintWriter out, String prefix, Object label, int count) {
-            ParsedActivityIntentInfo activity = (ParsedActivityIntentInfo) label;
+            @SuppressWarnings("unchecked") Pair<ParsedActivity, ParsedIntentInfo> pair =
+                    (Pair<ParsedActivity, ParsedIntentInfo>) label;
             out.print(prefix);
-            out.print(Integer.toHexString(System.identityHashCode(activity)));
+            out.print(Integer.toHexString(System.identityHashCode(pair.first)));
             out.print(' ');
-            ComponentName.printShortString(out, activity.getPackageName(), activity.getClassName());
+            ComponentName.printShortString(out, pair.first.getPackageName(),
+                    pair.first.getClassName());
             if (count > 1) {
                 out.print(" ("); out.print(count); out.print(" filters)");
             }
             out.println();
         }
 
+        @Override
+        protected IntentFilter getIntentFilter(
+                @NonNull Pair<ParsedActivity, ParsedIntentInfo> input) {
+            return input.second;
+        }
+
         protected List<ParsedActivity> getResolveList(AndroidPackage pkg) {
             return pkg.getActivities();
         }
@@ -1585,7 +1539,7 @@
     }
 
     private static final class ProviderIntentResolver
-            extends MimeGroupsAwareIntentResolver<ParsedProviderIntentInfo, ResolveInfo> {
+            extends MimeGroupsAwareIntentResolver<Pair<ParsedProvider, ParsedIntentInfo>, ResolveInfo> {
         @Override
         public List<ResolveInfo> queryIntent(Intent intent, String resolvedType,
                 boolean defaultOnly, int userId) {
@@ -1617,15 +1571,18 @@
             mFlags = flags;
             final boolean defaultOnly = (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0;
             final int providersSize = packageProviders.size();
-            ArrayList<ParsedProviderIntentInfo[]> listCut = new ArrayList<>(providersSize);
+            ArrayList<Pair<ParsedProvider, ParsedIntentInfo>[]> listCut =
+                    new ArrayList<>(providersSize);
 
-            List<ParsedProviderIntentInfo> intentFilters;
+            List<ParsedIntentInfo> intentFilters;
             for (int i = 0; i < providersSize; ++i) {
-                intentFilters = packageProviders.get(i).getIntents();
-                if (intentFilters != null && intentFilters.size() > 0) {
-                    ParsedProviderIntentInfo[] array =
-                            new ParsedProviderIntentInfo[intentFilters.size()];
-                    intentFilters.toArray(array);
+                ParsedProvider provider = packageProviders.get(i);
+                intentFilters = provider.getIntents();
+                if (!intentFilters.isEmpty()) {
+                    Pair<ParsedProvider, ParsedIntentInfo>[] array = newArray(intentFilters.size());
+                    for (int arrayIndex = 0; arrayIndex < intentFilters.size(); arrayIndex++) {
+                        array[arrayIndex] = Pair.create(provider, intentFilters.get(arrayIndex));
+                    }
                     listCut.add(array);
                 }
             }
@@ -1640,17 +1597,13 @@
 
             mProviders.put(p.getComponentName(), p);
             if (DEBUG_SHOW_INFO) {
-                Log.v(TAG, "  "
-                        + (p.nonLocalizedLabel != null
-                                ? p.nonLocalizedLabel
-                                : p.getName())
-                        + ":");
+                Log.v(TAG, "  provider:");
                 Log.v(TAG, "    Class=" + p.getName());
             }
             final int intentsSize = p.getIntents().size();
             int j;
             for (j = 0; j < intentsSize; j++) {
-                ParsedProviderIntentInfo intent = p.getIntents().get(j);
+                ParsedIntentInfo intent = p.getIntents().get(j);
                 if (DEBUG_SHOW_INFO) {
                     Log.v(TAG, "    IntentFilter:");
                     intent.dump(new LogPrinter(Log.VERBOSE, TAG), "      ");
@@ -1658,37 +1611,35 @@
                 if (!intent.debugCheck()) {
                     Log.w(TAG, "==> For Provider " + p.getName());
                 }
-                addFilter(intent);
+                addFilter(Pair.create(p, intent));
             }
         }
 
         void removeProvider(ParsedProvider p) {
             mProviders.remove(p.getComponentName());
             if (DEBUG_SHOW_INFO) {
-                Log.v(TAG, "  " + (p.nonLocalizedLabel != null
-                        ? p.nonLocalizedLabel
-                        : p.getName()) + ":");
+                Log.v(TAG, "  provider:");
                 Log.v(TAG, "    Class=" + p.getName());
             }
             final int intentsSize = p.getIntents().size();
             int j;
             for (j = 0; j < intentsSize; j++) {
-                ParsedProviderIntentInfo intent = p.getIntents().get(j);
+                ParsedIntentInfo intent = p.getIntents().get(j);
                 if (DEBUG_SHOW_INFO) {
                     Log.v(TAG, "    IntentFilter:");
                     intent.dump(new LogPrinter(Log.VERBOSE, TAG), "      ");
                 }
-                removeFilter(intent);
+                removeFilter(Pair.create(p, intent));
             }
         }
 
         @Override
-        protected boolean allowFilterResult(
-                ParsedProviderIntentInfo filter, List<ResolveInfo> dest) {
+        protected boolean allowFilterResult(Pair<ParsedProvider, ParsedIntentInfo> filter,
+                List<ResolveInfo> dest) {
             for (int i = dest.size() - 1; i >= 0; i--) {
                 ProviderInfo destPi = dest.get(i).providerInfo;
-                if (Objects.equals(destPi.name, filter.getClassName())
-                        && Objects.equals(destPi.packageName, filter.getPackageName())) {
+                if (Objects.equals(destPi.name, filter.first.getClassName())
+                        && Objects.equals(destPi.packageName, filter.first.getPackageName())) {
                     return false;
                 }
             }
@@ -1696,59 +1647,35 @@
         }
 
         @Override
-        protected ParsedProviderIntentInfo[] newArray(int size) {
-            return new ParsedProviderIntentInfo[size];
+        protected Pair<ParsedProvider, ParsedIntentInfo>[] newArray(int size) {
+            //noinspection unchecked
+            return (Pair<ParsedProvider, ParsedIntentInfo>[]) new Pair<?, ?>[size];
         }
 
         @Override
-        protected boolean isFilterStopped(ParsedProviderIntentInfo filter, int userId) {
-            if (!sUserManager.exists(userId)) {
-                return true;
-            }
-
-            AndroidPackage pkg = sPackageManagerInternal.getPackage(filter.getPackageName());
-            if (pkg == null) {
-                return false;
-            }
-
-            PackageSetting ps = (PackageSetting) sPackageManagerInternal.getPackageSetting(
-                    filter.getPackageName());
-            if (ps == null) {
-                return false;
-            }
-
-            // System apps are never considered stopped for purposes of
-            // filtering, because there may be no way for the user to
-            // actually re-launch them.
-            return (ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0
-                    && ps.getStopped(userId);
+        protected boolean isFilterStopped(Pair<ParsedProvider, ParsedIntentInfo> filter,
+                int userId) {
+            return ComponentResolver.isFilterStopped(filter, userId);
         }
 
         @Override
         protected boolean isPackageForFilter(String packageName,
-                ParsedProviderIntentInfo info) {
-            return packageName.equals(info.getPackageName());
+                Pair<ParsedProvider, ParsedIntentInfo> info) {
+            return packageName.equals(info.first.getPackageName());
         }
 
         @Override
-        protected ResolveInfo newResult(ParsedProviderIntentInfo filter,
+        protected ResolveInfo newResult(Pair<ParsedProvider, ParsedIntentInfo> pair,
                 int match, int userId) {
             if (!sUserManager.exists(userId)) {
                 return null;
             }
 
-            ParsedProvider provider = null;
+            ParsedProvider provider = pair.first;
+            ParsedIntentInfo filter = pair.second;
 
-            AndroidPackage pkg = sPackageManagerInternal.getPackage(filter.getPackageName());
-            if (pkg != null && pkg.getProviders() != null) {
-                for (ParsedProvider parsedProvider : pkg.getProviders()) {
-                    if (Objects.equals(parsedProvider.className, filter.getClassName())) {
-                        provider = parsedProvider;
-                    }
-                }
-            }
-
-            if (provider == null) {
+            AndroidPackage pkg = sPackageManagerInternal.getPackage(provider.getPackageName());
+            if (pkg == null) {
                 return null;
             }
 
@@ -1757,7 +1684,7 @@
             }
 
             PackageSetting ps = (PackageSetting) sPackageManagerInternal.getPackageSetting(
-                    filter.getPackageName());
+                    provider.getPackageName());
             if (ps == null) {
                 return null;
             }
@@ -1779,8 +1706,8 @@
             if (userState.instantApp && ps.isUpdateAvailable()) {
                 return null;
             }
-            ProviderInfo pi = PackageInfoUtils.generateProviderInfo(pkg, provider,
-                    mFlags, userState, userId);
+            ProviderInfo pi = PackageInfoUtils.generateProviderInfo(pkg, provider, mFlags,
+                    userState, userId, ps);
             if (pi == null) {
                 return null;
             }
@@ -1790,12 +1717,13 @@
                 res.filter = filter;
             }
             res.priority = filter.getPriority();
-            res.preferredOrder = pkg.getPreferredOrder();
+            // TODO(b/135203078): This field was unwritten and does nothing
+//            res.preferredOrder = pkg.getPreferredOrder();
             res.match = match;
-            res.isDefault = filter.hasDefault;
-            res.labelRes = filter.labelRes;
-            res.nonLocalizedLabel = filter.nonLocalizedLabel;
-            res.icon = filter.icon;
+            res.isDefault = filter.isHasDefault();
+            res.labelRes = filter.getLabelRes();
+            res.nonLocalizedLabel = filter.getNonLocalizedLabel();
+            res.icon = filter.getIcon();
             res.system = res.providerInfo.applicationInfo.isSystemApp();
             return res;
         }
@@ -1807,37 +1735,31 @@
 
         @Override
         protected void dumpFilter(PrintWriter out, String prefix,
-                ParsedProviderIntentInfo filter) {
-            ParsedProvider provider = null;
-
-            AndroidPackage pkg = sPackageManagerInternal.getPackage(filter.getPackageName());
-            if (pkg != null && pkg.getProviders() != null) {
-                for (ParsedProvider parsedProvider : pkg.getProviders()) {
-                    if (Objects.equals(parsedProvider.className, filter.getClassName())) {
-                        provider = parsedProvider;
-                    }
-                }
-            }
+                Pair<ParsedProvider, ParsedIntentInfo> pair) {
+            ParsedProvider provider = pair.first;
+            ParsedIntentInfo filter = pair.second;
 
             out.print(prefix);
             out.print(Integer.toHexString(System.identityHashCode(provider)));
             out.print(' ');
-            ComponentName.printShortString(out, filter.getPackageName(), filter.getClassName());
+            ComponentName.printShortString(out, provider.getPackageName(), provider.getClassName());
             out.print(" filter ");
             out.println(Integer.toHexString(System.identityHashCode(filter)));
         }
 
         @Override
-        protected Object filterToLabel(ParsedProviderIntentInfo filter) {
+        protected Object filterToLabel(Pair<ParsedProvider, ParsedIntentInfo> filter) {
             return filter;
         }
 
         protected void dumpFilterLabel(PrintWriter out, String prefix, Object label, int count) {
-            final ParsedProviderIntentInfo provider = (ParsedProviderIntentInfo) label;
+            @SuppressWarnings("unchecked") final Pair<ParsedProvider, ParsedIntentInfo> pair =
+                    (Pair<ParsedProvider, ParsedIntentInfo>) label;
             out.print(prefix);
-            out.print(Integer.toHexString(System.identityHashCode(provider)));
+            out.print(Integer.toHexString(System.identityHashCode(pair.first)));
             out.print(' ');
-            ComponentName.printShortString(out, provider.getPackageName(), provider.getClassName());
+            ComponentName.printShortString(out, pair.first.getPackageName(),
+                    pair.first.getClassName());
             if (count > 1) {
                 out.print(" (");
                 out.print(count);
@@ -1846,12 +1768,18 @@
             out.println();
         }
 
+        @Override
+        protected IntentFilter getIntentFilter(
+                @NonNull Pair<ParsedProvider, ParsedIntentInfo> input) {
+            return input.second;
+        }
+
         private final ArrayMap<ComponentName, ParsedProvider> mProviders = new ArrayMap<>();
         private int mFlags;
     }
 
     private static final class ServiceIntentResolver
-            extends MimeGroupsAwareIntentResolver<ParsedServiceIntentInfo, ResolveInfo> {
+            extends MimeGroupsAwareIntentResolver<Pair<ParsedService, ParsedIntentInfo>, ResolveInfo> {
         @Override
         public List<ResolveInfo> queryIntent(Intent intent, String resolvedType,
                 boolean defaultOnly, int userId) {
@@ -1877,15 +1805,18 @@
             mFlags = flags;
             final boolean defaultOnly = (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0;
             final int servicesSize = packageServices.size();
-            ArrayList<ParsedServiceIntentInfo[]> listCut = new ArrayList<>(servicesSize);
+            ArrayList<Pair<ParsedService, ParsedIntentInfo>[]> listCut =
+                    new ArrayList<>(servicesSize);
 
-            List<ParsedServiceIntentInfo> intentFilters;
+            List<ParsedIntentInfo> intentFilters;
             for (int i = 0; i < servicesSize; ++i) {
-                intentFilters = packageServices.get(i).intents;
-                if (intentFilters != null && intentFilters.size() > 0) {
-                    ParsedServiceIntentInfo[] array =
-                            new ParsedServiceIntentInfo[intentFilters.size()];
-                    intentFilters.toArray(array);
+                ParsedService service = packageServices.get(i);
+                intentFilters = service.getIntents();
+                if (intentFilters.size() > 0) {
+                    Pair<ParsedService, ParsedIntentInfo>[] array = newArray(intentFilters.size());
+                    for (int arrayIndex = 0; arrayIndex < intentFilters.size(); arrayIndex++) {
+                        array[arrayIndex] = Pair.create(service, intentFilters.get(arrayIndex));
+                    }
                     listCut.add(array);
                 }
             }
@@ -1895,15 +1826,13 @@
         void addService(ParsedService s) {
             mServices.put(s.getComponentName(), s);
             if (DEBUG_SHOW_INFO) {
-                Log.v(TAG, "  "
-                        + (s.nonLocalizedLabel != null
-                        ? s.nonLocalizedLabel : s.getName()) + ":");
+                Log.v(TAG, "  service:");
                 Log.v(TAG, "    Class=" + s.getName());
             }
-            final int intentsSize = s.intents.size();
+            final int intentsSize = s.getIntents().size();
             int j;
             for (j = 0; j < intentsSize; j++) {
-                ParsedServiceIntentInfo intent = s.intents.get(j);
+                ParsedIntentInfo intent = s.getIntents().get(j);
                 if (DEBUG_SHOW_INFO) {
                     Log.v(TAG, "    IntentFilter:");
                     intent.dump(new LogPrinter(Log.VERBOSE, TAG), "      ");
@@ -1911,36 +1840,35 @@
                 if (!intent.debugCheck()) {
                     Log.w(TAG, "==> For Service " + s.getName());
                 }
-                addFilter(intent);
+                addFilter(Pair.create(s, intent));
             }
         }
 
         void removeService(ParsedService s) {
             mServices.remove(s.getComponentName());
             if (DEBUG_SHOW_INFO) {
-                Log.v(TAG, "  " + (s.nonLocalizedLabel != null
-                        ? s.nonLocalizedLabel : s.getName()) + ":");
+                Log.v(TAG, "  service:");
                 Log.v(TAG, "    Class=" + s.getName());
             }
-            final int intentsSize = s.intents.size();
+            final int intentsSize = s.getIntents().size();
             int j;
             for (j = 0; j < intentsSize; j++) {
-                ParsedServiceIntentInfo intent = s.intents.get(j);
+                ParsedIntentInfo intent = s.getIntents().get(j);
                 if (DEBUG_SHOW_INFO) {
                     Log.v(TAG, "    IntentFilter:");
                     intent.dump(new LogPrinter(Log.VERBOSE, TAG), "      ");
                 }
-                removeFilter(intent);
+                removeFilter(Pair.create(s, intent));
             }
         }
 
         @Override
-        protected boolean allowFilterResult(
-                ParsedServiceIntentInfo filter, List<ResolveInfo> dest) {
+        protected boolean allowFilterResult(Pair<ParsedService, ParsedIntentInfo> filter,
+                List<ResolveInfo> dest) {
             for (int i = dest.size() - 1; i >= 0; --i) {
                 ServiceInfo destAi = dest.get(i).serviceInfo;
-                if (Objects.equals(destAi.name, filter.getClassName())
-                        && Objects.equals(destAi.packageName, filter.getPackageName())) {
+                if (Objects.equals(destAi.name, filter.first.getClassName())
+                        && Objects.equals(destAi.packageName, filter.first.getPackageName())) {
                     return false;
                 }
             }
@@ -1948,55 +1876,32 @@
         }
 
         @Override
-        protected ParsedServiceIntentInfo[] newArray(int size) {
-            return new ParsedServiceIntentInfo[size];
+        protected Pair<ParsedService, ParsedIntentInfo>[] newArray(int size) {
+            //noinspection unchecked
+            return (Pair<ParsedService, ParsedIntentInfo>[]) new Pair<?, ?>[size];
         }
 
         @Override
-        protected boolean isFilterStopped(ParsedServiceIntentInfo filter, int userId) {
-            if (!sUserManager.exists(userId)) return true;
-
-            AndroidPackage pkg = sPackageManagerInternal.getPackage(filter.getPackageName());
-            if (pkg == null) {
-                return false;
-            }
-
-            PackageSetting ps = (PackageSetting) sPackageManagerInternal.getPackageSetting(
-                    filter.getPackageName());
-            if (ps == null) {
-                return false;
-            }
-
-            // System apps are never considered stopped for purposes of
-            // filtering, because there may be no way for the user to
-            // actually re-launch them.
-            return (ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0
-                    && ps.getStopped(userId);
+        protected boolean isFilterStopped(Pair<ParsedService, ParsedIntentInfo> filter, int userId) {
+            return ComponentResolver.isFilterStopped(filter, userId);
         }
 
         @Override
         protected boolean isPackageForFilter(String packageName,
-                ParsedServiceIntentInfo info) {
-            return packageName.equals(info.getPackageName());
+                Pair<ParsedService, ParsedIntentInfo> info) {
+            return packageName.equals(info.first.getPackageName());
         }
 
         @Override
-        protected ResolveInfo newResult(ParsedServiceIntentInfo filter,
-                int match, int userId) {
+        protected ResolveInfo newResult(Pair<ParsedService, ParsedIntentInfo> pair, int match,
+                int userId) {
             if (!sUserManager.exists(userId)) return null;
 
-            ParsedService service = null;
+            ParsedService service = pair.first;
+            ParsedIntentInfo filter = pair.second;
 
-            AndroidPackage pkg = sPackageManagerInternal.getPackage(filter.getPackageName());
-            if (pkg != null && pkg.getServices() != null) {
-                for (ParsedService parsedService : pkg.getServices()) {
-                    if (Objects.equals(parsedService.className, filter.getClassName())) {
-                        service = parsedService;
-                    }
-                }
-            }
-
-            if (service == null) {
+            AndroidPackage pkg = sPackageManagerInternal.getPackage(service.getPackageName());
+            if (pkg == null) {
                 return null;
             }
 
@@ -2005,13 +1910,13 @@
             }
 
             PackageSetting ps = (PackageSetting) sPackageManagerInternal.getPackageSetting(
-                    filter.getPackageName());
+                    service.getPackageName());
             if (ps == null) {
                 return null;
             }
             final PackageUserState userState = ps.readUserState(userId);
             ServiceInfo si = PackageInfoUtils.generateServiceInfo(pkg, service, mFlags,
-                    userState, userId);
+                    userState, userId, ps);
             if (si == null) {
                 return null;
             }
@@ -2038,12 +1943,13 @@
                 res.filter = filter;
             }
             res.priority = filter.getPriority();
-            res.preferredOrder = pkg.getPreferredOrder();
+            // TODO(b/135203078): This field was unwritten and does nothing
+//            res.preferredOrder = pkg.getPreferredOrder();
             res.match = match;
-            res.isDefault = filter.hasDefault;
-            res.labelRes = filter.labelRes;
-            res.nonLocalizedLabel = filter.nonLocalizedLabel;
-            res.icon = filter.icon;
+            res.isDefault = filter.isHasDefault();
+            res.labelRes = filter.getLabelRes();
+            res.nonLocalizedLabel = filter.getNonLocalizedLabel();
+            res.icon = filter.getIcon();
             res.system = res.serviceInfo.applicationInfo.isSystemApp();
             return res;
         }
@@ -2055,25 +1961,17 @@
 
         @Override
         protected void dumpFilter(PrintWriter out, String prefix,
-                ParsedServiceIntentInfo filter) {
-            ParsedService service = null;
-
-            AndroidPackage pkg = sPackageManagerInternal.getPackage(filter.getPackageName());
-            if (pkg != null && pkg.getServices() != null) {
-                for (ParsedService parsedService : pkg.getServices()) {
-                    if (Objects.equals(parsedService.className, filter.getClassName())) {
-                        service = parsedService;
-                    }
-                }
-            }
+                Pair<ParsedService, ParsedIntentInfo> pair) {
+            ParsedService service = pair.first;
+            ParsedIntentInfo filter = pair.second;
 
             out.print(prefix);
             out.print(Integer.toHexString(System.identityHashCode(service)));
             out.print(' ');
-            ComponentName.printShortString(out, filter.getPackageName(), filter.getClassName());
+            ComponentName.printShortString(out, service.getPackageName(), service.getClassName());
             out.print(" filter ");
             out.print(Integer.toHexString(System.identityHashCode(filter)));
-            if (service != null && service.getPermission() != null) {
+            if (service.getPermission() != null) {
                 out.print(" permission "); out.println(service.getPermission());
             } else {
                 out.println();
@@ -2081,22 +1979,30 @@
         }
 
         @Override
-        protected Object filterToLabel(ParsedServiceIntentInfo filter) {
+        protected Object filterToLabel(Pair<ParsedService, ParsedIntentInfo> filter) {
             return filter;
         }
 
         protected void dumpFilterLabel(PrintWriter out, String prefix, Object label, int count) {
-            final ParsedServiceIntentInfo service = (ParsedServiceIntentInfo) label;
+            @SuppressWarnings("unchecked") final Pair<ParsedService, ParsedIntentInfo> pair =
+                    (Pair<ParsedService, ParsedIntentInfo>) label;
             out.print(prefix);
-            out.print(Integer.toHexString(System.identityHashCode(service)));
+            out.print(Integer.toHexString(System.identityHashCode(pair.first)));
             out.print(' ');
-            ComponentName.printShortString(out, service.getPackageName(), service.getClassName());
+            ComponentName.printShortString(out, pair.first.getPackageName(),
+                    pair.first.getClassName());
             if (count > 1) {
                 out.print(" ("); out.print(count); out.print(" filters)");
             }
             out.println();
         }
 
+        @Override
+        protected IntentFilter getIntentFilter(
+                @NonNull Pair<ParsedService, ParsedIntentInfo> input) {
+            return input.second;
+        }
+
         // Keys are String (activity class name), values are Activity.
         private final ArrayMap<ComponentName, ParsedService> mServices = new ArrayMap<>();
         private int mFlags;
@@ -2183,11 +2089,40 @@
                 i--;
             }
         }
+
+        @Override
+        protected IntentFilter getIntentFilter(
+                @NonNull AuxiliaryResolveInfo.AuxiliaryFilter input) {
+            return input;
+        }
+    }
+
+    private static boolean isFilterStopped(Pair<? extends ParsedComponent, ParsedIntentInfo> pair,
+            int userId) {
+        if (!sUserManager.exists(userId)) {
+            return true;
+        }
+
+        AndroidPackage pkg = sPackageManagerInternal.getPackage(pair.first.getPackageName());
+        if (pkg == null) {
+            return false;
+        }
+
+        PackageSetting ps = (PackageSetting) sPackageManagerInternal.getPackageSetting(
+                pair.first.getPackageName());
+        if (ps == null) {
+            return false;
+        }
+
+        // System apps are never considered stopped for purposes of
+        // filtering, because there may be no way for the user to
+        // actually re-launch them.
+        return !ps.isSystem() && ps.getStopped(userId);
     }
 
     /** Generic to create an {@link Iterator} for a data type */
     static class IterGenerator<E> {
-        public Iterator<E> generate(ParsedActivityIntentInfo info) {
+        public Iterator<E> generate(ParsedIntentInfo info) {
             return null;
         }
     }
@@ -2195,7 +2130,7 @@
     /** Create an {@link Iterator} for intent actions */
     static class ActionIterGenerator extends IterGenerator<String> {
         @Override
-        public Iterator<String> generate(ParsedActivityIntentInfo info) {
+        public Iterator<String> generate(ParsedIntentInfo info) {
             return info.actionsIterator();
         }
     }
@@ -2203,7 +2138,7 @@
     /** Create an {@link Iterator} for intent categories */
     static class CategoriesIterGenerator extends IterGenerator<String> {
         @Override
-        public Iterator<String> generate(ParsedActivityIntentInfo info) {
+        public Iterator<String> generate(ParsedIntentInfo info) {
             return info.categoriesIterator();
         }
     }
@@ -2211,7 +2146,7 @@
     /** Create an {@link Iterator} for intent schemes */
     static class SchemesIterGenerator extends IterGenerator<String> {
         @Override
-        public Iterator<String> generate(ParsedActivityIntentInfo info) {
+        public Iterator<String> generate(ParsedIntentInfo info) {
             return info.schemesIterator();
         }
     }
@@ -2219,7 +2154,7 @@
     /** Create an {@link Iterator} for intent authorities */
     static class AuthoritiesIterGenerator extends IterGenerator<IntentFilter.AuthorityEntry> {
         @Override
-        public Iterator<IntentFilter.AuthorityEntry> generate(ParsedActivityIntentInfo info) {
+        public Iterator<IntentFilter.AuthorityEntry> generate(ParsedIntentInfo info) {
             return info.authoritiesIterator();
         }
     }
diff --git a/services/core/java/com/android/server/pm/CrossProfileIntentResolver.java b/services/core/java/com/android/server/pm/CrossProfileIntentResolver.java
index 0e0096d..8e6b89a 100644
--- a/services/core/java/com/android/server/pm/CrossProfileIntentResolver.java
+++ b/services/core/java/com/android/server/pm/CrossProfileIntentResolver.java
@@ -18,6 +18,9 @@
 package com.android.server.pm;
 
 
+import android.annotation.NonNull;
+import android.content.IntentFilter;
+
 import com.android.server.IntentResolver;
 import java.util.List;
 
@@ -40,4 +43,9 @@
     protected void sortResults(List<CrossProfileIntentFilter> results) {
         //We don't sort the results
     }
+
+    @Override
+    protected IntentFilter getIntentFilter(@NonNull CrossProfileIntentFilter input) {
+        return input;
+    }
 }
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index 8ad3e9d..f37af3a 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -234,11 +234,11 @@
     }
 
     public void moveCompleteApp(String fromUuid, String toUuid, String packageName,
-            String dataAppName, int appId, String seInfo, int targetSdkVersion,
+            int appId, String seInfo, int targetSdkVersion,
             String fromCodePath) throws InstallerException {
         if (!checkBeforeRemote()) return;
         try {
-            mInstalld.moveCompleteApp(fromUuid, toUuid, packageName, dataAppName, appId, seInfo,
+            mInstalld.moveCompleteApp(fromUuid, toUuid, packageName, appId, seInfo,
                     targetSdkVersion, fromCodePath);
         } catch (Exception e) {
             throw InstallerException.from(e);
diff --git a/services/core/java/com/android/server/pm/InstantAppRegistry.java b/services/core/java/com/android/server/pm/InstantAppRegistry.java
index bcfe577..cf85b0f 100644
--- a/services/core/java/com/android/server/pm/InstantAppRegistry.java
+++ b/services/core/java/com/android/server/pm/InstantAppRegistry.java
@@ -24,8 +24,6 @@
 import android.content.pm.InstantAppInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageParser;
-import android.content.pm.parsing.AndroidPackage;
-import android.content.pm.parsing.PackageInfoUtils;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.graphics.Canvas;
@@ -52,6 +50,8 @@
 import com.android.internal.os.SomeArgs;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.XmlUtils;
+import com.android.server.pm.parsing.PackageInfoUtils;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
 
 import libcore.io.IoUtils;
 import libcore.util.HexEncoding;
@@ -694,12 +694,13 @@
             final int packageCount = mService.mPackages.size();
             for (int i = 0; i < packageCount; i++) {
                 final AndroidPackage pkg = mService.mPackages.valueAt(i);
-                if (now - pkg.getLatestPackageUseTimeInMills() < maxInstalledCacheDuration) {
+                final PackageSetting ps = mService.getPackageSetting(pkg.getPackageName());
+                if (ps == null) {
                     continue;
                 }
 
-                final PackageSetting ps = mService.getPackageSetting(pkg.getPackageName());
-                if (ps == null) {
+                if (now - ps.getPkgState().getLatestPackageUseTimeInMills()
+                        < maxInstalledCacheDuration) {
                     continue;
                 }
 
@@ -733,30 +734,28 @@
                     } else if (rhsPkg == null) {
                         return 1;
                     } else {
-                        if (lhsPkg.getLatestPackageUseTimeInMills() >
-                                rhsPkg.getLatestPackageUseTimeInMills()) {
+                        final PackageSetting lhsPs = mService.getPackageSetting(
+                                lhsPkg.getPackageName());
+                        if (lhsPs == null) {
+                            return 0;
+                        }
+
+                        final PackageSetting rhsPs = mService.getPackageSetting(
+                                rhsPkg.getPackageName());
+                        if (rhsPs == null) {
+                            return 0;
+                        }
+
+                        if (lhsPs.getPkgState().getLatestPackageUseTimeInMills() >
+                                rhsPs.getPkgState().getLatestPackageUseTimeInMills()) {
                             return 1;
-                        } else if (lhsPkg.getLatestPackageUseTimeInMills() <
-                                rhsPkg.getLatestPackageUseTimeInMills()) {
+                        } else if (lhsPs.getPkgState().getLatestPackageUseTimeInMills() <
+                                rhsPs.getPkgState().getLatestPackageUseTimeInMills()) {
                             return -1;
+                        } else if (lhsPs.firstInstallTime > rhsPs.firstInstallTime) {
+                            return 1;
                         } else {
-                            final PackageSetting lhsPs = mService.getPackageSetting(
-                                    lhsPkg.getPackageName());
-                            if (lhsPs == null) {
-                                return 0;
-                            }
-
-                            final PackageSetting rhsPs = mService.getPackageSetting(
-                                    rhsPkg.getPackageName());
-                            if (rhsPs == null) {
-                                return 0;
-                            }
-
-                            if (lhsPs.firstInstallTime > rhsPs.firstInstallTime) {
-                                return 1;
-                            } else {
-                                return -1;
-                            }
+                            return -1;
                         }
                     }
                 });
@@ -869,10 +868,9 @@
         // TODO(b/135203078): This may be broken due to inner mutability problems that were broken
         //  as part of moving to PackageInfoUtils. Flags couldn't be determined.
         ApplicationInfo appInfo = PackageInfoUtils.generateApplicationInfo(ps.pkg, 0,
-                ps.readUserState(userId), userId);
+                ps.readUserState(userId), userId, ps);
         if (addApplicationInfo) {
-            return new InstantAppInfo(appInfo,
-                    requestedPermissions, grantedPermissions);
+            return new InstantAppInfo(appInfo, requestedPermissions, grantedPermissions);
         } else {
             return new InstantAppInfo(appInfo.packageName,
                     appInfo.loadLabel(mService.mContext.getPackageManager()),
diff --git a/services/core/java/com/android/server/pm/InstructionSets.java b/services/core/java/com/android/server/pm/InstructionSets.java
index 0a065eb..2d42107 100644
--- a/services/core/java/com/android/server/pm/InstructionSets.java
+++ b/services/core/java/com/android/server/pm/InstructionSets.java
@@ -16,12 +16,14 @@
 
 package com.android.server.pm;
 
-import android.content.pm.parsing.AndroidPackage;
 import android.os.Build;
 import android.os.SystemProperties;
 import android.text.TextUtils;
 import android.util.ArraySet;
 
+import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
+
 import dalvik.system.VMRuntime;
 
 import java.util.ArrayList;
@@ -109,13 +111,4 @@
 
         return VMRuntime.getInstructionSet(abis.primary);
     }
-
-    public static String getPrimaryInstructionSet(AndroidPackage pkg) {
-        if (pkg.getPrimaryCpuAbi() == null) {
-            return getPreferredInstructionSet();
-        }
-
-        return VMRuntime.getInstructionSet(pkg.getPrimaryCpuAbi());
-    }
-
 }
diff --git a/services/core/java/com/android/server/pm/IntentFilterVerificationState.java b/services/core/java/com/android/server/pm/IntentFilterVerificationState.java
index c97d85d..9dc545a 100644
--- a/services/core/java/com/android/server/pm/IntentFilterVerificationState.java
+++ b/services/core/java/com/android/server/pm/IntentFilterVerificationState.java
@@ -17,7 +17,7 @@
 package com.android.server.pm;
 
 import android.content.pm.PackageManager;
-import android.content.pm.parsing.ComponentParseUtils;
+import android.content.pm.parsing.component.ParsedIntentInfo;
 import android.util.ArraySet;
 import android.util.Slog;
 
@@ -35,7 +35,7 @@
 
     private int mState;
 
-    private ArrayList<ComponentParseUtils.ParsedActivityIntentInfo> mFilters = new ArrayList<>();
+    private ArrayList<ParsedIntentInfo> mFilters = new ArrayList<>();
     private ArraySet<String> mHosts = new ArraySet<>();
     private int mUserId;
 
@@ -66,7 +66,7 @@
         setState(STATE_VERIFICATION_PENDING);
     }
 
-    public ArrayList<ComponentParseUtils.ParsedActivityIntentInfo> getFilters() {
+    public ArrayList<ParsedIntentInfo> getFilters() {
         return mFilters;
     }
 
@@ -123,7 +123,7 @@
         return false;
     }
 
-    public void addFilter(ComponentParseUtils.ParsedActivityIntentInfo filter) {
+    public void addFilter(ParsedIntentInfo filter) {
         mFilters.add(filter);
         mHosts.addAll(filter.getHostsList());
     }
diff --git a/services/core/java/com/android/server/pm/KeySetManagerService.java b/services/core/java/com/android/server/pm/KeySetManagerService.java
index f9cfee1..dabcc35 100644
--- a/services/core/java/com/android/server/pm/KeySetManagerService.java
+++ b/services/core/java/com/android/server/pm/KeySetManagerService.java
@@ -21,14 +21,13 @@
 import static com.android.server.pm.PackageManagerService.SCAN_INITIAL;
 
 import android.content.pm.PackageParser;
-import android.content.pm.parsing.AndroidPackage;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.Base64;
 import android.util.LongSparseArray;
 import android.util.Slog;
 
-import com.android.internal.util.Preconditions;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index 09e3feb..8031eaa 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -50,7 +50,6 @@
 import android.content.pm.ShortcutServiceInternal;
 import android.content.pm.ShortcutServiceInternal.ShortcutChangeListener;
 import android.content.pm.UserInfo;
-import android.content.pm.parsing.AndroidPackage;
 import android.graphics.Rect;
 import android.net.Uri;
 import android.os.Binder;
@@ -73,8 +72,10 @@
 import com.android.internal.content.PackageMonitor;
 import com.android.internal.os.BackgroundThread;
 import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.CollectionUtils;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.wm.ActivityTaskManagerInternal;
 
 import java.util.ArrayList;
@@ -134,6 +135,8 @@
 
         private final MyPackageMonitor mPackageMonitor = new MyPackageMonitor();
 
+        private final ShortcutChangeHandler mShortcutChangeHandler;
+
         private final Handler mCallbackHandler;
 
         private PackageInstallerService mPackageInstallerService;
@@ -153,6 +156,8 @@
             mShortcutServiceInternal = Objects.requireNonNull(
                     LocalServices.getService(ShortcutServiceInternal.class));
             mShortcutServiceInternal.addListener(mPackageMonitor);
+            mShortcutChangeHandler = new ShortcutChangeHandler(mUserManagerInternal);
+            mShortcutServiceInternal.addShortcutChangeCallback(mShortcutChangeHandler);
             mCallbackHandler = BackgroundThread.getHandler();
             mDpm = (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
         }
@@ -720,12 +725,37 @@
         @Override
         public void registerShortcutChangeCallback(String callingPackage, long changedSince,
                 String packageName, List shortcutIds, List<LocusId> locusIds,
-                ComponentName componentName, int flags, IShortcutChangeCallback callback,
-                int callbackId) {
+                ComponentName componentName, int flags, IShortcutChangeCallback callback) {
+            ensureShortcutPermission(callingPackage);
+
+            if (shortcutIds != null && packageName == null) {
+                throw new IllegalArgumentException(
+                        "To query by shortcut ID, package name must also be set");
+            }
+            if (locusIds != null && packageName == null) {
+                throw new IllegalArgumentException(
+                        "To query by locus ID, package name must also be set");
+            }
+
+            UserHandle user = UserHandle.of(injectCallingUserId());
+            if (mContext.checkCallingOrSelfPermission(
+                    android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
+                    == PackageManager.PERMISSION_GRANTED) {
+                user = null;
+            }
+
+            // TODO: When ShortcutQueryWrapper (ag/10323729) is available, pass that directly.
+            ShortcutChangeHandler.QueryInfo query = new ShortcutChangeHandler.QueryInfo(
+                    changedSince, packageName, shortcutIds, locusIds, componentName, flags, user);
+            mShortcutChangeHandler.addShortcutChangeCallback(callback, query);
         }
 
         @Override
-        public void unregisterShortcutChangeCallback(String callingPackage, int callbackId) {
+        public void unregisterShortcutChangeCallback(String callingPackage,
+                IShortcutChangeCallback callback) {
+            ensureShortcutPermission(callingPackage);
+
+            mShortcutChangeHandler.removeShortcutChangeCallback(callback);
         }
 
         @Override
@@ -1005,6 +1035,153 @@
             mCallbackHandler.post(r);
         }
 
+        public static class ShortcutChangeHandler implements LauncherApps.ShortcutChangeCallback {
+
+            static class QueryInfo {
+                final long mChangedSince;
+                final String mPackage;
+                final List<String> mShortcutIds;
+                final List<LocusId> mLocusIds;
+                final ComponentName mActivity;
+                final int mQueryFlags;
+                final UserHandle mCallbackUser;
+
+                QueryInfo(long changedSince, String packageName, List<String> shortcutIds,
+                        List<LocusId> locusIds, ComponentName activity, int flags,
+                        UserHandle callbackUser) {
+                    mChangedSince = changedSince;
+                    mPackage = packageName;
+                    mShortcutIds = shortcutIds;
+                    mLocusIds = locusIds;
+                    mActivity = activity;
+                    mQueryFlags = flags;
+                    mCallbackUser = callbackUser;
+                }
+            }
+
+            private final UserManagerInternal mUserManagerInternal;
+
+            ShortcutChangeHandler(UserManagerInternal userManager) {
+                mUserManagerInternal = userManager;
+            }
+
+            private final RemoteCallbackList<IShortcutChangeCallback> mCallbacks =
+                    new RemoteCallbackList<>();
+
+            public synchronized void addShortcutChangeCallback(IShortcutChangeCallback callback,
+                    QueryInfo query) {
+                mCallbacks.unregister(callback);
+                mCallbacks.register(callback, query);
+            }
+
+            public synchronized void removeShortcutChangeCallback(
+                    IShortcutChangeCallback callback) {
+                mCallbacks.unregister(callback);
+            }
+
+            @Override
+            public void onShortcutsAddedOrUpdated(String packageName, List<ShortcutInfo> shortcuts,
+                    UserHandle user) {
+                onShortcutEvent(packageName, shortcuts, user, false);
+            }
+
+            @Override
+            public void onShortcutsRemoved(String packageName, List<ShortcutInfo> shortcuts,
+                    UserHandle user) {
+                onShortcutEvent(packageName, shortcuts, user, true);
+            }
+
+            private void onShortcutEvent(String packageName,
+                    List<ShortcutInfo> shortcuts, UserHandle user, boolean shortcutsRemoved) {
+                int count = mCallbacks.beginBroadcast();
+
+                for (int i = 0; i < count; i++) {
+                    final IShortcutChangeCallback callback = mCallbacks.getBroadcastItem(i);
+                    final QueryInfo query = (QueryInfo) mCallbacks.getBroadcastCookie(i);
+
+                    if (query.mCallbackUser != null && !hasUserAccess(query.mCallbackUser, user)) {
+                        // Callback owner does not have access to the shortcuts' user.
+                        continue;
+                    }
+
+                    // Filter the list by query, if any matches exists, send via callback.
+                    List<ShortcutInfo> matchedList =
+                            filterShortcutsByQuery(packageName, shortcuts, query);
+                    if (!CollectionUtils.isEmpty(matchedList)) {
+                        try {
+                            if (shortcutsRemoved) {
+                                callback.onShortcutsRemoved(packageName, matchedList, user);
+                            } else {
+                                callback.onShortcutsAddedOrUpdated(packageName, matchedList, user);
+                            }
+                        } catch (RemoteException e) {
+                            // The RemoteCallbackList will take care of removing the dead object.
+                        }
+                    }
+                }
+
+                mCallbacks.finishBroadcast();
+            }
+
+            public static List<ShortcutInfo> filterShortcutsByQuery(String packageName,
+                    List<ShortcutInfo> shortcuts, QueryInfo query) {
+                if (query.mPackage != null && query.mPackage != packageName) {
+                    return null;
+                }
+
+                List<ShortcutInfo> matches = new ArrayList<>();
+
+                final boolean matchDynamic =
+                        (query.mQueryFlags & ShortcutQuery.FLAG_MATCH_DYNAMIC) != 0;
+                final boolean matchPinned =
+                        (query.mQueryFlags & ShortcutQuery.FLAG_MATCH_PINNED) != 0;
+                final boolean matchManifest =
+                        (query.mQueryFlags & ShortcutQuery.FLAG_MATCH_MANIFEST) != 0;
+                final boolean matchCached =
+                        (query.mQueryFlags & ShortcutQuery.FLAG_MATCH_CACHED) != 0;
+                final int shortcutFlags = (matchDynamic ? ShortcutInfo.FLAG_DYNAMIC : 0)
+                        | (matchPinned ? ShortcutInfo.FLAG_PINNED : 0)
+                        | (matchManifest ? ShortcutInfo.FLAG_MANIFEST : 0)
+                        | (matchCached ? ShortcutInfo.FLAG_CACHED : 0);
+
+                for (int i = 0; i < shortcuts.size(); i++) {
+                    final ShortcutInfo si = shortcuts.get(i);
+
+                    if (query.mActivity != null && !query.mActivity.equals(si.getActivity())) {
+                        continue;
+                    }
+
+                    if (query.mChangedSince != 0
+                            && query.mChangedSince > si.getLastChangedTimestamp()) {
+                        continue;
+                    }
+
+                    if (query.mShortcutIds != null && !query.mShortcutIds.contains(si.getId())) {
+                        continue;
+                    }
+
+                    if (query.mLocusIds != null && !query.mLocusIds.contains(si.getLocusId())) {
+                        continue;
+                    }
+
+                    if ((shortcutFlags & si.getFlags()) != 0) {
+                        matches.add(si);
+                    }
+                }
+
+                return matches;
+            }
+
+            private boolean hasUserAccess(UserHandle callbackUser, UserHandle shortcutUser) {
+                final int callbackUserId = callbackUser.getIdentifier();
+                final int shortcutUserId = shortcutUser.getIdentifier();
+
+                if (shortcutUser == callbackUser) return true;
+                return mUserManagerInternal.isProfileAccessible(callbackUserId, shortcutUserId,
+                        null, false);
+            }
+        }
+
         private class MyPackageMonitor extends PackageMonitor implements ShortcutChangeListener {
 
             // TODO Simplify with lambdas.
diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java
index ae7a4a7..2df4a92 100644
--- a/services/core/java/com/android/server/pm/OtaDexoptService.java
+++ b/services/core/java/com/android/server/pm/OtaDexoptService.java
@@ -22,7 +22,6 @@
 import android.annotation.Nullable;
 import android.content.Context;
 import android.content.pm.IOtaDexopt;
-import android.content.pm.parsing.AndroidPackage;
 import android.os.Environment;
 import android.os.RemoteException;
 import android.os.ResultReceiver;
@@ -35,13 +34,17 @@
 import com.android.internal.logging.MetricsLogger;
 import com.android.server.pm.Installer.InstallerException;
 import com.android.server.pm.dex.DexoptOptions;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
 
 import java.io.File;
 import java.io.FileDescriptor;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.concurrent.TimeUnit;
 
 /**
@@ -118,31 +121,33 @@
         if (mDexoptCommands != null) {
             throw new IllegalStateException("already called prepare()");
         }
-        final List<AndroidPackage> important;
-        final List<AndroidPackage> others;
+        final List<PackageSetting> important;
+        final List<PackageSetting> others;
         synchronized (mPackageManagerService.mLock) {
             // Important: the packages we need to run with ab-ota compiler-reason.
             important = PackageManagerServiceUtils.getPackagesForDexopt(
-                    mPackageManagerService.mPackages.values(), mPackageManagerService,
+                    mPackageManagerService.mSettings.mPackages.values(), mPackageManagerService,
                     DEBUG_DEXOPT);
             // Others: we should optimize this with the (first-)boot compiler-reason.
-            others = new ArrayList<>(mPackageManagerService.mPackages.values());
+            others = new ArrayList<>(mPackageManagerService.mSettings.mPackages.values());
             others.removeAll(important);
+            others.removeIf(PackageManagerServiceUtils.REMOVE_IF_NULL_PKG);
 
             // Pre-size the array list by over-allocating by a factor of 1.5.
             mDexoptCommands = new ArrayList<>(3 * mPackageManagerService.mPackages.size() / 2);
         }
 
-        for (AndroidPackage p : important) {
-            mDexoptCommands.addAll(generatePackageDexopts(p, PackageManagerService.REASON_AB_OTA));
+        for (PackageSetting pkgSetting : important) {
+            mDexoptCommands.addAll(generatePackageDexopts(pkgSetting.pkg, pkgSetting,
+                    PackageManagerService.REASON_AB_OTA));
         }
-        for (AndroidPackage p : others) {
+        for (PackageSetting pkgSetting : others) {
             // We assume here that there are no core apps left.
-            if (p.isCoreApp()) {
+            if (pkgSetting.pkg.isCoreApp()) {
                 throw new IllegalStateException("Found a core app that's not important");
             }
-            mDexoptCommands.addAll(
-                    generatePackageDexopts(p, PackageManagerService.REASON_FIRST_BOOT));
+            mDexoptCommands.addAll(generatePackageDexopts(pkgSetting.pkg, pkgSetting,
+                            PackageManagerService.REASON_FIRST_BOOT));
         }
         completeSize = mDexoptCommands.size();
 
@@ -150,8 +155,8 @@
         if (spaceAvailable < BULK_DELETE_THRESHOLD) {
             Log.i(TAG, "Low on space, deleting oat files in an attempt to free up space: "
                     + PackageManagerServiceUtils.packagesToString(others));
-            for (AndroidPackage pkg : others) {
-                mPackageManagerService.deleteOatArtifactsOfPackage(pkg.getPackageName());
+            for (PackageSetting pkg : others) {
+                mPackageManagerService.deleteOatArtifactsOfPackage(pkg.name);
             }
         }
         long spaceAvailableNow = getAvailableSpace();
@@ -161,16 +166,18 @@
         if (DEBUG_DEXOPT) {
             try {
                 // Output some data about the packages.
-                AndroidPackage lastUsed = Collections.max(important,
-                        (pkg1, pkg2) -> Long.compare(
-                                pkg1.getLatestForegroundPackageUseTimeInMills(),
-                                pkg2.getLatestForegroundPackageUseTimeInMills()));
+                PackageSetting lastUsed = Collections.max(important,
+                        (pkgSetting1, pkgSetting2) -> Long.compare(
+                                pkgSetting1.getPkgState()
+                                        .getLatestForegroundPackageUseTimeInMills(),
+                                pkgSetting2.getPkgState()
+                                        .getLatestForegroundPackageUseTimeInMills()));
                 Log.d(TAG, "A/B OTA: lastUsed time = "
-                        + lastUsed.getLatestForegroundPackageUseTimeInMills());
+                        + lastUsed.getPkgState().getLatestForegroundPackageUseTimeInMills());
                 Log.d(TAG, "A/B OTA: deprioritized packages:");
-                for (AndroidPackage pkg : others) {
-                    Log.d(TAG, "  " + pkg.getPackageName() + " - "
-                            + pkg.getLatestForegroundPackageUseTimeInMills());
+                for (PackageSetting pkgSetting : others) {
+                    Log.d(TAG, "  " + pkgSetting.name + " - "
+                            + pkgSetting.getPkgState().getLatestForegroundPackageUseTimeInMills());
                 }
             } catch (Exception ignored) {
             }
@@ -263,7 +270,7 @@
      * Generate all dexopt commands for the given package.
      */
     private synchronized List<String> generatePackageDexopts(AndroidPackage pkg,
-            int compilationReason) {
+            PackageSetting pkgSetting, int compilationReason) {
         // Intercept and collect dexopt requests
         final List<String> commands = new ArrayList<String>();
         final Installer collectingInstaller = new Installer(mContext, true) {
@@ -333,7 +340,7 @@
         PackageDexOptimizer optimizer = new OTADexoptPackageDexOptimizer(
                 collectingInstaller, mPackageManagerService.mInstallLock, mContext);
 
-        optimizer.performDexOpt(pkg,
+        optimizer.performDexOpt(pkg, pkgSetting,
                 null /* ISAs */,
                 null /* CompilerStats.PackageStats */,
                 mPackageManagerService.getDexManager().getPackageUseInfoOrDefault(
@@ -386,9 +393,12 @@
                 continue;
             }
 
-            final String[] instructionSets = getAppDexInstructionSets(pkg.getPrimaryCpuAbi(),
-                    pkg.getSecondaryCpuAbi());
-            final List<String> paths = pkg.getAllCodePathsExcludingResourceOnly();
+            PackageSetting pkgSetting = mPackageManagerService.getPackageSetting(pkg.getPackageName());
+            final String[] instructionSets = getAppDexInstructionSets(
+                    AndroidPackageUtils.getPrimaryCpuAbi(pkg, pkgSetting),
+                    AndroidPackageUtils.getSecondaryCpuAbi(pkg, pkgSetting));
+            final List<String> paths =
+                    AndroidPackageUtils.getAllCodePathsExcludingResourceOnly(pkg);
             final String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
             for (String dexCodeInstructionSet : dexCodeInstructionSets) {
                 for (String path : paths) {
diff --git a/services/core/java/com/android/server/pm/PackageAbiHelper.java b/services/core/java/com/android/server/pm/PackageAbiHelper.java
index d7c161c..e355bb9 100644
--- a/services/core/java/com/android/server/pm/PackageAbiHelper.java
+++ b/services/core/java/com/android/server/pm/PackageAbiHelper.java
@@ -17,11 +17,12 @@
 package com.android.server.pm;
 
 import android.annotation.Nullable;
-import android.content.pm.parsing.AndroidPackage;
-import android.content.pm.parsing.ParsedPackage;
 import android.util.Pair;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
+import com.android.server.pm.parsing.pkg.ParsedPackage;
 
 import java.io.File;
 import java.util.Set;
@@ -33,7 +34,8 @@
      * Derive and get the location of native libraries for the given package,
      * which varies depending on where and how the package was installed.
      */
-    NativeLibraryPaths getNativeLibraryPaths(AndroidPackage pkg, File appLib32InstallDir);
+    NativeLibraryPaths getNativeLibraryPaths(AndroidPackage pkg, PackageSetting pkgSetting,
+            File appLib32InstallDir);
 
     /**
      * Calculate the abis for a bundled app. These can uniquely be determined from the contents of
@@ -48,9 +50,8 @@
      *
      * If {@code extractLibs} is true, native libraries are extracted from the app if required.
      */
-    Pair<Abis, NativeLibraryPaths> derivePackageAbi(
-            AndroidPackage pkg, String cpuAbiOverride, boolean extractLibs)
-            throws PackageManagerException;
+    Pair<Abis, NativeLibraryPaths> derivePackageAbi(AndroidPackage pkg, boolean isUpdatedSystemApp,
+            String cpuAbiOverride, boolean extractLibs) throws PackageManagerException;
 
     /**
      * Calculates adjusted ABIs for a set of packages belonging to a shared user so that they all
@@ -113,8 +114,9 @@
             this.secondary = secondary;
         }
 
-        Abis(AndroidPackage pkg) {
-            this(pkg.getPrimaryCpuAbi(), pkg.getSecondaryCpuAbi());
+        Abis(AndroidPackage pkg, PackageSetting pkgSetting)  {
+            this(AndroidPackageUtils.getPrimaryCpuAbi(pkg, pkgSetting),
+                    AndroidPackageUtils.getSecondaryCpuAbi(pkg, pkgSetting));
         }
 
         public void applyTo(ParsedPackage pkg) {
diff --git a/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java b/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java
index 482fc49..0bd8b28 100644
--- a/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java
+++ b/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java
@@ -27,9 +27,7 @@
 import static com.android.server.pm.InstructionSets.getPrimaryInstructionSet;
 
 import android.annotation.Nullable;
-import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
-import android.content.pm.parsing.AndroidPackage;
 import android.os.Build;
 import android.os.Environment;
 import android.os.FileUtils;
@@ -40,6 +38,8 @@
 
 import com.android.internal.content.NativeLibraryHelper;
 import com.android.internal.util.ArrayUtils;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
 
 import dalvik.system.VMRuntime;
 
@@ -131,11 +131,11 @@
     }
 
     @Override
-    public NativeLibraryPaths getNativeLibraryPaths(
-            AndroidPackage pkg, File appLib32InstallDir) {
-        return getNativeLibraryPaths(new Abis(pkg), appLib32InstallDir, pkg.getCodePath(),
-                pkg.getBaseCodePath(), pkg.isSystemApp(),
-                pkg.isUpdatedSystemApp());
+    public NativeLibraryPaths getNativeLibraryPaths(AndroidPackage pkg, PackageSetting pkgSetting,
+            File appLib32InstallDir) {
+        return getNativeLibraryPaths(new Abis(pkg, pkgSetting), appLib32InstallDir,
+                pkg.getCodePath(), pkg.getBaseCodePath(), pkg.isSystem(),
+                pkgSetting.getPkgState().isUpdatedSystemApp());
     }
 
     private static NativeLibraryPaths getNativeLibraryPaths(final Abis abis,
@@ -273,7 +273,7 @@
             // ABI that's higher on the list, i.e, a device that's configured to prefer
             // 64 bit apps will see a 64 bit primary ABI,
 
-            if ((pkg.getFlags() & ApplicationInfo.FLAG_MULTIARCH) == 0) {
+            if (!pkg.isMultiArch()) {
                 Slog.e(PackageManagerService.TAG,
                         "Package " + pkg + " has multiple bundled libs, but is not multiarch.");
             }
@@ -293,18 +293,21 @@
     }
 
     @Override
-    public Pair<Abis, NativeLibraryPaths> derivePackageAbi(
-            AndroidPackage pkg, String cpuAbiOverride, boolean extractLibs)
+    public Pair<Abis, NativeLibraryPaths> derivePackageAbi(AndroidPackage pkg,
+            boolean isUpdatedSystemApp, String cpuAbiOverride, boolean extractLibs)
             throws PackageManagerException {
         // Give ourselves some initial paths; we'll come back for another
         // pass once we've determined ABI below.
-        final NativeLibraryPaths initialLibraryPaths = getNativeLibraryPaths(new Abis(pkg),
+        String pkgRawPrimaryCpuAbi = AndroidPackageUtils.getRawPrimaryCpuAbi(pkg);
+        String pkgRawSecondaryCpuAbi = AndroidPackageUtils.getRawSecondaryCpuAbi(pkg);
+        final NativeLibraryPaths initialLibraryPaths = getNativeLibraryPaths(
+                new Abis(pkgRawPrimaryCpuAbi, pkgRawSecondaryCpuAbi),
                 PackageManagerService.sAppLib32InstallDir, pkg.getCodePath(),
-                pkg.getBaseCodePath(), pkg.isSystemApp(),
-                pkg.isUpdatedSystemApp());
+                pkg.getBaseCodePath(), pkg.isSystem(),
+                isUpdatedSystemApp);
 
         // We shouldn't attempt to extract libs from system app when it was not updated.
-        if (PackageManagerService.isSystemApp(pkg) && !pkg.isUpdatedSystemApp()) {
+        if (pkg.isSystem() && !isUpdatedSystemApp) {
             extractLibs = false;
         }
 
@@ -317,7 +320,7 @@
 
         NativeLibraryHelper.Handle handle = null;
         try {
-            handle = NativeLibraryHelper.Handle.create(pkg);
+            handle = AndroidPackageUtils.createNativeLibraryHandle(pkg);
             // TODO(multiArch): This can be null for apps that didn't go through the
             // usual installation process. We can calculate it again, like we
             // do during install time.
@@ -329,17 +332,7 @@
             // Null out the abis so that they can be recalculated.
             primaryCpuAbi = null;
             secondaryCpuAbi = null;
-            if ((pkg.getFlags() & ApplicationInfo.FLAG_MULTIARCH) != 0) {
-                // Warn if we've set an abiOverride for multi-lib packages..
-                // By definition, we need to copy both 32 and 64 bit libraries for
-                // such packages.
-                if (pkg.getCpuAbiOverride() != null
-                        && !NativeLibraryHelper.CLEAR_ABI_OVERRIDE.equals(
-                        pkg.getCpuAbiOverride())) {
-                    Slog.w(PackageManagerService.TAG,
-                            "Ignoring abiOverride for multi arch application.");
-                }
-
+            if (pkg.isMultiArch()) {
                 int abi32 = PackageManager.NO_NATIVE_LIBRARIES;
                 int abi64 = PackageManager.NO_NATIVE_LIBRARIES;
                 if (Build.SUPPORTED_32_BIT_ABIS.length > 0) {
@@ -357,7 +350,7 @@
                 }
 
                 // Shared library native code should be in the APK zip aligned
-                if (abi32 >= 0 && pkg.isLibrary() && extractLibs) {
+                if (abi32 >= 0 && AndroidPackageUtils.isLibrary(pkg) && extractLibs) {
                     throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
                             "Shared library native lib extraction not supported");
                 }
@@ -384,7 +377,7 @@
 
                 if (abi64 >= 0) {
                     // Shared library native libs should be in the APK zip aligned
-                    if (extractLibs && pkg.isLibrary()) {
+                    if (extractLibs && AndroidPackageUtils.isLibrary(pkg)) {
                         throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
                                 "Shared library native lib extraction not supported");
                     }
@@ -437,7 +430,7 @@
 
                 if (copyRet >= 0) {
                     // Shared libraries that have native libs must be multi-architecture
-                    if (pkg.isLibrary()) {
+                    if (AndroidPackageUtils.isLibrary(pkg)) {
                         throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
                                 "Shared library with native libs must be multiarch");
                     }
@@ -461,9 +454,8 @@
         final Abis abis = new Abis(primaryCpuAbi, secondaryCpuAbi);
         return new Pair<>(abis,
                 getNativeLibraryPaths(abis, PackageManagerService.sAppLib32InstallDir,
-                        pkg.getCodePath(), pkg.getBaseCodePath(),
-                        pkg.isSystemApp(),
-                        pkg.isUpdatedSystemApp()));
+                        pkg.getCodePath(), pkg.getBaseCodePath(), pkg.isSystem(),
+                        isUpdatedSystemApp));
     }
 
     /**
@@ -484,9 +476,11 @@
     public String getAdjustedAbiForSharedUser(
             Set<PackageSetting> packagesForUser, AndroidPackage scannedPackage) {
         String requiredInstructionSet = null;
-        if (scannedPackage != null && scannedPackage.getPrimaryCpuAbi() != null) {
-            requiredInstructionSet = VMRuntime.getInstructionSet(
-                    scannedPackage.getPrimaryCpuAbi());
+        if (scannedPackage != null) {
+            String pkgRawPrimaryCpuAbi = AndroidPackageUtils.getRawPrimaryCpuAbi(scannedPackage);
+            if (pkgRawPrimaryCpuAbi != null) {
+                requiredInstructionSet = VMRuntime.getInstructionSet(pkgRawPrimaryCpuAbi);
+            }
         }
 
         PackageSetting requirer = null;
@@ -533,7 +527,7 @@
         } else {
             // requirer == null implies that we're updating all ABIs in the set to
             // match scannedPackage.
-            adjustedAbi = scannedPackage.getPrimaryCpuAbi();
+            adjustedAbi = AndroidPackageUtils.getRawPrimaryCpuAbi(scannedPackage);
         }
         return adjustedAbi;
     }
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index 2b42221..e625aef 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -38,13 +38,13 @@
 import static dalvik.system.DexFile.getSafeModeCompilerFilter;
 import static dalvik.system.DexFile.isProfileGuidedCompilerFilter;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.SharedLibraryInfo;
 import android.content.pm.dex.ArtManager;
 import android.content.pm.dex.DexMetadataHelper;
-import android.content.pm.parsing.AndroidPackage;
 import android.os.FileUtils;
 import android.os.PowerManager;
 import android.os.SystemClock;
@@ -63,6 +63,8 @@
 import com.android.server.pm.dex.DexoptOptions;
 import com.android.server.pm.dex.DexoptUtils;
 import com.android.server.pm.dex.PackageDexUsage;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
 
 import dalvik.system.DexFile;
 
@@ -112,7 +114,7 @@
 
     static boolean canOptimizePackage(AndroidPackage pkg) {
         // We do not dexopt a package with no code.
-        if ((pkg.getFlags() & ApplicationInfo.FLAG_HAS_CODE) == 0) {
+        if (!pkg.isHasCode()) {
             return false;
         }
 
@@ -126,7 +128,7 @@
      * <p>Calls to {@link com.android.server.pm.Installer#dexopt} on {@link #mInstaller} are
      * synchronized on {@link #mInstallLock}.
      */
-    int performDexOpt(AndroidPackage pkg,
+    int performDexOpt(AndroidPackage pkg, @NonNull PackageSetting pkgSetting,
             String[] instructionSets, CompilerStats.PackageStats packageStats,
             PackageDexUsage.PackageUseInfo packageUseInfo, DexoptOptions options) {
         if (pkg.getUid() == -1) {
@@ -139,7 +141,7 @@
         synchronized (mInstallLock) {
             final long acquireTime = acquireWakeLockLI(pkg.getUid());
             try {
-                return performDexOptLI(pkg, instructionSets,
+                return performDexOptLI(pkg, pkgSetting, instructionSets,
                         packageStats, packageUseInfo, options);
             } finally {
                 releaseWakeLockLI(acquireTime);
@@ -152,19 +154,21 @@
      * It assumes the install lock is held.
      */
     @GuardedBy("mInstallLock")
-    private int performDexOptLI(AndroidPackage pkg,
+    private int performDexOptLI(AndroidPackage pkg, @NonNull PackageSetting pkgSetting,
             String[] targetInstructionSets, CompilerStats.PackageStats packageStats,
             PackageDexUsage.PackageUseInfo packageUseInfo, DexoptOptions options) {
-        final List<SharedLibraryInfo> sharedLibraries = pkg.getUsesLibraryInfos();
+        final List<SharedLibraryInfo> sharedLibraries = pkgSetting.getPkgState()
+                .getUsesLibraryInfos();
         final String[] instructionSets = targetInstructionSets != null ?
-                targetInstructionSets : getAppDexInstructionSets(pkg.getPrimaryCpuAbi(),
-                pkg.getSecondaryCpuAbi());
+                targetInstructionSets : getAppDexInstructionSets(
+                AndroidPackageUtils.getPrimaryCpuAbi(pkg, pkgSetting),
+                AndroidPackageUtils.getSecondaryCpuAbi(pkg, pkgSetting));
         final String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
-        final List<String> paths = pkg.getAllCodePaths();
+        final List<String> paths = AndroidPackageUtils.getAllCodePaths(pkg);
 
         int sharedGid = UserHandle.getSharedAppGid(pkg.getUid());
         if (sharedGid == -1) {
-            Slog.wtf(TAG, "Well this is awkward; package " + pkg.getAppInfoName() + " had UID "
+            Slog.wtf(TAG, "Well this is awkward; package " + pkg.getPackageName() + " had UID "
                     + pkg.getUid(), new Throwable());
             sharedGid = android.os.Process.NOBODY_UID;
         }
@@ -173,7 +177,7 @@
         // For each code path in the package, this array contains the class loader context that
         // needs to be passed to dexopt in order to ensure correct optimizations.
         boolean[] pathsWithCode = new boolean[paths.size()];
-        pathsWithCode[0] = (pkg.getFlags() & ApplicationInfo.FLAG_HAS_CODE) != 0;
+        pathsWithCode[0] = pkg.isHasCode();
         for (int i = 1; i < paths.size(); i++) {
             pathsWithCode[i] = (pkg.getSplitFlags()[i - 1] & ApplicationInfo.FLAG_HAS_CODE) != 0;
         }
@@ -232,10 +236,10 @@
 
             // Get the dexopt flags after getRealCompilerFilter to make sure we get the correct
             // flags.
-            final int dexoptFlags = getDexFlags(pkg, compilerFilter, options);
+            final int dexoptFlags = getDexFlags(pkg, pkgSetting, compilerFilter, options);
 
             for (String dexCodeIsa : dexCodeInstructionSets) {
-                int newResult = dexOptPath(pkg, path, dexCodeIsa, compilerFilter,
+                int newResult = dexOptPath(pkg, pkgSetting, path, dexCodeIsa, compilerFilter,
                         profileUpdated, classLoaderContexts[i], dexoptFlags, sharedGid,
                         packageStats, options.isDowngrade(), profileName, dexMetadataPath,
                         options.getCompilationReason());
@@ -260,8 +264,8 @@
      *      DEX_OPT_SKIPPED if the path does not need to be deopt-ed.
      */
     @GuardedBy("mInstallLock")
-    private int dexOptPath(AndroidPackage pkg, String path, String isa,
-            String compilerFilter, boolean profileUpdated, String classLoaderContext,
+    private int dexOptPath(AndroidPackage pkg, @NonNull PackageSetting pkgSetting, String path,
+            String isa, String compilerFilter, boolean profileUpdated, String classLoaderContext,
             int dexoptFlags, int uid, CompilerStats.PackageStats packageStats, boolean downgrade,
             String profileName, String dexMetadataPath, int compilationReason) {
         int dexoptNeeded = getDexoptNeeded(path, isa, compilerFilter, classLoaderContext,
@@ -270,10 +274,11 @@
             return DEX_OPT_SKIPPED;
         }
 
-        String oatDir = getPackageOatDirIfSupported(pkg);
+        String oatDir = getPackageOatDirIfSupported(pkg,
+                pkgSetting.getPkgState().isUpdatedSystemApp());
 
         Log.i(TAG, "Running dexopt (dexoptNeeded=" + dexoptNeeded + ") on: " + path
-                + " pkg=" + pkg.getAppInfoPackageName() + " isa=" + isa
+                + " pkg=" + pkg.getPackageName() + " isa=" + isa
                 + " dexoptFlags=" + printDexoptFlags(dexoptFlags)
                 + " targetFilter=" + compilerFilter + " oatDir=" + oatDir
                 + " classLoaderContext=" + classLoaderContext);
@@ -284,9 +289,10 @@
             // TODO: Consider adding 2 different APIs for primary and secondary dexopt.
             // installd only uses downgrade flag for secondary dex files and ignores it for
             // primary dex files.
+            String seInfo = AndroidPackageUtils.getSeInfo(pkg, pkgSetting);
             mInstaller.dexopt(path, uid, pkg.getPackageName(), isa, dexoptNeeded, oatDir,
                     dexoptFlags, compilerFilter, pkg.getVolumeUuid(), classLoaderContext,
-                    pkg.getSeInfo(), false /* downgrade*/, pkg.getTargetSdkVersion(),
+                    seInfo, false /* downgrade*/, pkg.getTargetSdkVersion(),
                     profileName, dexMetadataPath,
                     getAugmentedReasonName(compilationReason, dexMetadataPath != null));
 
@@ -449,13 +455,14 @@
     /**
      * Dumps the dexopt state of the given package {@code pkg} to the given {@code PrintWriter}.
      */
-    void dumpDexoptState(IndentingPrintWriter pw, AndroidPackage pkg,
+    void dumpDexoptState(IndentingPrintWriter pw, AndroidPackage pkg, PackageSetting pkgSetting,
             PackageDexUsage.PackageUseInfo useInfo) {
-        final String[] instructionSets = getAppDexInstructionSets(pkg.getPrimaryCpuAbi(),
-                pkg.getSecondaryCpuAbi());
+        final String[] instructionSets = getAppDexInstructionSets(
+                AndroidPackageUtils.getPrimaryCpuAbi(pkg, pkgSetting),
+                AndroidPackageUtils.getSecondaryCpuAbi(pkg, pkgSetting));
         final String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
 
-        final List<String> paths = pkg.getAllCodePathsExcludingResourceOnly();
+        final List<String> paths = AndroidPackageUtils.getAllCodePathsExcludingResourceOnly(pkg);
 
         for (String path : paths) {
             pw.println("path: " + path);
@@ -546,7 +553,7 @@
     private String getRealCompilerFilter(AndroidPackage pkg, String targetCompilerFilter,
             boolean isUsedByOtherApps) {
         // When an app or priv app is configured to run out of box, only verify it.
-        if (pkg.isEmbeddedDexUsed()
+        if (pkg.isUseEmbeddedDex()
                 || (pkg.isPrivileged()
                     && DexManager.isPackageSelectedToRunOob(pkg.getPackageName()))) {
             return "verify";
@@ -562,8 +569,7 @@
         // PackageDexOptimizer#canOptimizePackage or PackageManagerService#getOptimizablePackages
         // but that would have the downside of possibly producing a big odex files which would
         // be ignored anyway.
-        boolean vmSafeModeOrDebuggable = ((pkg.getFlags() & ApplicationInfo.FLAG_VM_SAFE_MODE) != 0)
-                || ((pkg.getFlags() & ApplicationInfo.FLAG_DEBUGGABLE) != 0);
+        boolean vmSafeModeOrDebuggable = pkg.isVmSafeMode() || pkg.isDebuggable();
 
         if (vmSafeModeOrDebuggable) {
             return getSafeModeCompilerFilter(targetCompilerFilter);
@@ -583,14 +589,15 @@
     }
 
     private int getDexFlags(ApplicationInfo info, String compilerFilter, DexoptOptions options) {
-        return getDexFlags(info.flags, info.getHiddenApiEnforcementPolicy(),
-                info.splitDependencies, info.requestsIsolatedSplitLoading(), compilerFilter,
-                options);
+        return getDexFlags((info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0,
+                info.getHiddenApiEnforcementPolicy(), info.splitDependencies,
+                info.requestsIsolatedSplitLoading(), compilerFilter, options);
     }
-    private int getDexFlags(AndroidPackage pkg, String compilerFilter,
-            DexoptOptions options) {
-        return getDexFlags(pkg.getFlags(), pkg.getHiddenApiEnforcementPolicy(),
-                pkg.getSplitDependencies(), pkg.requestsIsolatedSplitLoading(), compilerFilter,
+    private int getDexFlags(AndroidPackage pkg, @NonNull PackageSetting pkgSetting,
+            String compilerFilter, DexoptOptions options) {
+        return getDexFlags(pkg.isDebuggable(),
+                AndroidPackageUtils.getHiddenApiEnforcementPolicy(pkg, pkgSetting),
+                pkg.getSplitDependencies(), pkg.isIsolatedSplitLoading(), compilerFilter,
                 options);
     }
 
@@ -598,10 +605,9 @@
      * Computes the dex flags that needs to be pass to installd for the given package and compiler
      * filter.
      */
-    private int getDexFlags(int flags, int hiddenApiEnforcementPolicy,
+    private int getDexFlags(boolean debuggable, int hiddenApiEnforcementPolicy,
             SparseArray<int[]> splitDependencies, boolean requestsIsolatedSplitLoading,
             String compilerFilter, DexoptOptions options) {
-        boolean debuggable = (flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
         // Profile guide compiled oat files should not be public unles they are based
         // on profiles from dex metadata archives.
         // The flag isDexoptInstallWithDexMetadata applies only on installs when we know that
@@ -699,8 +705,8 @@
      * not needed or unsupported for the package.
      */
     @Nullable
-    private String getPackageOatDirIfSupported(AndroidPackage pkg) {
-        if (!pkg.canHaveOatDir()) {
+    private String getPackageOatDirIfSupported(AndroidPackage pkg, boolean isUpdatedSystemApp) {
+        if (!AndroidPackageUtils.canHaveOatDir(pkg, isUpdatedSystemApp)) {
             return null;
         }
         File codePath = new File(pkg.getCodePath());
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 0e554f8..41988d6 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -81,7 +81,6 @@
 import android.content.pm.PackageParser.PackageLite;
 import android.content.pm.PackageParser.PackageParserException;
 import android.content.pm.dex.DexMetadataHelper;
-import android.content.pm.parsing.AndroidPackage;
 import android.content.pm.parsing.ApkLiteParseUtils;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
@@ -127,6 +126,7 @@
 import com.android.server.LocalServices;
 import com.android.server.pm.Installer.InstallerException;
 import com.android.server.pm.dex.DexManager;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.security.VerityUtils;
 
 import libcore.io.IoUtils;
@@ -1169,12 +1169,13 @@
      */
     private static boolean isIncrementalInstallationAllowed(String packageName) {
         final PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
-        final AndroidPackage existingPackage = pmi.getPackage(packageName);
-        if (existingPackage == null) {
+        final PackageSetting existingPkgSetting = pmi.getPackageSetting(packageName);
+        if (existingPkgSetting == null || existingPkgSetting.pkg == null) {
             return true;
         }
 
-        return !PackageManagerService.isSystemApp(existingPackage);
+        return !existingPkgSetting.pkg.isSystem()
+                && !existingPkgSetting.getPkgState().isUpdatedSystemApp();
     }
 
     /**
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 2a3f7ed..14964b5 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -104,6 +104,9 @@
 import static com.android.internal.content.NativeLibraryHelper.LIB_DIR_NAME;
 import static com.android.internal.util.ArrayUtils.emptyIfNull;
 import static com.android.internal.util.ArrayUtils.filter;
+import static com.android.internal.util.FrameworkStatsLog.BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_DATA_APP_AVG_SCAN_TIME;
+import static com.android.internal.util.FrameworkStatsLog.BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_INIT_TIME;
+import static com.android.internal.util.FrameworkStatsLog.BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_SYSTEM_APP_AVG_SCAN_TIME;
 import static com.android.server.pm.ComponentResolver.RESOLVE_PRIORITY_SORTER;
 import static com.android.server.pm.InstructionSets.getAppDexInstructionSets;
 import static com.android.server.pm.InstructionSets.getDexCodeInstructionSet;
@@ -209,20 +212,17 @@
 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.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.PackageInfoWithoutStateUtils;
+import android.content.pm.parsing.ParsingPackageRead;
+import android.content.pm.parsing.ParsingPackageUtils;
+import android.content.pm.parsing.component.ParsedActivity;
+import android.content.pm.parsing.component.ParsedInstrumentation;
+import android.content.pm.parsing.component.ParsedIntentInfo;
+import android.content.pm.parsing.component.ParsedMainComponent;
+import android.content.pm.parsing.component.ParsedPermission;
+import android.content.pm.parsing.component.ParsedProcess;
+import android.content.pm.parsing.component.ParsedProvider;
+import android.content.pm.parsing.component.ParsedService;
 import android.content.res.Resources;
 import android.content.rollback.IRollbackManager;
 import android.database.ContentObserver;
@@ -341,6 +341,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 +1018,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<>();
@@ -1080,7 +1087,7 @@
     boolean mResolverReplaced = false;
 
     private final @Nullable ComponentName mIntentFilterVerifierComponent;
-    private final @Nullable IntentFilterVerifier<ParsedActivityIntentInfo> mIntentFilterVerifier;
+    private final @Nullable IntentFilterVerifier<ParsedIntentInfo> mIntentFilterVerifier;
 
     private int mIntentFilterVerificationToken = 0;
 
@@ -1141,7 +1148,7 @@
         void receiveVerificationResponse(int verificationId);
     }
 
-    private class IntentVerifierProxy implements IntentFilterVerifier<ParsedActivityIntentInfo> {
+    private class IntentVerifierProxy implements IntentFilterVerifier<ParsedIntentInfo> {
         private Context mContext;
         private ComponentName mIntentFilterVerifierComponent;
         private ArrayList<Integer> mCurrentIntentFilterVerifications = new ArrayList<>();
@@ -1166,11 +1173,11 @@
 
                 String packageName = ivs.getPackageName();
 
-                ArrayList<ParsedActivityIntentInfo> filters = ivs.getFilters();
+                ArrayList<ParsedIntentInfo> filters = ivs.getFilters();
                 final int filterCount = filters.size();
                 ArraySet<String> domainsSet = new ArraySet<>();
                 for (int m=0; m<filterCount; m++) {
-                    ParsedActivityIntentInfo filter = filters.get(m);
+                    ParsedIntentInfo filter = filters.get(m);
                     domainsSet.addAll(filter.getHostsList());
                 }
                 synchronized (mLock) {
@@ -1222,14 +1229,14 @@
 
             final boolean verified = ivs.isVerified();
 
-            ArrayList<ParsedActivityIntentInfo> filters = ivs.getFilters();
+            ArrayList<ParsedIntentInfo> filters = ivs.getFilters();
             final int count = filters.size();
             if (DEBUG_DOMAIN_VERIFICATION) {
                 Slog.i(TAG, "Received verification response " + verificationId
                         + " for " + count + " filters, verified=" + verified);
             }
             for (int n=0; n<count; n++) {
-                ParsedActivityIntentInfo filter = filters.get(n);
+                ParsedIntentInfo filter = filters.get(n);
                 filter.setVerified(verified);
 
                 if (DEBUG_DOMAIN_VERIFICATION) Slog.d(TAG, "IntentFilter " + filter.toString()
@@ -1342,7 +1349,7 @@
 
         @Override
         public boolean addOneIntentFilterVerification(int verifierUid, int userId, int verificationId,
-                ParsedActivityIntentInfo filter, String packageName) {
+                ParsedIntentInfo filter, String packageName) {
             if (!hasValidDomains(filter)) {
                 return false;
             }
@@ -1371,7 +1378,7 @@
         }
     }
 
-    private static boolean hasValidDomains(ParsedActivityIntentInfo filter) {
+    private static boolean hasValidDomains(ParsedIntentInfo filter) {
         return filter.hasCategory(Intent.CATEGORY_BROWSABLE)
                 && (filter.hasDataScheme(IntentFilter.SCHEME_HTTP) ||
                         filter.hasDataScheme(IntentFilter.SCHEME_HTTPS));
@@ -2033,7 +2040,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 +2090,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);
 
@@ -2147,7 +2154,7 @@
                             null /*package*/, null /*extras*/, 0 /*flags*/,
                             packageName /*targetPackage*/,
                             null /*finishedReceiver*/, updateUserIds, instantUserIds);
-                } else if (launchedForRestore && !isSystemApp(res.pkg)) {
+                } else if (launchedForRestore && !res.pkg.isSystem()) {
                     // First-install and we did a restore, so we're responsible for the
                     // first-launch broadcast.
                     if (DEBUG_BACKUP) {
@@ -2159,14 +2166,14 @@
                 }
 
                 // Send broadcast package appeared if external for all users
-                if (isExternal(res.pkg)) {
+                if (res.pkg.isExternalStorage()) {
                     if (!update) {
                         final StorageManager storage = mInjector.getStorageManager();
                         VolumeInfo volume =
                                 storage.findVolumeByUuid(
                                         res.pkg.getStorageUuid().toString());
                         int packageExternalStorageType =
-                                getPackageExternalStorageType(volume, isExternal(res.pkg));
+                                getPackageExternalStorageType(volume, res.pkg.isExternalStorage());
                         // If the package was installed externally, log it.
                         if (packageExternalStorageType != StorageEnums.UNKNOWN) {
                             FrameworkStatsLog.write(
@@ -2499,15 +2506,18 @@
                 packageName -> {
                     synchronized (m.mInstallLock) {
                         final AndroidPackage pkg;
+                        final PackageSetting ps;
                         final SharedUserSetting sharedUser;
+                        final String oldSeInfo;
                         synchronized (m.mLock) {
-                            PackageSetting ps = m.mSettings.getPackageLPr(packageName);
+                            ps = m.mSettings.getPackageLPr(packageName);
                             if (ps == null) {
                                 Slog.e(TAG, "Failed to find package setting " + packageName);
                                 return;
                             }
                             pkg = ps.pkg;
-                            sharedUser = ps.sharedUser;
+                            sharedUser = ps.getSharedUser();
+                            oldSeInfo = AndroidPackageUtils.getSeInfo(pkg, ps);
                         }
 
                         if (pkg == null) {
@@ -2517,10 +2527,10 @@
                         final String newSeInfo = SELinuxMMAC.getSeInfo(pkg, sharedUser,
                                 m.mInjector.getCompatibility());
 
-                        if (!newSeInfo.equals(pkg.getSeInfo())) {
+                        if (!newSeInfo.equals(oldSeInfo)) {
                             Slog.i(TAG, "Updating seInfo for package " + packageName + " from: "
-                                    + pkg.getSeInfo() + " to: " + newSeInfo);
-                            pkg.mutate().setSeInfo(newSeInfo);
+                                    + oldSeInfo + " to: " + newSeInfo);
+                            ps.getPkgState().setOverrideSeInfo(newSeInfo);
                             m.prepareAppDataAfterInstallLIF(pkg);
                         }
                     }
@@ -2859,12 +2869,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 +2908,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<>();
@@ -2995,8 +3003,11 @@
                     + (systemPackagesCount == 0 ? 0 : systemScanTime / systemPackagesCount)
                     + " , cached: " + cachedSystemApps);
             if (mIsUpgrade && systemPackagesCount > 0) {
-                MetricsLogger.histogram(null, "ota_package_manager_system_app_avg_scan_time",
-                        ((int) systemScanTime) / systemPackagesCount);
+                //CHECKSTYLE:OFF IndentationCheck
+                FrameworkStatsLog.write(FrameworkStatsLog.BOOT_TIME_EVENT_DURATION_REPORTED,
+                    BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_SYSTEM_APP_AVG_SCAN_TIME,
+                    systemScanTime / systemPackagesCount);
+                //CHECKSTYLE:ON IndentationCheck
             }
             if (!mOnlyCore) {
                 EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
@@ -3044,7 +3055,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: "
@@ -3123,8 +3134,12 @@
                         + (dataPackagesCount == 0 ? 0 : dataScanTime / dataPackagesCount)
                         + " , cached: " + cachedNonSystemApps);
                 if (mIsUpgrade && dataPackagesCount > 0) {
-                    MetricsLogger.histogram(null, "ota_package_manager_data_app_avg_scan_time",
-                            ((int) dataScanTime) / dataPackagesCount);
+                    //CHECKSTYLE:OFF IndentationCheck
+                    FrameworkStatsLog.write(
+                        FrameworkStatsLog.BOOT_TIME_EVENT_DURATION_REPORTED,
+                        BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_DATA_APP_AVG_SCAN_TIME,
+                        dataScanTime / dataPackagesCount);
+                    //CHECKSTYLE:OFF IndentationCheck
                 }
             }
             mExpectingBetter.clear();
@@ -3149,7 +3164,7 @@
 
             // Now that we know all of the shared libraries, update all clients to have
             // the correct library paths.
-            updateAllSharedLibrariesLocked(null, Collections.unmodifiableMap(mPackages));
+            updateAllSharedLibrariesLocked(null, null, Collections.unmodifiableMap(mPackages));
 
             for (SharedUserSetting setting : mSettings.getAllSharedUsersLPw()) {
                 // NOTE: We ignore potential failures here during a system scan (like
@@ -3177,7 +3192,7 @@
 
             // Now that we know all the packages we are keeping,
             // read and update their last usage times.
-            mPackageUsage.read(mPackages);
+            mPackageUsage.read(mSettings.mPackages);
             mCompilerStats.read();
 
             EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SCAN_END,
@@ -3385,8 +3400,10 @@
             }
             mDexManager.load(userPackages);
             if (mIsUpgrade) {
-                MetricsLogger.histogram(null, "ota_package_manager_init_time",
-                        (int) (SystemClock.uptimeMillis() - startTime));
+                FrameworkStatsLog.write(
+                        FrameworkStatsLog.BOOT_TIME_EVENT_DURATION_REPORTED,
+                        BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_INIT_TIME,
+                        SystemClock.uptimeMillis() - startTime);
             }
         } // synchronized (mLock)
         } // synchronized (mInstallLock)
@@ -3476,7 +3493,8 @@
      * APK will be installed and the package will be disabled. To recover from this situation,
      * the user will need to go into system settings and re-enable the package.
      */
-    private boolean enableCompressedPackage(AndroidPackage stubPkg) {
+    private boolean enableCompressedPackage(AndroidPackage stubPkg,
+            @NonNull PackageSetting stubPkgSetting) {
         final int parseFlags = mDefParseFlags | PackageParser.PARSE_CHATTY
                 | PackageParser.PARSE_ENFORCE_CODE;
         synchronized (mInstallLock) {
@@ -3487,7 +3505,7 @@
                 synchronized (mLock) {
                     prepareAppDataAfterInstallLIF(pkg);
                     try {
-                        updateSharedLibrariesLocked(pkg, null,
+                        updateSharedLibrariesLocked(pkg, stubPkgSetting, null, null,
                                 Collections.unmodifiableMap(mPackages));
                     } catch (PackageManagerException e) {
                         Slog.e(TAG, "updateAllSharedLibrariesLPw failed: ", e);
@@ -4010,15 +4028,13 @@
                 }
 
                 ArraySet<String> domains = null;
-                if (pkg.getActivities() != null) {
-                    for (ParsedActivity a : pkg.getActivities()) {
-                        for (ParsedActivityIntentInfo filter : a.intents) {
-                            if (hasValidDomains(filter)) {
-                                if (domains == null) {
-                                    domains = new ArraySet<>();
-                                }
-                                domains.addAll(filter.getHostsList());
+                for (ParsedActivity a : pkg.getActivities()) {
+                    for (ParsedIntentInfo filter : a.getIntents()) {
+                        if (hasValidDomains(filter)) {
+                            if (domains == null) {
+                                domains = new ArraySet<>();
                             }
+                            domains.addAll(filter.getHostsList());
                         }
                     }
                 }
@@ -4146,7 +4162,7 @@
                     ? Collections.emptySet() : permissionsState.getPermissions(userId);
 
             PackageInfo packageInfo = PackageInfoUtils.generate(p, gids, flags,
-                    ps.firstInstallTime, ps.lastUpdateTime, permissions, state, userId);
+                    ps.firstInstallTime, ps.lastUpdateTime, permissions, state, userId, ps);
 
             if (packageInfo == null) {
                 return null;
@@ -4208,7 +4224,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!");
             }
         }
@@ -4289,7 +4305,7 @@
             }
 
             AndroidPackage p = mPackages.get(packageName);
-            if (matchFactoryOnly && p != null && !isSystemApp(p)) {
+            if (matchFactoryOnly && p != null && !p.isSystem()) {
                 return null;
             }
             if (DEBUG_PACKAGE_INFO)
@@ -4344,9 +4360,9 @@
                 return false;
             }
             final boolean visibleToInstantApp =
-                    (activity.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0;
+                    (activity.getFlags() & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0;
             final boolean explicitlyVisibleToInstantApp =
-                    (activity.flags & ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP) == 0;
+                    (activity.getFlags() & ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP) == 0;
             return visibleToInstantApp && explicitlyVisibleToInstantApp;
         } else if (type == TYPE_RECEIVER) {
             final ParsedActivity activity = mComponentResolver.getReceiver(component);
@@ -4354,20 +4370,18 @@
                 return false;
             }
             final boolean visibleToInstantApp =
-                    (activity.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0;
+                    (activity.getFlags() & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0;
             final boolean explicitlyVisibleToInstantApp =
-                    (activity.flags & ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP) == 0;
+                    (activity.getFlags() & ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP) == 0;
             return visibleToInstantApp && !explicitlyVisibleToInstantApp;
         } else if (type == TYPE_SERVICE) {
             final ParsedService service = mComponentResolver.getService(component);
             return service != null
-                    ? (service.flags & ServiceInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0
-                    : false;
+                    && (service.getFlags() & ServiceInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0;
         } else if (type == TYPE_PROVIDER) {
             final ParsedProvider provider = mComponentResolver.getProvider(component);
             return provider != null
-                    ? (provider.getFlags() & ProviderInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0
-                    : false;
+                    && (provider.getFlags() & ProviderInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0;
         } else if (type == TYPE_UNKNOWN) {
             return isComponentVisibleToInstantApp(component);
         }
@@ -4574,7 +4588,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 +4618,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;
@@ -4656,7 +4670,7 @@
                 return null;
             }
             ApplicationInfo ai = PackageInfoUtils.generateApplicationInfo(ps.pkg, flags,
-                    ps.readUserState(userId), userId);
+                    ps.readUserState(userId), userId, ps);
             if (ai != null) {
                 ai.packageName = resolveExternalPackageNameLPr(ps.pkg);
             }
@@ -4708,7 +4722,7 @@
                 }
                 // Note: isEnabledLP() does not apply here - always return info
                 ApplicationInfo ai = PackageInfoUtils.generateApplicationInfo(
-                        p, flags, ps.readUserState(userId), userId);
+                        p, flags, ps.readUserState(userId), userId, ps);
                 if (ai != null) {
                     ai.packageName = resolveExternalPackageNameLPr(p);
                 }
@@ -5092,7 +5106,7 @@
                     return null;
                 }
                 return PackageInfoUtils.generateActivityInfo(pkg,
-                        a, flags, ps.readUserState(userId), userId);
+                        a, flags, ps.readUserState(userId), userId, ps);
             }
             if (mResolveComponentName.equals(component)) {
                 return PackageParser.generateActivityInfo(
@@ -5140,8 +5154,8 @@
                     ps, callingUid, component, TYPE_ACTIVITY, callingUserId)) {
                 return false;
             }
-            for (int i=0; i<a.intents.size(); i++) {
-                if (a.intents.get(i).match(intent.getAction(), resolvedType, intent.getScheme(),
+            for (int i=0; i< a.getIntents().size(); i++) {
+                if (a.getIntents().get(i).match(intent.getAction(), resolvedType, intent.getScheme(),
                         intent.getData(), intent.getCategories(), TAG) >= 0) {
                     return true;
                 }
@@ -5179,7 +5193,7 @@
                     return null;
                 }
                 return PackageInfoUtils.generateActivityInfo(pkg,
-                        a, flags, ps.readUserState(userId), userId);
+                        a, flags, ps.readUserState(userId), userId, ps);
             }
         }
         return null;
@@ -5400,7 +5414,7 @@
                     return null;
                 }
                 return PackageInfoUtils.generateServiceInfo(pkg,
-                        s, flags, ps.readUserState(userId), userId);
+                        s, flags, ps.readUserState(userId), userId, ps);
             }
         }
         return null;
@@ -5434,7 +5448,7 @@
                     return null;
                 }
                 PackageUserState state = ps.readUserState(userId);
-                return PackageInfoUtils.generateProviderInfo(pkg, p, flags, state, userId);
+                return PackageInfoUtils.generateProviderInfo(pkg, p, flags, state, userId, ps);
             }
         }
         return null;
@@ -8272,7 +8286,7 @@
                             continue;
                         }
                         ai = PackageInfoUtils.generateApplicationInfo(ps.pkg, effectiveFlags,
-                                ps.readUserState(userId), userId);
+                                ps.readUserState(userId), userId, ps);
                         if (ai != null) {
                             ai.packageName = resolveExternalPackageNameLPr(ps.pkg);
                         }
@@ -8298,7 +8312,7 @@
                             continue;
                         }
                         ApplicationInfo ai = PackageInfoUtils.generateApplicationInfo(p, flags,
-                                ps.readUserState(userId), userId);
+                                ps.readUserState(userId), userId, ps);
                         if (ai != null) {
                             ai.packageName = resolveExternalPackageNameLPr(p);
                             list.add(ai);
@@ -8451,13 +8465,13 @@
                 final boolean matchesAware = ((flags & MATCH_DIRECT_BOOT_AWARE) != 0)
                         && p.isDirectBootAware();
 
-                if ((p.getFlags() & ApplicationInfo.FLAG_PERSISTENT) != 0
-                        && (!mSafeMode || isSystemApp(p))
+                if (p.isPersistent()
+                        && (!mSafeMode || p.isSystem())
                         && (matchesUnaware || matchesAware)) {
                     PackageSetting ps = mSettings.mPackages.get(p.getPackageName());
                     if (ps != null) {
                         ApplicationInfo ai = PackageInfoUtils.generateApplicationInfo(p, flags,
-                                ps.readUserState(userId), userId);
+                                ps.readUserState(userId), userId, ps);
                         if (ai != null) {
                             finalList.add(ai);
                         }
@@ -8563,7 +8577,7 @@
                 return null;
             }
             final ParsedInstrumentation i = mInstrumentation.get(component);
-            return PackageInfoUtils.generateInstrumentationInfo(i, pkg, flags);
+            return PackageInfoUtils.generateInstrumentationInfo(i, pkg, flags, callingUserId, ps);
         }
     }
 
@@ -8576,11 +8590,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
@@ -8590,10 +8605,12 @@
                 final ParsedInstrumentation p = i.next();
                 if (targetPackage == null
                         || targetPackage.equals(p.getTargetPackage())) {
-                    AndroidPackage pkg = mPackages.get(p.getPackageName());
+                    String packageName = p.getPackageName();
+                    AndroidPackage pkg = mPackages.get(packageName);
+                    PackageSetting pkgSetting = getPackageSetting(packageName);
                     if (pkg != null) {
                         InstrumentationInfo ii = PackageInfoUtils.generateInstrumentationInfo(p,
-                                pkg, flags);
+                                pkg, flags, userId, pkgSetting);
                         if (ii != null) {
                             finalList.add(ii);
                         }
@@ -8606,7 +8623,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 +8633,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 +8737,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 +8792,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 +8884,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);
@@ -8933,8 +8936,8 @@
                     final ScanRequest request = new ScanRequest(parsedPackage, sharedUserSetting,
                             null, disabledPkgSetting /* pkgSetting */,
                             null /* disabledPkgSetting */, null /* originalPkgSetting */,
-                            null, parseFlags, scanFlags, isPlatformPackage, user);
-                    applyPolicy(parsedPackage, parseFlags, scanFlags, mPlatformPackage);
+                            null, parseFlags, scanFlags, isPlatformPackage, user, null);
+                    applyPolicy(parsedPackage, parseFlags, scanFlags, mPlatformPackage, true);
                     final ScanResult scanResult =
                             scanPackageOnlyLI(request, mInjector, mFactoryTest, -1L);
                     if (scanResult.existingSettingCopied && scanResult.request.pkgSetting != null) {
@@ -9068,7 +9071,7 @@
         }
 
         final ScanResult scanResult = scanPackageNewLI(parsedPackage, parseFlags, scanFlags
-                | SCAN_UPDATE_SIGNATURE, currentTime, user);
+                | SCAN_UPDATE_SIGNATURE, currentTime, user, null);
         if (scanResult.success) {
             synchronized (mLock) {
                 boolean appIdCreated = false;
@@ -9208,9 +9211,15 @@
             return;
         }
 
-        List<AndroidPackage> pkgs;
+        List<PackageSetting> pkgSettings;
         synchronized (mLock) {
-            pkgs = PackageManagerServiceUtils.getPackagesForDexopt(mPackages.values(), this);
+            pkgSettings = PackageManagerServiceUtils.getPackagesForDexopt(
+                    mSettings.mPackages.values(), this);
+        }
+
+        List<AndroidPackage> pkgs = new ArrayList<>(pkgSettings.size());
+        for (int index = 0; index < pkgSettings.size(); index++) {
+            pkgs.add(pkgSettings.get(index).pkg);
         }
 
         final long startTime = System.nanoTime();
@@ -9255,7 +9264,7 @@
 
             boolean useProfileForDexopt = false;
 
-            if ((isFirstBoot() || isDeviceUpgrading()) && isSystemApp(pkg)) {
+            if ((isFirstBoot() || isDeviceUpgrading()) && pkg.isSystem()) {
                 // Copy over initial preopt profiles since we won't get any JIT samples for methods
                 // that are already compiled.
                 File profileFile = new File(getPrebuildProfilePath(pkg));
@@ -9409,16 +9418,16 @@
 
     @GuardedBy("mLock")
     private void notifyPackageUseLocked(String packageName, int reason) {
-        final AndroidPackage p = mPackages.get(packageName);
-        if (p == null) {
+        final PackageSetting pkgSetting = mSettings.getPackageLPr(packageName);
+        if (pkgSetting == null) {
             return;
         }
-        p.mutate().setLastPackageUsageTimeInMills(reason, System.currentTimeMillis());
+        pkgSetting.getPkgState().setLastPackageUsageTimeInMills(reason, System.currentTimeMillis());
     }
 
     @Override
-    public void notifyDexLoad(String loadingPackageName, List<String> classLoaderNames,
-            List<String> classPaths, String loaderIsa) {
+    public void notifyDexLoad(String loadingPackageName, Map<String, String> classLoaderContextMap,
+            String loaderIsa) {
         int userId = UserHandle.getCallingUserId();
         ApplicationInfo ai = getApplicationInfo(loadingPackageName, /*flags*/ 0, userId);
         if (ai == null) {
@@ -9426,7 +9435,7 @@
                 + loadingPackageName + ", user=" + userId);
             return;
         }
-        mDexManager.notifyDexLoad(ai, classLoaderNames, classPaths, loaderIsa, userId);
+        mDexManager.notifyDexLoad(ai, classLoaderContextMap, loaderIsa, userId);
     }
 
     @Override
@@ -9541,19 +9550,21 @@
     // if the package can now be considered up to date for the given filter.
     private int performDexOptInternal(DexoptOptions options) {
         AndroidPackage p;
+        PackageSetting pkgSetting;
         synchronized (mLock) {
             p = mPackages.get(options.getPackageName());
-            if (p == null) {
+            pkgSetting = mSettings.getPackageLPr(options.getPackageName());
+            if (p == null || pkgSetting == null) {
                 // Package could not be found. Report failure.
                 return PackageDexOptimizer.DEX_OPT_FAILED;
             }
-            mPackageUsage.maybeWriteAsync(mPackages);
+            mPackageUsage.maybeWriteAsync(mSettings.mPackages);
             mCompilerStats.maybeWriteAsync();
         }
         long callingId = Binder.clearCallingIdentity();
         try {
             synchronized (mInstallLock) {
-                return performDexOptInternalWithDependenciesLI(p, options);
+                return performDexOptInternalWithDependenciesLI(p, pkgSetting, options);
             }
         } finally {
             Binder.restoreCallingIdentity(callingId);
@@ -9573,7 +9584,7 @@
     }
 
     private int performDexOptInternalWithDependenciesLI(AndroidPackage p,
-            DexoptOptions options) {
+            @NonNull PackageSetting pkgSetting, DexoptOptions options) {
         // Select the dex optimizer based on the force parameter.
         // Note: The force option is rarely used (cmdline input for testing, mostly), so it's OK to
         //       allocate an object here.
@@ -9588,9 +9599,10 @@
         // at boot, or background job), the passed 'targetCompilerFilter' stays the same,
         // and the first package that uses the library will dexopt it. The
         // others will see that the compiled code for the library is up to date.
-        Collection<SharedLibraryInfo> deps = findSharedLibraries(p);
-        final String[] instructionSets = getAppDexInstructionSets(p.getPrimaryCpuAbi(),
-                p.getSecondaryCpuAbi());
+        Collection<SharedLibraryInfo> deps = findSharedLibraries(pkgSetting);
+        final String[] instructionSets = getAppDexInstructionSets(
+                AndroidPackageUtils.getPrimaryCpuAbi(p, pkgSetting),
+                AndroidPackageUtils.getSecondaryCpuAbi(p, pkgSetting));
         if (!deps.isEmpty()) {
             DexoptOptions libraryOptions = new DexoptOptions(options.getPackageName(),
                     options.getCompilationReason(), options.getCompilerFilter(),
@@ -9598,12 +9610,14 @@
                     options.getFlags() | DexoptOptions.DEXOPT_AS_SHARED_LIBRARY);
             for (SharedLibraryInfo info : deps) {
                 AndroidPackage depPackage = null;
+                PackageSetting depPackageSetting = null;
                 synchronized (mLock) {
                     depPackage = mPackages.get(info.getPackageName());
+                    depPackageSetting = mSettings.getPackageLPr(info.getPackageName());
                 }
-                if (depPackage != null) {
+                if (depPackage != null && depPackageSetting != null) {
                     // TODO: Analyze and investigate if we (should) profile libraries.
-                    pdo.performDexOpt(depPackage, instructionSets,
+                    pdo.performDexOpt(depPackage, depPackageSetting, instructionSets,
                             getOrCreateCompilerPackageStats(depPackage),
                             mDexManager.getPackageUseInfoOrDefault(depPackage.getPackageName()),
                             libraryOptions);
@@ -9612,7 +9626,8 @@
                 }
             }
         }
-        return pdo.performDexOpt(p, instructionSets,
+
+        return pdo.performDexOpt(p, pkgSetting, instructionSets,
                 getOrCreateCompilerPackageStats(p),
                 mDexManager.getPackageUseInfoOrDefault(p.getPackageName()), options);
     }
@@ -9655,11 +9670,11 @@
         }
     }
 
-    private static List<SharedLibraryInfo> findSharedLibraries(AndroidPackage p) {
-        if (p.getUsesLibraryInfos() != null) {
+    private static List<SharedLibraryInfo> findSharedLibraries(PackageSetting pkgSetting) {
+        if (!pkgSetting.getPkgState().getUsesLibraryInfos().isEmpty()) {
             ArrayList<SharedLibraryInfo> retValue = new ArrayList<>();
             Set<String> collectedNames = new HashSet<>();
-            for (SharedLibraryInfo info : p.getUsesLibraryInfos()) {
+            for (SharedLibraryInfo info : pkgSetting.getPkgState().getUsesLibraryInfos()) {
                 findSharedLibrariesRecursive(info, retValue, collectedNames);
             }
             return retValue;
@@ -9682,15 +9697,16 @@
         }
     }
 
-    List<AndroidPackage> findSharedNonSystemLibraries(AndroidPackage pkg) {
-        List<SharedLibraryInfo> deps = findSharedLibraries(pkg);
+    List<PackageSetting> findSharedNonSystemLibraries(PackageSetting pkgSetting) {
+        List<SharedLibraryInfo> deps = findSharedLibraries(pkgSetting);
         if (!deps.isEmpty()) {
-            ArrayList<AndroidPackage> retValue = new ArrayList<>();
+            List<PackageSetting> retValue = new ArrayList<>();
             synchronized (mLock) {
                 for (SharedLibraryInfo info : deps) {
-                    AndroidPackage depPackage = mPackages.get(info.getPackageName());
-                    if (depPackage != null) {
-                        retValue.add(depPackage);
+                    PackageSetting depPackageSetting =
+                            mSettings.getPackageLPr(info.getPackageName());
+                    if (depPackageSetting != null && depPackageSetting.pkg != null) {
+                        retValue.add(depPackageSetting);
                     }
                 }
             }
@@ -9762,7 +9778,7 @@
     }
 
     public void shutdown() {
-        mPackageUsage.writeNow(mPackages);
+        mPackageUsage.writeNow(mSettings.mPackages);
         mCompilerStats.writeNow();
         mDexManager.writePackageDexUsageNow();
         PackageWatchdog.getInstance(mContext).writeNow();
@@ -9808,9 +9824,11 @@
         enforceSystemOrRoot("forceDexOpt");
 
         AndroidPackage pkg;
+        PackageSetting pkgSetting;
         synchronized (mLock) {
             pkg = mPackages.get(packageName);
-            if (pkg == null) {
+            pkgSetting = mSettings.getPackageLPr(packageName);
+            if (pkg == null || pkgSetting == null) {
                 throw new IllegalArgumentException("Unknown package: " + packageName);
             }
         }
@@ -9820,8 +9838,7 @@
 
             // Whoever is calling forceDexOpt wants a compiled package.
             // Don't use profiles since that may cause compilation to be skipped.
-            final int res = performDexOptInternalWithDependenciesLI(
-                    pkg,
+            final int res = performDexOptInternalWithDependenciesLI(pkg, pkgSetting,
                     new DexoptOptions(packageName,
                             getDefaultCompilerFilter(),
                             DexoptOptions.DEXOPT_FORCE | DexoptOptions.DEXOPT_BOOT_COMPLETE));
@@ -9957,7 +9974,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());
@@ -9978,40 +9995,44 @@
 
     @GuardedBy("mLock")
     private void addSharedLibraryLPr(AndroidPackage pkg, Set<String> usesLibraryFiles,
-            SharedLibraryInfo libInfo, AndroidPackage changingLib) {
+            SharedLibraryInfo libInfo, @Nullable AndroidPackage changingLib,
+            @Nullable PackageSetting changingLibSetting) {
         if (libInfo.getPath() != null) {
             usesLibraryFiles.add(libInfo.getPath());
             return;
         }
-        AndroidPackage p = mPackages.get(libInfo.getPackageName());
+        AndroidPackage pkgForCodePaths = mPackages.get(libInfo.getPackageName());
+        PackageSetting pkgSetting = mSettings.getPackageLPr(libInfo.getPackageName());
         if (changingLib != null && changingLib.getPackageName().equals(libInfo.getPackageName())) {
             // If we are doing this while in the middle of updating a library apk,
             // then we need to make sure to use that new apk for determining the
             // dependencies here.  (We haven't yet finished committing the new apk
             // to the package manager state.)
-            if (p == null || p.getPackageName().equals(changingLib.getPackageName())) {
-                p = changingLib;
+            if (pkgForCodePaths == null
+                    || pkgForCodePaths.getPackageName().equals(changingLib.getPackageName())) {
+                pkgForCodePaths = changingLib;
+                pkgSetting = changingLibSetting;
             }
         }
-        if (p != null) {
-            usesLibraryFiles.addAll(p.getAllCodePaths());
+        if (pkgForCodePaths != null) {
+            usesLibraryFiles.addAll(AndroidPackageUtils.getAllCodePaths(pkgForCodePaths));
             // If the package provides libraries, add the dependency to them.
-            applyDefiningSharedLibraryUpdateLocked(pkg, libInfo, (definingLibrary, dependency) -> {
-                definingLibrary.addDependency(dependency);
-            });
-            if (p.getUsesLibraryFiles() != null) {
-                Collections.addAll(usesLibraryFiles, p.getUsesLibraryFiles());
+            applyDefiningSharedLibraryUpdateLocked(pkg, libInfo, SharedLibraryInfo::addDependency);
+            if (pkgSetting != null) {
+                usesLibraryFiles.addAll(pkgSetting.getPkgState().getUsesLibraryFiles());
             }
         }
     }
 
     @GuardedBy("mLock")
-    private void updateSharedLibrariesLocked(AndroidPackage pkg,
-            AndroidPackage changingLib, Map<String, AndroidPackage> availablePackages)
-                    throws PackageManagerException {
-        final ArrayList<SharedLibraryInfo> sharedLibraryInfos =
-                collectSharedLibraryInfos(pkg, availablePackages, mSharedLibraries, null);
-        executeSharedLibrariesUpdateLPr(pkg, changingLib, sharedLibraryInfos);
+    private void updateSharedLibrariesLocked(AndroidPackage pkg, PackageSetting pkgSetting,
+            @Nullable AndroidPackage changingLib, @Nullable PackageSetting changingLibSetting,
+            Map<String, AndroidPackage> availablePackages)
+            throws PackageManagerException {
+        final ArrayList<SharedLibraryInfo> sharedLibraryInfos = collectSharedLibraryInfos(
+                pkgSetting.pkg, availablePackages, mSharedLibraries, null);
+        executeSharedLibrariesUpdateLPr(pkg, pkgSetting, changingLib, changingLibSetting,
+                sharedLibraryInfos);
     }
 
     private static ArrayList<SharedLibraryInfo> collectSharedLibraryInfos(AndroidPackage pkg,
@@ -10026,18 +10047,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);
@@ -10046,25 +10067,27 @@
     }
 
     private void executeSharedLibrariesUpdateLPr(AndroidPackage pkg,
-            AndroidPackage changingLib, ArrayList<SharedLibraryInfo> usesLibraryInfos) {
+            @NonNull PackageSetting pkgSetting, @Nullable AndroidPackage changingLib,
+            @Nullable PackageSetting changingLibSetting,
+            ArrayList<SharedLibraryInfo> usesLibraryInfos) {
         // If the package provides libraries, clear their old dependencies.
         // This method will set them up again.
         applyDefiningSharedLibraryUpdateLocked(pkg, null, (definingLibrary, dependency) -> {
             definingLibrary.clearDependencies();
         });
         if (usesLibraryInfos != null) {
-            pkg.mutate().setUsesLibraryInfos(usesLibraryInfos);
+            pkgSetting.getPkgState().setUsesLibraryInfos(usesLibraryInfos);
             // Use LinkedHashSet to preserve the order of files added to
             // usesLibraryFiles while eliminating duplicates.
             Set<String> usesLibraryFiles = new LinkedHashSet<>();
             for (SharedLibraryInfo libInfo : usesLibraryInfos) {
-                addSharedLibraryLPr(pkg, usesLibraryFiles, libInfo, changingLib);
+                addSharedLibraryLPr(pkg, usesLibraryFiles, libInfo, changingLib,
+                        changingLibSetting);
             }
-            pkg.mutate().setUsesLibraryFiles(usesLibraryFiles.toArray(
-                    new String[usesLibraryFiles.size()]));
+            pkgSetting.getPkgState().setUsesLibraryFiles(new ArrayList<>(usesLibraryFiles));
         } else {
-            pkg.mutate().setUsesLibraryInfos(null)
-                    .setUsesLibraryFiles(null);
+            pkgSetting.getPkgState().setUsesLibraryInfos(Collections.emptyList())
+                    .setUsesLibraryFiles(Collections.emptyList());
         }
     }
 
@@ -10180,27 +10203,32 @@
 
     @GuardedBy("mLock")
     private ArrayList<AndroidPackage> updateAllSharedLibrariesLocked(
-            AndroidPackage updatedPkg,
+            @Nullable AndroidPackage updatedPkg, @Nullable PackageSetting updatedPkgSetting,
             Map<String, AndroidPackage> availablePackages) {
         ArrayList<AndroidPackage> resultList = null;
         // Set of all descendants of a library; used to eliminate cycles
         ArraySet<String> descendants = null;
         // The current list of packages that need updating
-        ArrayList<AndroidPackage> needsUpdating = null;
-        if (updatedPkg != null) {
+        List<Pair<AndroidPackage, PackageSetting>> needsUpdating = null;
+        if (updatedPkg != null && updatedPkgSetting != null) {
             needsUpdating = new ArrayList<>(1);
-            needsUpdating.add(updatedPkg);
+            needsUpdating.add(Pair.create(updatedPkg, updatedPkgSetting));
         }
         do {
-            final AndroidPackage changingPkg =
+            final Pair<AndroidPackage, PackageSetting> changingPkgPair =
                     (needsUpdating == null) ? null : needsUpdating.remove(0);
+            final AndroidPackage changingPkg = changingPkgPair != null
+                    ? changingPkgPair.first : null;
+            final PackageSetting changingPkgSetting = changingPkgPair != null
+                    ? changingPkgPair.second : null;
             for (int i = mPackages.size() - 1; i >= 0; --i) {
                 final AndroidPackage pkg = mPackages.valueAt(i);
+                final PackageSetting pkgSetting = mSettings.getPackageLPr(pkg.getPackageName());
                 if (changingPkg != null
                         && !hasString(pkg.getUsesLibraries(), changingPkg.getLibraryNames())
                         && !hasString(pkg.getUsesOptionalLibraries(), changingPkg.getLibraryNames())
                         && !ArrayUtils.contains(pkg.getUsesStaticLibraries(),
-                                changingPkg.getStaticSharedLibName())) {
+                        changingPkg.getStaticSharedLibName())) {
                     continue;
                 }
                 if (resultList == null) {
@@ -10214,19 +10242,20 @@
                     }
                     if (!descendants.contains(pkg.getPackageName())) {
                         descendants.add(pkg.getPackageName());
-                        needsUpdating.add(pkg);
+                        needsUpdating.add(Pair.create(pkg, pkgSetting));
                     }
                 }
                 try {
-                    updateSharedLibrariesLocked(pkg, changingPkg, availablePackages);
+                    updateSharedLibrariesLocked(pkg, pkgSetting, changingPkg,
+                            changingPkgSetting, availablePackages);
                 } catch (PackageManagerException e) {
                     // If a system app update or an app and a required lib missing we
                     // delete the package and for updated system apps keep the data as
                     // it is better for the user to reinstall than to be in an limbo
                     // state. Also libs disappearing under an app should never happen
                     // - just in case.
-                    if (!pkg.isSystem() || pkg.isUpdatedSystemApp()) {
-                        final int flags = pkg.isUpdatedSystemApp()
+                    if (!pkg.isSystem() || pkgSetting.getPkgState().isUpdatedSystemApp()) {
+                        final int flags = pkgSetting.getPkgState().isUpdatedSystemApp()
                                 ? PackageManager.DELETE_KEEP_DATA : 0;
                         deletePackageLIF(pkg.getPackageName(), null, true,
                                 mUserManager.getUserIds(), flags, null,
@@ -10242,10 +10271,11 @@
     @GuardedBy({"mInstallLock", "mLock"})
     private ScanResult scanPackageTracedLI(ParsedPackage parsedPackage,
             final @ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime,
-            @Nullable UserHandle user) throws PackageManagerException {
+            @Nullable UserHandle user, String cpuAbiOverride) throws PackageManagerException {
         Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanPackage");
         try {
-            return scanPackageNewLI(parsedPackage, parseFlags, scanFlags, currentTime, user);
+            return scanPackageNewLI(parsedPackage, parseFlags, scanFlags, currentTime, user,
+                    cpuAbiOverride);
         } finally {
             Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
         }
@@ -10320,6 +10350,9 @@
         @Nullable public final UserHandle user;
         /** Whether or not the platform package is being scanned */
         public final boolean isPlatformPackage;
+        /** Override value for package ABI if set during install */
+        @Nullable
+        public final String cpuAbiOverride;
         public ScanRequest(
                 @NonNull ParsedPackage parsedPackage,
                 @Nullable SharedUserSetting sharedUserSetting,
@@ -10331,7 +10364,8 @@
                 @ParseFlags int parseFlags,
                 @ScanFlags int scanFlags,
                 boolean isPlatformPackage,
-                @Nullable UserHandle user) {
+                @Nullable UserHandle user,
+                @Nullable String cpuAbiOverride) {
             this.parsedPackage = parsedPackage;
             this.oldPkg = oldPkg;
             this.pkgSetting = pkgSetting;
@@ -10344,6 +10378,7 @@
             this.scanFlags = scanFlags;
             this.isPlatformPackage = isPlatformPackage;
             this.user = user;
+            this.cpuAbiOverride = cpuAbiOverride;
         }
     }
 
@@ -10451,7 +10486,7 @@
     @GuardedBy({"mInstallLock", "mLock"})
     private ScanResult scanPackageNewLI(@NonNull ParsedPackage parsedPackage,
             final @ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime,
-            @Nullable UserHandle user) throws PackageManagerException {
+            @Nullable UserHandle user, String cpuAbiOverride) throws PackageManagerException {
 
         final String renamedPkgName = mSettings.getRenamedPackageLPr(
                 parsedPackage.getRealPackage());
@@ -10472,7 +10507,13 @@
 
         scanFlags = adjustScanFlags(scanFlags, pkgSetting, disabledPkgSetting, user, parsedPackage);
         synchronized (mLock) {
-            applyPolicy(parsedPackage, parseFlags, scanFlags, mPlatformPackage);
+            boolean isUpdatedSystemApp;
+            if (pkgSetting != null) {
+                isUpdatedSystemApp = pkgSetting.getPkgState().isUpdatedSystemApp();
+            } else {
+                isUpdatedSystemApp = disabledPkgSetting != null;
+            }
+            applyPolicy(parsedPackage, parseFlags, scanFlags, mPlatformPackage, isUpdatedSystemApp);
             assertPackageIsValid(parsedPackage, parseFlags, scanFlags);
 
             SharedUserSetting sharedUserSetting = null;
@@ -10492,7 +10533,8 @@
             final ScanRequest request = new ScanRequest(parsedPackage, sharedUserSetting,
                     pkgSetting == null ? null : pkgSetting.pkg, pkgSetting, disabledPkgSetting,
                     originalPkgSetting, realPkgName, parseFlags, scanFlags,
-                    Objects.equals(parsedPackage.getPackageName(), platformPackageName), user);
+                    Objects.equals(parsedPackage.getPackageName(), platformPackageName), user,
+                    cpuAbiOverride);
             return scanPackageOnlyLI(request, mInjector, mFactoryTest, currentTime);
         }
     }
@@ -10594,7 +10636,8 @@
         }
 
         if (reconciledPkg.collectedSharedLibraryInfos != null) {
-            executeSharedLibrariesUpdateLPr(pkg, null, reconciledPkg.collectedSharedLibraryInfos);
+            executeSharedLibrariesUpdateLPr(pkg, pkgSetting, null, null,
+                    reconciledPkg.collectedSharedLibraryInfos);
         }
 
         final KeySetManagerService ksms = mSettings.mKeySetManagerService;
@@ -10607,7 +10650,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--) {
@@ -10661,8 +10704,7 @@
     /** Returns {@code true} if the package has been renamed. Otherwise, {@code false}. */
     private static boolean isPackageRenamed(@NonNull AndroidPackage pkg,
             @Nullable String renamedPkgName) {
-        return pkg.getOriginalPackages() != null
-                && pkg.getOriginalPackages().contains(renamedPkgName);
+        return pkg.getOriginalPackages().contains(renamedPkgName);
     }
 
     /**
@@ -10714,8 +10756,7 @@
      */
     private static void ensurePackageRenamed(@NonNull ParsedPackage parsedPackage,
             @NonNull String renamedPackageName) {
-        if (parsedPackage.getOriginalPackages() == null
-                || !parsedPackage.getOriginalPackages().contains(renamedPackageName)
+        if (!parsedPackage.getOriginalPackages().contains(renamedPackageName)
                 || parsedPackage.getPackageName().equals(renamedPackageName)) {
             return;
         }
@@ -10744,19 +10785,21 @@
                 }
 
                 ps.primaryCpuAbiString = adjustedAbi;
-                if (ps.pkg != null && !TextUtils.equals(adjustedAbi, ps.pkg.getPrimaryCpuAbi())) {
-                    ps.pkg.mutate().setPrimaryCpuAbi(adjustedAbi);
-                    if (DEBUG_ABI_SELECTION) {
-                        Slog.i(TAG,
-                                "Adjusting ABI for " + ps.name + " to " + adjustedAbi
-                                        + " (scannedPackage="
-                                        + (scannedPackage != null ? scannedPackage : "null")
-                                        + ")");
+                if (ps.pkg != null) {
+                    if (!TextUtils.equals(adjustedAbi,
+                            AndroidPackageUtils.getRawPrimaryCpuAbi(ps.pkg))) {
+                        if (DEBUG_ABI_SELECTION) {
+                            Slog.i(TAG,
+                                    "Adjusting ABI for " + ps.name + " to " + adjustedAbi
+                                            + " (scannedPackage="
+                                            + (scannedPackage != null ? scannedPackage : "null")
+                                            + ")");
+                        }
+                        if (changedAbiCodePath == null) {
+                            changedAbiCodePath = new ArrayList<>();
+                        }
+                        changedAbiCodePath.add(ps.codePathString);
                     }
-                    if (changedAbiCodePath == null) {
-                        changedAbiCodePath = new ArrayList<>();
-                    }
-                    changedAbiCodePath.add(ps.codePathString);
                 }
             }
         }
@@ -10766,6 +10809,8 @@
     /**
      * Sets the enabled state of components configured through {@link SystemConfig}.
      * This modifies the {@link PackageSetting} object.
+     *
+     * TODO(b/135203078): Move this to package parsing
      **/
     static void configurePackageComponents(AndroidPackage pkg) {
         final ArrayMap<String, Boolean> componentsEnabledStates = SystemConfig.getInstance()
@@ -10776,7 +10821,7 @@
 
         for (int i = ArrayUtils.size(pkg.getActivities()) - 1; i >= 0; i--) {
             final ParsedActivity component = pkg.getActivities().get(i);
-            final Boolean enabled = componentsEnabledStates.get(component.className);
+            final Boolean enabled = componentsEnabledStates.get(component.getName());
             if (enabled != null) {
                 component.setEnabled(enabled);
             }
@@ -10784,7 +10829,7 @@
 
         for (int i = ArrayUtils.size(pkg.getReceivers()) - 1; i >= 0; i--) {
             final ParsedActivity component = pkg.getReceivers().get(i);
-            final Boolean enabled = componentsEnabledStates.get(component.className);
+            final Boolean enabled = componentsEnabledStates.get(component.getName());
             if (enabled != null) {
                 component.setEnabled(enabled);
             }
@@ -10792,7 +10837,7 @@
 
         for (int i = ArrayUtils.size(pkg.getProviders()) - 1; i >= 0; i--) {
             final ParsedProvider component = pkg.getProviders().get(i);
-            final Boolean enabled = componentsEnabledStates.get(component.className);
+            final Boolean enabled = componentsEnabledStates.get(component.getName());
             if (enabled != null) {
                 component.setEnabled(enabled);
             }
@@ -10800,7 +10845,7 @@
 
         for (int i = ArrayUtils.size(pkg.getServices()) - 1; i >= 0; i--) {
             final ParsedService component = pkg.getServices().get(i);
-            final Boolean enabled = componentsEnabledStates.get(component.className);
+            final Boolean enabled = componentsEnabledStates.get(component.getName());
             if (enabled != null) {
                 component.setEnabled(enabled);
             }
@@ -10848,8 +10893,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,10 +10923,13 @@
         }
 
         String[] usesStaticLibraries = null;
-        if (parsedPackage.getUsesStaticLibraries() != null) {
+        if (!parsedPackage.getUsesStaticLibraries().isEmpty()) {
             usesStaticLibraries = new String[parsedPackage.getUsesStaticLibraries().size()];
             parsedPackage.getUsesStaticLibraries().toArray(usesStaticLibraries);
         }
+        // TODO(b/135203078): Remove appInfoFlag usage in favor of individually assigned booleans
+        //  to avoid adding something that's unsupported due to lack of state, since it's called
+        //  with null.
         final boolean createNewPackage = (pkgSetting == null);
         if (createNewPackage) {
             final boolean instantApp = (scanFlags & SCAN_AS_INSTANT_APP) != 0;
@@ -10890,16 +10938,18 @@
             pkgSetting = Settings.createNewSetting(parsedPackage.getPackageName(),
                     originalPkgSetting, disabledPkgSetting, realPkgName, sharedUserSetting,
                     destCodeFile, destResourceFile, parsedPackage.getNativeLibraryRootDir(),
-                    parsedPackage.getPrimaryCpuAbi(), parsedPackage.getSecondaryCpuAbi(),
-                    parsedPackage.getVersionCode(), parsedPackage.getFlags(),
-                    parsedPackage.getPrivateFlags(), user, true /*allowInstall*/, instantApp,
+                    AndroidPackageUtils.getRawPrimaryCpuAbi(parsedPackage),
+                    AndroidPackageUtils.getRawSecondaryCpuAbi(parsedPackage),
+                    parsedPackage.getVersionCode(),
+                    PackageInfoWithoutStateUtils.appInfoFlags(parsedPackage),
+                    PackageInfoWithoutStateUtils.appInfoPrivateFlags(parsedPackage),
+                    user, true /*allowInstall*/, instantApp,
                     virtualPreload, UserManagerService.getInstance(), usesStaticLibraries,
                     parsedPackage.getUsesStaticLibrariesVersions(), parsedPackage.getMimeGroups());
         } 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.
             //
@@ -10908,8 +10958,10 @@
             // to null here, only to reset them at a later point.
             Settings.updatePackageSetting(pkgSetting, disabledPkgSetting, sharedUserSetting,
                     destCodeFile, destResourceFile, parsedPackage.getNativeLibraryDir(),
-                    parsedPackage.getPrimaryCpuAbi(), parsedPackage.getSecondaryCpuAbi(),
-                    parsedPackage.getFlags(), parsedPackage.getPrivateFlags(),
+                    AndroidPackageUtils.getRawPrimaryCpuAbi(parsedPackage),
+                    AndroidPackageUtils.getRawSecondaryCpuAbi(parsedPackage),
+                    PackageInfoWithoutStateUtils.appInfoFlags(parsedPackage),
+                    PackageInfoWithoutStateUtils.appInfoPrivateFlags(parsedPackage),
                     UserManagerService.getInstance(),
                     usesStaticLibraries, parsedPackage.getUsesStaticLibrariesVersions(),
                     parsedPackage.getMimeGroups());
@@ -10938,35 +10990,28 @@
         if (disabledPkgSetting != null
                 || (0 != (scanFlags & SCAN_NEW_INSTALL)
                 && pkgSetting != null && pkgSetting.isSystem())) {
-            parsedPackage.mutate().setUpdatedSystemApp(true);
+            pkgSetting.getPkgState().setUpdatedSystemApp(true);
         }
 
         parsedPackage
                 .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()));
-
-        if (!isPlatformPackage) {
-            // Get all of our default paths setup
-            parsedPackage.initForUser(UserHandle.USER_SYSTEM);
-        }
+                        userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM : userId)));
 
         if (parsedPackage.isSystem()) {
             configurePackageComponents(parsedPackage);
         }
 
-        final String cpuAbiOverride = deriveAbiOverride(parsedPackage.getCpuAbiOverride(),
-                pkgSetting);
+        final String cpuAbiOverride = deriveAbiOverride(request.cpuAbiOverride, pkgSetting);
 
         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,
+                        packageAbiHelper.derivePackageAbi(parsedPackage,
+                                pkgSetting.getPkgState().isUpdatedSystemApp(), cpuAbiOverride,
                                 extractNativeLibs);
                 derivedAbi.first.applyTo(parsedPackage);
                 derivedAbi.second.applyTo(parsedPackage);
@@ -10975,14 +11020,16 @@
                 // Some system apps still use directory structure for native libraries
                 // in which case we might end up not detecting abi solely based on apk
                 // structure. Try to detect abi based on directory structure.
-                if (isSystemApp(parsedPackage) && !parsedPackage.isUpdatedSystemApp() &&
-                        parsedPackage.getPrimaryCpuAbi() == null) {
+
+                String pkgRawPrimaryCpuAbi = AndroidPackageUtils.getRawPrimaryCpuAbi(parsedPackage);
+                if (parsedPackage.isSystem() && !pkgSetting.getPkgState().isUpdatedSystemApp() &&
+                        pkgRawPrimaryCpuAbi == null) {
                     final PackageAbiHelper.Abis abis = packageAbiHelper.getBundledAppAbis(
                             parsedPackage);
                     abis.applyTo(parsedPackage);
                     abis.applyTo(pkgSetting);
                     final PackageAbiHelper.NativeLibraryPaths nativeLibraryPaths =
-                            packageAbiHelper.getNativeLibraryPaths(parsedPackage,
+                            packageAbiHelper.getNativeLibraryPaths(parsedPackage, pkgSetting,
                                     sAppLib32InstallDir);
                     nativeLibraryPaths.applyTo(parsedPackage);
                 }
@@ -10994,13 +11041,16 @@
                         .setSecondaryCpuAbi(secondaryCpuAbiFromSettings);
 
                 final PackageAbiHelper.NativeLibraryPaths nativeLibraryPaths =
-                        packageAbiHelper.getNativeLibraryPaths(parsedPackage, sAppLib32InstallDir);
+                        packageAbiHelper.getNativeLibraryPaths(parsedPackage,
+                                pkgSetting, sAppLib32InstallDir);
                 nativeLibraryPaths.applyTo(parsedPackage);
 
                 if (DEBUG_ABI_SELECTION) {
                     Slog.i(TAG, "Using ABIS and native lib paths from settings : " +
-                            parsedPackage.getPackageName() + " " + parsedPackage.getPrimaryCpuAbi()
-                            + ", " + parsedPackage.getSecondaryCpuAbi());
+                            parsedPackage.getPackageName() + " " +
+                            AndroidPackageUtils.getRawPrimaryCpuAbi(parsedPackage)
+                            + ", " 
+                            + AndroidPackageUtils.getRawSecondaryCpuAbi(parsedPackage));
                 }
             }
         } else {
@@ -11017,7 +11067,8 @@
             // ABIs we determined during compilation, but the path will depend on the final
             // package path (after the rename away from the stage path).
             final PackageAbiHelper.NativeLibraryPaths nativeLibraryPaths =
-                    packageAbiHelper.getNativeLibraryPaths(parsedPackage, sAppLib32InstallDir);
+                    packageAbiHelper.getNativeLibraryPaths(parsedPackage, pkgSetting,
+                            sAppLib32InstallDir);
             nativeLibraryPaths.applyTo(parsedPackage);
         }
 
@@ -11035,20 +11086,16 @@
         // would've already compiled the app without taking the package setting into
         // account.
         if ((scanFlags & SCAN_NO_DEX) == 0 && (scanFlags & SCAN_NEW_INSTALL) != 0) {
-            if (cpuAbiOverride == null && parsedPackage.getPackageName() != null) {
+            if (cpuAbiOverride == null) {
                 Slog.w(TAG, "Ignoring persisted ABI override " + cpuAbiOverride +
                         " for package " + parsedPackage.getPackageName());
             }
         }
 
-        pkgSetting.primaryCpuAbiString = parsedPackage.getPrimaryCpuAbi();
-        pkgSetting.secondaryCpuAbiString = parsedPackage.getSecondaryCpuAbi();
+        pkgSetting.primaryCpuAbiString = AndroidPackageUtils.getRawPrimaryCpuAbi(parsedPackage);
+        pkgSetting.secondaryCpuAbiString = AndroidPackageUtils.getRawSecondaryCpuAbi(parsedPackage);
         pkgSetting.cpuAbiOverrideString = cpuAbiOverride;
 
-        // Copy the derived override back to the parsed package, so that we can
-        // update the package settings accordingly.
-        parsedPackage.setCpuAbiOverride(cpuAbiOverride);
-
         if (DEBUG_ABI_SELECTION) {
             Slog.d(TAG, "Resolved nativeLibraryRoot for " + parsedPackage.getPackageName()
                     + " to root=" + parsedPackage.getNativeLibraryRootDir() + ", isa="
@@ -11061,8 +11108,8 @@
 
         if (DEBUG_ABI_SELECTION) {
             Log.d(TAG, "Abis for package[" + parsedPackage.getPackageName() + "] are" +
-                    " primary=" + parsedPackage.getPrimaryCpuAbi() +
-                    " secondary=" + parsedPackage.getSecondaryCpuAbi());
+                    " primary=" + AndroidPackageUtils.getRawPrimaryCpuAbi(parsedPackage) +
+                    " secondary=" + AndroidPackageUtils.getRawSecondaryCpuAbi(parsedPackage));
         }
 
         if ((scanFlags & SCAN_BOOTING) == 0 && pkgSetting.sharedUser != null) {
@@ -11104,13 +11151,13 @@
         }
         pkgSetting.setTimeStamp(scanFileTime);
         // TODO(b/135203078): Remove, move to constructor
-        parsedPackage.setPackageSettingCallback(pkgSetting);
-        pkgSetting.pkgFlags = parsedPackage.getFlags();
+        pkgSetting.pkg = parsedPackage;
+        pkgSetting.pkgFlags = PackageInfoUtils.appInfoFlags(parsedPackage, pkgSetting);
         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 +11169,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));
             }
         }
 
@@ -11167,7 +11215,7 @@
      */
     private static void assertCodePolicy(AndroidPackage pkg)
             throws PackageManagerException {
-        final boolean shouldHaveCode = (pkg.getFlags() & ApplicationInfo.FLAG_HAS_CODE) != 0;
+        final boolean shouldHaveCode = pkg.isHasCode();
         if (shouldHaveCode && !apkHasCode(pkg.getBaseCodePath())) {
             throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
                     "Package " + pkg.getBaseCodePath() + " code is missing");
@@ -11193,7 +11241,8 @@
      * ideally be static, but, it requires locks to read system state.
      */
     private static void applyPolicy(ParsedPackage parsedPackage, final @ParseFlags int parseFlags,
-            final @ScanFlags int scanFlags, AndroidPackage platformPkg) {
+            final @ScanFlags int scanFlags, AndroidPackage platformPkg,
+            boolean isUpdatedSystemApp) {
         if ((scanFlags & SCAN_AS_SYSTEM) != 0) {
             parsedPackage.setSystem(true);
             // TODO(b/135203078): Can this be done in PackageParser? Or just inferred when the flag
@@ -11202,7 +11251,7 @@
                 parsedPackage.setAllComponentsDirectBootAware(true);
             }
             if (compressedFileExists(parsedPackage.getCodePath())) {
-                parsedPackage.setIsStub(true);
+                parsedPackage.setStub(true);
             }
         } else {
             parsedPackage
@@ -11237,14 +11286,14 @@
                 ) == PackageManager.SIGNATURE_MATCH))
         );
 
-        if (!isSystemApp(parsedPackage)) {
+        if (!parsedPackage.isSystem()) {
             // Only system apps can use these features.
             parsedPackage.clearOriginalPackages()
                     .setRealPackage(null)
                     .clearAdoptPermissions();
         }
 
-        PackageBackwardCompatibility.modifySharedLibraries(parsedPackage);
+        PackageBackwardCompatibility.modifySharedLibraries(parsedPackage, isUpdatedSystemApp);
     }
 
     private static @NonNull <T> T assertNotNull(@Nullable T object, String message)
@@ -11255,19 +11304,19 @@
         return object;
     }
 
-    private <T extends ComponentParseUtils.ParsedMainComponent>
+    private <T extends ParsedMainComponent>
             void assertPackageProcesses(AndroidPackage pkg, List<T> components,
-            ArrayMap<String, ComponentParseUtils.ParsedProcess> procs, String compName)
+            Map<String, ParsedProcess> procs, String compName)
             throws PackageManagerException {
         if (components == null) {
             return;
         }
         for (int i = components.size() - 1; i >= 0; i--) {
-            final ComponentParseUtils.ParsedMainComponent<?> component = components.get(i);
+            final ParsedMainComponent component = components.get(i);
             if (!procs.containsKey(component.getProcessName())) {
                 throw new PackageManagerException(
                         INSTALL_FAILED_PROCESS_NOT_DEFINED,
-                        "Can't install because " + compName + " " + component.className
+                        "Can't install because " + compName + " " + component.getClassName()
                                 + "'s process attribute " + component.getProcessName()
                                 + " (in package " + pkg.getPackageName()
                                 + ") is not included in the <processes> list");
@@ -11291,8 +11340,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 +11423,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 +11527,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 +11553,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, ParsedProcess> procs = pkg.getProcesses();
+            if (!procs.isEmpty()) {
                 if (!procs.containsKey(pkg.getProcessName())) {
                     throw new PackageManagerException(
                             INSTALL_FAILED_PROCESS_NOT_DEFINED,
@@ -11761,14 +11808,16 @@
                         reconciledPkg.getCombinedAvailablePackages();
                 try {
                     // Shared libraries for the package need to be updated.
-                    updateSharedLibrariesLocked(pkg, null, combinedSigningDetails);
+                    updateSharedLibrariesLocked(pkg, pkgSetting, null, null,
+                            combinedSigningDetails);
                 } catch (PackageManagerException e) {
                     Slog.e(TAG, "updateSharedLibrariesLPr failed: ", e);
                 }
                 // Update all applications that use this library. Skip when booting
                 // since this will be done after all packages are scaned.
                 if ((scanFlags & SCAN_BOOTING) == 0) {
-                    clientLibPkgs = updateAllSharedLibrariesLocked(pkg, combinedSigningDetails);
+                    clientLibPkgs = updateAllSharedLibrariesLocked(pkg, pkgSetting,
+                            combinedSigningDetails);
                 }
             }
         }
@@ -11793,7 +11842,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 +11856,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);
             }
@@ -11855,7 +11904,7 @@
                 if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, "  Instrumentation: " + r);
             }
 
-            if (pkg.getProtectedBroadcasts() != null) {
+            if (!pkg.getProtectedBroadcasts().isEmpty()) {
                 synchronized (mProtectedBroadcasts) {
                     mProtectedBroadcasts.addAll(pkg.getProtectedBroadcasts());
                 }
@@ -11887,8 +11936,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;
@@ -12006,21 +12055,19 @@
         }
 
         r = null;
-        if ((pkg.getFlags() & ApplicationInfo.FLAG_SYSTEM) != 0) {
+        if (pkg.isSystem()) {
             // Only system apps can hold shared libraries.
-            if (pkg.getLibraryNames() != null) {
-                final int libraryNamesSize = pkg.getLibraryNames().size();
-                for (i = 0; i < libraryNamesSize; i++) {
-                    String name = pkg.getLibraryNames().get(i);
-                    if (removeSharedLibraryLPw(name, 0)) {
-                        if (DEBUG_REMOVE && chatty) {
-                            if (r == null) {
-                                r = new StringBuilder(256);
-                            } else {
-                                r.append(' ');
-                            }
-                            r.append(name);
+            final int libraryNamesSize = pkg.getLibraryNames().size();
+            for (i = 0; i < libraryNamesSize; i++) {
+                String name = pkg.getLibraryNames().get(i);
+                if (removeSharedLibraryLPw(name, 0)) {
+                    if (DEBUG_REMOVE && chatty) {
+                        if (r == null) {
+                            r = new StringBuilder(256);
+                        } else {
+                            r.append(' ');
                         }
+                        r.append(name);
                     }
                 }
             }
@@ -12431,18 +12478,12 @@
             if (pkgSetting == null || !pkgSetting.isSystem()) {
                 return;
             }
-            AndroidPackage pkg = pkgSetting.pkg;
-            if (pkg != null) {
-                pkg.mutate().setHiddenUntilInstalled(hidden);
-            }
+            pkgSetting.getPkgState().setHiddenUntilInstalled(hidden);
             final PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(packageName);
             if (disabledPs == null) {
                 return;
             }
-            pkg = disabledPs.pkg;
-            if (pkg != null) {
-                pkg.mutate().setHiddenUntilInstalled(hidden);
-            }
+            disabledPs.getPkgState().setHiddenUntilInstalled(hidden);
         }
     }
 
@@ -13464,15 +13505,15 @@
             ArrayList<IntentFilter> result = new ArrayList<>();
             for (int n=0; n<count; n++) {
                 ParsedActivity activity = pkg.getActivities().get(n);
-                if (activity.intents != null && activity.intents.size() > 0) {
-                    result.addAll(activity.intents);
+                if (activity.getIntents() != null && activity.getIntents().size() > 0) {
+                    result.addAll(activity.getIntents());
                 }
             }
             return new ParceledListSlice<IntentFilter>(result) {
                 @Override
                 protected void writeElement(IntentFilter parcelable, Parcel dest, int callFlags) {
                     // IntentFilter has final Parcelable methods, so redirect to the subclass
-                    ((ParsedActivityIntentInfo) parcelable).writeIntentInfoToParcel(dest,
+                    ((ParsedIntentInfo) parcelable).writeIntentInfoToParcel(dest,
                             callFlags);
                 }
             };
@@ -13657,9 +13698,8 @@
         // package has not opted out of backup participation.
         final boolean update = res.removedInfo != null
                 && res.removedInfo.removedPackage != null;
-        final int flags = (res.pkg == null) ? 0 : res.pkg.getFlags();
-        boolean doRestore = !update
-                && ((flags & ApplicationInfo.FLAG_ALLOW_BACKUP) != 0);
+        boolean allowBackup = res.pkg != null && res.pkg.isAllowBackup();
+        boolean doRestore = !update && allowBackup;
 
         // Set up the post-install work request bookkeeping.  This will be used
         // and cleaned up by the post-install event handling regardless of whether
@@ -13727,7 +13767,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,8 +13795,7 @@
         IRollbackManager rm = IRollbackManager.Stub.asInterface(
                 ServiceManager.getService(Context.ROLLBACK_SERVICE));
 
-        final String packageName = res.pkg.getAppInfoPackageName();
-        final String seInfo = res.pkg.getSeInfo();
+        final String packageName = res.pkg.getPackageName();
         final int[] allUsers = mUserManager.getUserIds();
         final int[] installedUsers;
 
@@ -13780,6 +13819,7 @@
                 || (data.args.installFlags & PackageManager.INSTALL_REQUEST_DOWNGRADE) != 0);
 
         if (ps != null && doSnapshotOrRestore) {
+            final String seInfo = AndroidPackageUtils.getSeInfo(res.pkg, ps);
             try {
                 rm.snapshotAndRestoreUserData(packageName, installedUsers, appId, ceDataInode,
                         seInfo, token);
@@ -13815,7 +13855,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]) {
@@ -13951,20 +13991,18 @@
         final String fromUuid;
         final String toUuid;
         final String packageName;
-        final String dataAppName;
         final int appId;
         final String seinfo;
         final int targetSdkVersion;
         final String fromCodePath;
 
         public MoveInfo(int moveId, String fromUuid, String toUuid, String packageName,
-                String dataAppName, int appId, String seinfo, int targetSdkVersion,
+                int appId, String seinfo, int targetSdkVersion,
                 String fromCodePath) {
             this.moveId = moveId;
             this.fromUuid = fromUuid;
             this.toUuid = toUuid;
             this.packageName = packageName;
-            this.dataAppName = dataAppName;
             this.appId = appId;
             this.seinfo = seinfo;
             this.targetSdkVersion = targetSdkVersion;
@@ -14200,7 +14238,7 @@
 
                 if (dataOwnerPkg != null) {
                     if (!PackageManagerServiceUtils.isDowngradePermitted(installFlags,
-                            dataOwnerPkg.getFlags())) {
+                            dataOwnerPkg.isDebuggable())) {
                         try {
                             checkDowngrade(dataOwnerPkg, pkgLite);
                         } catch (PackageManagerException e) {
@@ -14213,7 +14251,7 @@
                 if (installedPkg != null) {
                     if ((installFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) {
                         // Check for updated system application.
-                        if ((installedPkg.getFlags() & ApplicationInfo.FLAG_SYSTEM) != 0) {
+                        if (installedPkg.isSystem()) {
                             return PackageHelper.RECOMMEND_INSTALL_INTERNAL;
                         } else {
                             // If current upgrade specifies particular preference
@@ -14224,7 +14262,7 @@
                                 // App explictly prefers external. Let policy decide
                             } else {
                                 // Prefer previous location
-                                if (isExternal(installedPkg)) {
+                                if (installedPkg.isExternalStorage()) {
                                     return PackageHelper.RECOMMEND_INSTALL_EXTERNAL;
                                 }
                                 return PackageHelper.RECOMMEND_INSTALL_INTERNAL;
@@ -15000,14 +15038,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;
         }
 
@@ -15088,7 +15118,7 @@
             synchronized (mInstaller) {
                 try {
                     mInstaller.moveCompleteApp(move.fromUuid, move.toUuid, move.packageName,
-                            move.dataAppName, move.appId, move.seinfo, move.targetSdkVersion,
+                            move.appId, move.seinfo, move.targetSdkVersion,
                             move.fromCodePath);
                 } catch (InstallerException e) {
                     Slog.w(TAG, "Failed to move app", e);
@@ -15096,7 +15126,8 @@
                 }
             }
 
-            codeFile = new File(Environment.getDataAppDirectory(move.toUuid), move.dataAppName);
+            final String toPathName = new File(move.fromCodePath).getName();
+            codeFile = new File(Environment.getDataAppDirectory(move.toUuid), toPathName);
             resourceFile = codeFile;
             if (DEBUG_INSTALL) Slog.d(TAG, "codeFile after move is " + codeFile);
 
@@ -15117,14 +15148,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;
         }
 
@@ -15148,8 +15171,9 @@
         }
 
         private boolean cleanUp(String volumeUuid) {
+            final String toPathName = new File(move.fromCodePath).getName();
             final File codeFile = new File(Environment.getDataAppDirectory(volumeUuid),
-                    move.dataAppName);
+                    toPathName);
             Slog.d(TAG, "Cleaning up " + move.packageName + " on " + volumeUuid);
             final int[] userIds = mUserManager.getUserIds();
             synchronized (mInstallLock) {
@@ -15320,7 +15344,7 @@
             final PackageSetting ps = mSettings.mPackages.get(pkgName);
             final int userId = installArgs.user.getIdentifier();
             if (ps != null) {
-                if (isSystemApp(pkg)) {
+                if (pkg.isSystem()) {
                     if (DEBUG_INSTALL) {
                         Slog.d(TAG, "Implicitly enabling system package on upgrade: " + pkgName);
                     }
@@ -15349,8 +15373,8 @@
                 }
 
                 // Retrieve the overlays for shared libraries of the package.
-                if (pkg.getUsesLibraryInfos() != null) {
-                    for (SharedLibraryInfo sharedLib : pkg.getUsesLibraryInfos()) {
+                if (!ps.getPkgState().getUsesLibraryInfos().isEmpty()) {
+                    for (SharedLibraryInfo sharedLib : ps.getPkgState().getUsesLibraryInfos()) {
                         for (int currentUserId : UserManagerService.getInstance().getUserIds()) {
                             if (!sharedLib.isDynamic()) {
                                 // TODO(146804378): Support overlaying static shared libraries
@@ -15822,13 +15846,13 @@
         if (scanResult.staticSharedLibraryInfo != null) {
             return Collections.singletonList(scanResult.staticSharedLibraryInfo);
         }
-        final boolean hasDynamicLibraries =
-                (parsedPackage.getFlags() & ApplicationInfo.FLAG_SYSTEM) != 0
+        final boolean hasDynamicLibraries = parsedPackage.isSystem()
                         && scanResult.dynamicSharedLibraryInfos != null;
         if (!hasDynamicLibraries) {
             return null;
         }
-        final boolean isUpdatedSystemApp = parsedPackage.isUpdatedSystemApp();
+        final boolean isUpdatedSystemApp = scanResult.pkgSetting.getPkgState()
+                .isUpdatedSystemApp();
         // We may not yet have disabled the updated package yet, so be sure to grab the
         // current setting if that's the case.
         final PackageSetting updatedSystemPs = isUpdatedSystemApp
@@ -15925,10 +15949,13 @@
                         // 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(),
-                                getAppDexInstructionSets(oldPackage.getPrimaryCpuAbi(),
-                                        oldPackage.getSecondaryCpuAbi()));
+                                oldPackage.getCodePath(),
+                                oldPackage.getCodePath(),
+                                getAppDexInstructionSets(
+                                        AndroidPackageUtils.getPrimaryCpuAbi(oldPackage,
+                                                deletedPkgSetting),
+                                        AndroidPackageUtils.getSecondaryCpuAbi(oldPackage,
+                                                deletedPkgSetting)));
                     } else {
                         res.removedInfo.args = null;
                     }
@@ -15947,14 +15974,14 @@
 
                     // If deleted package lived in a container, give users a chance to
                     // relinquish resources before killing.
-                    if (oldPackage.isForwardLocked() || isExternal(oldPackage)) {
+                    if (oldPackage.isExternalStorage()) {
                         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);
                     }
 
@@ -16061,7 +16088,7 @@
                     final ScanResult result = scanPackageTracedLI(
                             prepareResult.packageToScan, prepareResult.parseFlags,
                             prepareResult.scanFlags, System.currentTimeMillis(),
-                            request.args.user);
+                            request.args.user, request.args.abiOverride);
                     if (null != preparedScans.put(result.pkgSetting.pkg.getPackageName(), result)) {
                         request.installResult.setError(
                                 PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE,
@@ -16194,7 +16221,7 @@
             final boolean performDexopt =
                     (!instantApp || Global.getInt(mContext.getContentResolver(),
                     Global.INSTANT_APP_DEXOPT_ENABLED, 0) != 0)
-                    && ((pkg.getFlags() & ApplicationInfo.FLAG_DEBUGGABLE) == 0)
+                    && !pkg.isDebuggable()
                     && (!onIncremental);
 
             if (performDexopt) {
@@ -16214,7 +16241,7 @@
                         REASON_INSTALL,
                         DexoptOptions.DEXOPT_BOOT_COMPLETE
                                 | DexoptOptions.DEXOPT_INSTALL_WITH_DEX_METADATA_FILE);
-                mPackageDexOptimizer.performDexOpt(pkg,
+                mPackageDexOptimizer.performDexOpt(pkg, reconciledPkg.pkgSetting,
                         null /* instructionSets */,
                         getOrCreateCompilerPackageStats(pkg),
                         mDexManager.getPackageUseInfoOrDefault(packageName),
@@ -16331,16 +16358,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 {
@@ -16375,16 +16400,8 @@
             }
         }
 
-        // If package doesn't declare API override, mark that we have an install
-        // time CPU ABI override.
-        // TODO(b/135203078): Isn't this always true because cpuAbiOverride isn't assigned during
-        //  parsing?
-        if (TextUtils.isEmpty(parsedPackage.getCpuAbiOverride())) {
-            parsedPackage.setCpuAbiOverride(args.abiOverride);
-        }
-
         String pkgName = res.name = parsedPackage.getPackageName();
-        if ((parsedPackage.getFlags() & ApplicationInfo.FLAG_TEST_ONLY) != 0) {
+        if (parsedPackage.isTestOnly()) {
             if ((installFlags & PackageManager.INSTALL_ALLOW_TEST) == 0) {
                 throw new PrepareFailure(INSTALL_FAILED_TEST_ONLY, "installPackageLI");
             }
@@ -16396,7 +16413,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);
@@ -16418,8 +16436,7 @@
             // Check if installing already existing package
             if ((installFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) {
                 String oldName = mSettings.getRenamedPackageLPr(pkgName);
-                if (parsedPackage.getOriginalPackages() != null
-                        && parsedPackage.getOriginalPackages().contains(oldName)
+                if (parsedPackage.getOriginalPackages().contains(oldName)
                         && mPackages.containsKey(oldName)) {
                     // This package is derived from an original package,
                     // and this device has been updating from that original
@@ -16454,7 +16471,7 @@
                                         + " target SDK " + oldTargetSdk + " does.");
                     }
                     // Prevent persistent apps from being updated
-                    if (((oldPackage.getFlags() & ApplicationInfo.FLAG_PERSISTENT) != 0)
+                    if (oldPackage.isPersistent()
                             && ((installFlags & PackageManager.INSTALL_STAGED) == 0)) {
                         throw new PrepareFailure(PackageManager.INSTALL_FAILED_INVALID_APK,
                                 "Package " + oldPackage.getPackageName() + " is a persistent app. "
@@ -16509,7 +16526,7 @@
                 }
 
                 if (ps.pkg != null) {
-                    systemApp = (ps.pkg.getFlags() & ApplicationInfo.FLAG_SYSTEM) != 0;
+                    systemApp = ps.pkg.isSystem();
                 }
                 res.origUsers = ps.queryInstalledUsers(mUserManager.getUserIds(), true);
             }
@@ -16521,12 +16538,12 @@
                 final BasePermission bp = mPermissionManager.getPermissionTEMP(perm.getName());
 
                 // Don't allow anyone but the system to define ephemeral permissions.
-                if ((perm.protectionLevel & PermissionInfo.PROTECTION_FLAG_INSTANT) != 0
+                if ((perm.getProtectionLevel() & PermissionInfo.PROTECTION_FLAG_INSTANT) != 0
                         && !systemApp) {
                     Slog.w(TAG, "Non-System package " + parsedPackage.getPackageName()
                             + " attempting to delcare ephemeral permission "
                             + perm.getName() + "; Removing ephemeral.");
-                    perm.protectionLevel &= ~PermissionInfo.PROTECTION_FLAG_INSTANT;
+                    perm.setProtectionLevel(perm.getProtectionLevel() & ~PermissionInfo.PROTECTION_FLAG_INSTANT);
                 }
 
                 // Check whether the newly-scanned package wants to define an already-defined perm
@@ -16587,14 +16604,14 @@
                         // type as this would allow a privilege escalation where an app adds a
                         // normal/signature permission in other app's group and later redefines
                         // it as dangerous leading to the group auto-grant.
-                        if ((perm.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE)
+                        if ((perm.getProtectionLevel() & PermissionInfo.PROTECTION_MASK_BASE)
                                 == PermissionInfo.PROTECTION_DANGEROUS) {
                             if (bp != null && !bp.isRuntime()) {
                                 Slog.w(TAG, "Package " + parsedPackage.getPackageName()
                                         + " trying to change a non-runtime permission "
                                         + perm.getName()
                                         + " to runtime; keeping old protection level");
-                                perm.protectionLevel = bp.getProtectionLevel();
+                                perm.setProtectionLevel(bp.getProtectionLevel());
                             }
                         }
                     }
@@ -16637,12 +16654,22 @@
             scanFlags |= SCAN_NO_DEX;
 
             try {
-                String abiOverride = (TextUtils.isEmpty(parsedPackage.getCpuAbiOverride())
-                        ? args.abiOverride : parsedPackage.getCpuAbiOverride());
-                final boolean extractNativeLibs = !parsedPackage.isLibrary();
+                final boolean extractNativeLibs = !AndroidPackageUtils.isLibrary(parsedPackage);
+                PackageSetting pkgSetting;
+                synchronized (mLock) {
+                    pkgSetting = mSettings.getPackageLPr(pkgName);
+                }
+                String abiOverride =
+                        (pkgSetting == null || TextUtils.isEmpty(pkgSetting.cpuAbiOverrideString)
+                        ? args.abiOverride : pkgSetting.cpuAbiOverrideString);
+                boolean isUpdatedSystemAppFromExistingSetting = pkgSetting != null
+                        && pkgSetting.getPkgState().isUpdatedSystemApp();
+                AndroidPackage oldPackage = mPackages.get(pkgName);
+                boolean isUpdatedSystemAppInferred = oldPackage != null && oldPackage.isSystem();
                 final Pair<PackageAbiHelper.Abis, PackageAbiHelper.NativeLibraryPaths>
-                        derivedAbi = mInjector.getAbiHelper().derivePackageAbi(
-                                parsedPackage, abiOverride, extractNativeLibs);
+                        derivedAbi = mInjector.getAbiHelper().derivePackageAbi(parsedPackage,
+                        isUpdatedSystemAppFromExistingSetting || isUpdatedSystemAppInferred,
+                        abiOverride, extractNativeLibs);
                 derivedAbi.first.applyTo(parsedPackage);
                 derivedAbi.second.applyTo(parsedPackage);
             } catch (PackageManagerException pme) {
@@ -16817,14 +16844,14 @@
                     res.removedInfo.installReasons.put(userId, ps.getInstallReason(userId));
                 }
 
-                sysPkg = (isSystemApp(oldPackage));
+                sysPkg = oldPackage.isSystem();
                 if (sysPkg) {
                     // Set the system/privileged/oem/vendor/product flags as needed
-                    final boolean privileged = isPrivilegedApp(oldPackage);
-                    final boolean oem = isOemApp(oldPackage);
-                    final boolean vendor = isVendorApp(oldPackage);
-                    final boolean product = isProductApp(oldPackage);
-                    final boolean odm = isOdmApp(oldPackage);
+                    final boolean privileged = oldPackage.isPrivileged();
+                    final boolean oem = oldPackage.isOem();
+                    final boolean vendor = oldPackage.isVendor();
+                    final boolean product = oldPackage.isProduct();
+                    final boolean odm = oldPackage.isOdm();
                     final @ParseFlags int systemParseFlags = parseFlags;
                     final @ScanFlags int systemScanFlags = scanFlags
                             | SCAN_AS_SYSTEM
@@ -16839,7 +16866,7 @@
                                 + ", old=" + oldPackage);
                     }
                     res.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
-                    parsedPackage.setUpdatedSystemApp(true);
+                    ps.getPkgState().setUpdatedSystemApp(true);
                     targetParseFlags = systemParseFlags;
                     targetScanFlags = systemScanFlags;
                 } else { // non system replace
@@ -17006,7 +17033,7 @@
         Message msg = mHandler.obtainMessage(START_INTENT_FILTER_VERIFICATIONS);
         msg.obj = new IFVerificationParams(
                 pkg.getPackageName(),
-                hasDomainURLs(pkg),
+                pkg.isHasDomainUrls(),
                 pkg.getActivities(),
                 replacing,
                 userId,
@@ -17058,11 +17085,12 @@
             // examine handling policy even if not re-verifying.
             boolean needToVerify = false;
             for (ParsedActivity a : activities) {
-                for (ParsedActivityIntentInfo filter : a.intents) {
+                for (ParsedIntentInfo filter : a.getIntents()) {
                     if (filter.handlesWebUris(true)) {
                         handlesWebUris = true;
                     }
-                    if (filter.needsVerification() && needsNetworkVerificationLPr(filter)) {
+                    if (filter.needsVerification()
+                            && needsNetworkVerificationLPr(a.getPackageName())) {
                         if (DEBUG_DOMAIN_VERIFICATION) {
                             Slog.d(TAG,
                                     "Intent filter needs verification, so processing all filters");
@@ -17082,8 +17110,9 @@
             if (needToVerify) {
                 final int verificationId = mIntentFilterVerificationToken++;
                 for (ParsedActivity a : activities) {
-                    for (ParsedActivityIntentInfo filter : a.intents) {
-                        if (filter.handlesWebUris(true) && needsNetworkVerificationLPr(filter)) {
+                    for (ParsedIntentInfo filter : a.getIntents()) {
+                        if (filter.handlesWebUris(true)
+                                && needsNetworkVerificationLPr(a.getPackageName())) {
                             if (DEBUG_DOMAIN_VERIFICATION) Slog.d(TAG,
                                     "Verification needed for IntentFilter:" + filter.toString());
                             mIntentFilterVerifier.addOneIntentFilterVerification(
@@ -17118,9 +17147,7 @@
     }
 
     @GuardedBy("mLock")
-    private boolean needsNetworkVerificationLPr(ParsedActivityIntentInfo filter) {
-        final String packageName = filter.getPackageName();
-
+    private boolean needsNetworkVerificationLPr(String packageName) {
         IntentFilterVerificationInfo ivi = mSettings.getIntentFilterVerificationLPr(
                 packageName);
         if (ivi == null) {
@@ -17139,47 +17166,10 @@
         }
     }
 
-    private static boolean isExternal(AndroidPackage pkg) {
-        return (pkg.getFlags() & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0;
-    }
-
     private static boolean isExternal(PackageSetting ps) {
         return (ps.pkgFlags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0;
     }
 
-    static boolean isSystemApp(AndroidPackage pkg) {
-        return (pkg.getFlags() & ApplicationInfo.FLAG_SYSTEM) != 0;
-    }
-
-    private static boolean isPrivilegedApp(AndroidPackage pkg) {
-        return (pkg.getPrivateFlags() & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
-    }
-
-    private static boolean isOemApp(AndroidPackage pkg) {
-        return (pkg.getPrivateFlags() & ApplicationInfo.PRIVATE_FLAG_OEM) != 0;
-    }
-
-    private static boolean isVendorApp(AndroidPackage pkg) {
-        return (pkg.getPrivateFlags() & ApplicationInfo.PRIVATE_FLAG_VENDOR) != 0;
-    }
-
-    private static boolean isProductApp(AndroidPackage pkg) {
-        return (pkg.getPrivateFlags() & ApplicationInfo.PRIVATE_FLAG_PRODUCT) != 0;
-    }
-
-    private static boolean isSystemExtApp(AndroidPackage pkg) {
-        return (pkg.getPrivateFlags()
-                & ApplicationInfo.PRIVATE_FLAG_SYSTEM_EXT) != 0;
-    }
-
-    private static boolean isOdmApp(AndroidPackage pkg) {
-        return (pkg.getPrivateFlags() & ApplicationInfo.PRIVATE_FLAG_ODM) != 0;
-    }
-
-    private static boolean hasDomainURLs(AndroidPackage pkg) {
-        return (pkg.getPrivateFlags() & ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS) != 0;
-    }
-
     private static boolean isSystemApp(PackageSetting ps) {
         return (ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0;
     }
@@ -17189,7 +17179,7 @@
     }
 
     private VersionInfo getSettingsVersionForPackage(AndroidPackage pkg) {
-        if (isExternal(pkg)) {
+        if (pkg.isExternalStorage()) {
             if (TextUtils.isEmpty(pkg.getVolumeUuid())) {
                 return mSettings.getExternalVersion();
             } else {
@@ -17649,10 +17639,11 @@
             final AndroidPackage stubPkg =
                     (disabledSystemPs == null) ? null : disabledSystemPs.pkg;
             if (stubPkg != null && stubPkg.isStub()) {
+                final PackageSetting stubPs;
                 synchronized (mLock) {
                     // restore the enabled state of the stub; the state is overwritten when
                     // the stub is uninstalled
-                    final PackageSetting stubPs = mSettings.mPackages.get(stubPkg.getPackageName());
+                    stubPs = mSettings.getPackageLPr(stubPkg.getPackageName());
                     if (stubPs != null) {
                         stubPs.setEnabled(origEnabledState, userId, "android");
                     }
@@ -17663,7 +17654,7 @@
                         Slog.i(TAG, "Enabling system stub after removal; pkg: "
                                 + stubPkg.getPackageName());
                     }
-                    enableCompressedPackage(stubPkg);
+                    enableCompressedPackage(stubPkg, stubPs);
                 }
             }
         }
@@ -18046,9 +18037,12 @@
         final AndroidPackage pkg =
                 scanPackageTracedLI(codePath, parseFlags, scanFlags, 0 /*currentTime*/, null);
 
+        PackageSetting pkgSetting = mSettings.getPackageLPr(pkg.getPackageName());
+
         try {
             // update shared libraries for the newly re-installed system package
-            updateSharedLibrariesLocked(pkg, null, Collections.unmodifiableMap(mPackages));
+            updateSharedLibrariesLocked(pkg, pkgSetting, null, null,
+                    Collections.unmodifiableMap(mPackages));
         } catch (PackageManagerException e) {
             Slog.e(TAG, "updateAllSharedLibrariesLPw failed: " + e.getMessage());
         }
@@ -18479,10 +18473,11 @@
 
         // Try finding details about the requested package
         AndroidPackage pkg;
+        PackageSetting ps;
         synchronized (mLock) {
             pkg = mPackages.get(packageName);
+            ps = mSettings.mPackages.get(packageName);
             if (pkg == null) {
-                final PackageSetting ps = mSettings.mPackages.get(packageName);
                 if (ps != null) {
                     pkg = ps.pkg;
                 }
@@ -18509,7 +18504,7 @@
         } else {
             flags = 0;
         }
-        prepareAppDataContentsLIF(pkg, userId, flags);
+        prepareAppDataContentsLIF(pkg, ps, userId, flags);
 
         return true;
     }
@@ -19966,7 +19961,7 @@
             if (isSystemStub
                     && (newState == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT
                             || newState == PackageManager.COMPONENT_ENABLED_STATE_ENABLED)) {
-                if (!enableCompressedPackage(deletedPkg)) {
+                if (!enableCompressedPackage(deletedPkg, pkgSetting)) {
                     return;
                 }
             }
@@ -19983,7 +19978,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) {
@@ -21216,24 +21211,27 @@
         ipw.println();
         ipw.println("Dexopt state:");
         ipw.increaseIndent();
-        Collection<AndroidPackage> packages;
+        Collection<PackageSetting> pkgSettings;
         if (packageName != null) {
-            AndroidPackage targetPackage = mPackages.get(packageName);
-            if (targetPackage != null) {
-                packages = Collections.singletonList(targetPackage);
+            PackageSetting targetPkgSetting = mSettings.mPackages.get(packageName);
+            if (targetPkgSetting != null) {
+                pkgSettings = Collections.singletonList(targetPkgSetting);
             } else {
                 ipw.println("Unable to find package: " + packageName);
                 return;
             }
         } else {
-            packages = mPackages.values();
+            pkgSettings = mSettings.mPackages.values();
         }
 
-        for (AndroidPackage pkg : packages) {
-            ipw.println("[" + pkg.getPackageName() + "]");
+        for (PackageSetting pkgSetting : pkgSettings) {
+            if (pkgSetting.pkg == null) {
+                continue;
+            }
+            ipw.println("[" + pkgSetting.name + "]");
             ipw.increaseIndent();
-            mPackageDexOptimizer.dumpDexoptState(ipw, pkg,
-                    mDexManager.getPackageUseInfoOrDefault(pkg.getPackageName()));
+            mPackageDexOptimizer.dumpDexoptState(ipw, pkgSetting.pkg, pkgSetting,
+                    mDexManager.getPackageUseInfoOrDefault(pkgSetting.pkg.getPackageName()));
             ipw.decreaseIndent();
         }
     }
@@ -21339,7 +21337,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,
@@ -21803,16 +21801,17 @@
 
         final int appId = UserHandle.getAppId(pkg.getUid());
 
-        Preconditions.checkNotNull(pkg.getSeInfo());
+        String pkgSeInfo = AndroidPackageUtils.getSeInfo(pkg, ps);
 
-        final String seInfo =
-                pkg.getSeInfo() + (pkg.getSeInfoUser() != null ? pkg.getSeInfoUser() : "");
+        Preconditions.checkNotNull(pkgSeInfo);
+
+        final String seInfo = pkgSeInfo + (pkg.getSeInfoUser() != null ? pkg.getSeInfoUser() : "");
         long ceDataInode = -1;
         try {
             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);
@@ -21857,18 +21856,20 @@
             }
         }
 
-        prepareAppDataContentsLeafLIF(pkg, userId, flags);
+        prepareAppDataContentsLeafLIF(pkg, ps, userId, flags);
     }
 
-    private void prepareAppDataContentsLIF(AndroidPackage pkg, int userId, int flags) {
+    private void prepareAppDataContentsLIF(AndroidPackage pkg, @Nullable PackageSetting pkgSetting,
+            int userId, int flags) {
         if (pkg == null) {
             Slog.wtf(TAG, "Package was null!", new Throwable());
             return;
         }
-        prepareAppDataContentsLeafLIF(pkg, userId, flags);
+        prepareAppDataContentsLeafLIF(pkg, pkgSetting, userId, flags);
     }
 
-    private void prepareAppDataContentsLeafLIF(AndroidPackage pkg, int userId, int flags) {
+    private void prepareAppDataContentsLeafLIF(AndroidPackage pkg,
+            @Nullable PackageSetting pkgSetting, int userId, int flags) {
         final String volumeUuid = pkg.getVolumeUuid();
         final String packageName = pkg.getPackageName();
 
@@ -21876,7 +21877,8 @@
             // Create a native library symlink only if we have native libraries
             // and if the native libraries are 32 bit libraries. We do not provide
             // this symlink for 64 bit libraries.
-            if (pkg.getPrimaryCpuAbi() != null && !VMRuntime.is64BitAbi(pkg.getPrimaryCpuAbi())) {
+            String primaryCpuAbi = AndroidPackageUtils.getPrimaryCpuAbi(pkg, pkgSetting);
+            if (primaryCpuAbi != null && !VMRuntime.is64BitAbi(primaryCpuAbi)) {
                 final String nativeLibPath = pkg.getNativeLibraryDir();
                 try {
                     mInstaller.linkNativeLibraryDirectory(volumeUuid, packageName,
@@ -22065,7 +22067,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");
             }
@@ -22091,7 +22093,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");
             }
@@ -22101,17 +22103,21 @@
                         "Failed to move already frozen package");
             }
 
-            isCurrentLocationExternal = isExternal(pkg);
+            isCurrentLocationExternal = pkg.isExternalStorage();
             codeFile = new File(pkg.getCodePath());
             installSource = ps.installSource;
             packageAbiOverride = ps.cpuAbiOverrideString;
             appId = UserHandle.getAppId(pkg.getUid());
-            seinfo = pkg.getSeInfo();
+            seinfo = AndroidPackageUtils.getSeInfo(pkg, ps);
             label = String.valueOf(pm.getApplicationLabel(pkg.toAppInfoWithoutState()));
             targetSdkVersion = pkg.getTargetSdkVersion();
             freezer = freezePackage(packageName, "movePackageInternal");
             installedUserIds = ps.queryInstalledUsers(mUserManager.getUserIds(), true);
-            fromCodePath = pkg.getCodePath();
+            if (codeFile.getParentFile().getName().startsWith(RANDOM_DIR_PREFIX)) {
+                fromCodePath = codeFile.getParentFile().getAbsolutePath();
+            } else {
+                fromCodePath = codeFile.getAbsolutePath();
+            }
         }
 
         final Bundle extras = new Bundle();
@@ -22238,9 +22244,8 @@
                 }
             }).start();
 
-            final String dataAppName = codeFile.getName();
             move = new MoveInfo(moveId, currentVolumeUuid, volumeUuid, packageName,
-                    dataAppName, appId, seinfo, targetSdkVersion, fromCodePath);
+                    appId, seinfo, targetSdkVersion, fromCodePath);
         } else {
             move = null;
         }
@@ -22281,15 +22286,15 @@
 
         final StorageManager storage = mInjector.getStorageManager();;
         VolumeInfo volume = storage.findVolumeByUuid(pkg.getStorageUuid().toString());
-        int packageExternalStorageType = getPackageExternalStorageType(volume, isExternal(pkg));
+        int packageExternalStorageType = getPackageExternalStorageType(volume, pkg.isExternalStorage());
 
-        if (!isPreviousLocationExternal && isExternal(pkg)) {
+        if (!isPreviousLocationExternal && pkg.isExternalStorage()) {
             // Move from internal to external storage.
             FrameworkStatsLog.write(FrameworkStatsLog.APP_MOVED_STORAGE_REPORTED,
                     packageExternalStorageType,
                     FrameworkStatsLog.APP_MOVED_STORAGE_REPORTED__MOVE_TYPE__TO_EXTERNAL,
                     packageName);
-        } else if (isPreviousLocationExternal && !isExternal(pkg)) {
+        } else if (isPreviousLocationExternal && !pkg.isExternalStorage()) {
             // Move from external to internal storage.
             FrameworkStatsLog.write(FrameworkStatsLog.APP_MOVED_STORAGE_REPORTED,
                     packageExternalStorageType,
@@ -23013,7 +23018,7 @@
         }
 
         @Override
-        public Object getDisabledSystemPackage(@NonNull String packageName) {
+        public PackageSetting getDisabledSystemPackage(@NonNull String packageName) {
             synchronized (mLock) {
                 return mSettings.getDisabledSystemPkgLPr(packageName);
             }
@@ -23363,7 +23368,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);
@@ -23455,11 +23460,7 @@
         public boolean isPackagePersistent(String packageName) {
             synchronized (mLock) {
                 AndroidPackage pkg = mPackages.get(packageName);
-                return pkg != null
-                        ? ((pkg.getFlags() & (ApplicationInfo.FLAG_SYSTEM
-                                        | ApplicationInfo.FLAG_PERSISTENT)) ==
-                                (ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_PERSISTENT))
-                        : false;
+                return pkg != null && pkg.isSystem() && pkg.isPersistent();
             }
         }
 
@@ -23690,6 +23691,15 @@
         }
 
         @Override
+        public void forEachPackageSetting(Consumer<PackageSetting> actionLocked) {
+            synchronized (mLock) {
+                for (int index = 0; index < mSettings.mPackages.size(); index++) {
+                    actionLocked.accept(mSettings.mPackages.valueAt(index));
+                }
+            }
+        }
+
+        @Override
         public void forEachInstalledPackage(@NonNull Consumer<AndroidPackage> actionLocked,
                 @UserIdInt int userId) {
             PackageManagerService.this.forEachInstalledPackage(actionLocked, userId);
@@ -24185,15 +24195,18 @@
     boolean canHaveOatDir(String packageName) {
         synchronized (mLock) {
             AndroidPackage p = mPackages.get(packageName);
-            if (p == null) {
+            PackageSetting pkgSetting = mSettings.getPackageLPr(packageName);
+            if (p == null || pkgSetting == null) {
                 return false;
             }
-            return p.canHaveOatDir();
+            return AndroidPackageUtils.canHaveOatDir(p,
+                    pkgSetting.getPkgState().isUpdatedSystemApp());
         }
     }
 
-    private String getOatDir(AndroidPackage pkg) {
-        if (!pkg.canHaveOatDir()) {
+    private String getOatDir(AndroidPackage pkg, @NonNull PackageSetting pkgSetting) {
+        if (!AndroidPackageUtils.canHaveOatDir(pkg,
+                pkgSetting.getPkgState().isUpdatedSystemApp())) {
             return null;
         }
         File codePath = new File(pkg.getCodePath());
@@ -24208,13 +24221,16 @@
         final List<String> codePaths;
         final String oatDir;
         final AndroidPackage pkg;
+        final PackageSetting pkgSetting;
         synchronized (mLock) {
             pkg = mPackages.get(packageName);
+            pkgSetting = mSettings.getPackageLPr(packageName);
         }
-        instructionSets = getAppDexInstructionSets(pkg.getPrimaryCpuAbi(),
-                pkg.getSecondaryCpuAbi());
-        codePaths = pkg.getAllCodePaths();
-        oatDir = getOatDir(pkg);
+        instructionSets = getAppDexInstructionSets(
+                AndroidPackageUtils.getPrimaryCpuAbi(pkg, pkgSetting),
+                AndroidPackageUtils.getSecondaryCpuAbi(pkg, pkgSetting));
+        codePaths = AndroidPackageUtils.getAllCodePaths(pkg);
+        oatDir = getOatDir(pkg, pkgSetting);
 
         for (String codePath : codePaths) {
             for (String isa : instructionSets) {
@@ -24241,8 +24257,8 @@
                 if (PackageManagerServiceUtils
                         .isUnusedSinceTimeInMillis(ps.firstInstallTime, currentTimeInMillis,
                                 downgradeTimeThresholdMillis, packageUseInfo,
-                                pkg.getLatestPackageUseTimeInMills(),
-                                pkg.getLatestForegroundPackageUseTimeInMills())) {
+                                ps.getPkgState().getLatestPackageUseTimeInMills(),
+                                ps.getPkgState().getLatestForegroundPackageUseTimeInMills())) {
                     unusedPackages.add(pkg.getPackageName());
                 }
             }
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index a9035b2..91afd84 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;
@@ -94,6 +94,8 @@
 import java.util.Date;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Map;
+import java.util.Set;
 import java.util.function.Predicate;
 import java.util.zip.GZIPInputStream;
 
@@ -105,6 +107,9 @@
 public class PackageManagerServiceUtils {
     private final static long SEVEN_DAYS_IN_MILLISECONDS = 7 * 24 * 60 * 60 * 1000;
 
+    public final static Predicate<PackageSetting> REMOVE_IF_NULL_PKG =
+            pkgSetting -> pkgSetting.pkg == null;
+
     private static ArraySet<String> getPackageNamesForIntent(Intent intent, int userId) {
         List<ResolveInfo> ris = null;
         try {
@@ -124,40 +129,43 @@
     // Sort a list of apps by their last usage, most recently used apps first. The order of
     // packages without usage data is undefined (but they will be sorted after the packages
     // that do have usage data).
-    public static void sortPackagesByUsageDate(List<AndroidPackage> pkgs,
+    public static void sortPackagesByUsageDate(List<PackageSetting> pkgSettings,
             PackageManagerService packageManagerService) {
         if (!packageManagerService.isHistoricalPackageUsageAvailable()) {
             return;
         }
 
-        Collections.sort(pkgs, (pkg1, pkg2) ->
-                Long.compare(pkg2.getLatestForegroundPackageUseTimeInMills(),
-                        pkg1.getLatestForegroundPackageUseTimeInMills()));
+        Collections.sort(pkgSettings, (pkgSetting1, pkgSetting2) ->
+                Long.compare(
+                        pkgSetting2.getPkgState().getLatestForegroundPackageUseTimeInMills(),
+                        pkgSetting1.getPkgState().getLatestForegroundPackageUseTimeInMills())
+        );
     }
 
     // Apply the given {@code filter} to all packages in {@code packages}. If tested positive, the
     // package will be removed from {@code packages} and added to {@code result} with its
     // dependencies. If usage data is available, the positive packages will be sorted by usage
     // data (with {@code sortTemp} as temporary storage).
-    private static void applyPackageFilter(Predicate<AndroidPackage> filter,
-            Collection<AndroidPackage> result,
-            Collection<AndroidPackage> packages,
-            @NonNull List<AndroidPackage> sortTemp,
+    private static void applyPackageFilter(
+            Predicate<PackageSetting> filter,
+            Collection<PackageSetting> result,
+            Collection<PackageSetting> packages,
+            @NonNull List<PackageSetting> sortTemp,
             PackageManagerService packageManagerService) {
-        for (AndroidPackage pkg : packages) {
-            if (filter.test(pkg)) {
-                sortTemp.add(pkg);
+        for (PackageSetting pkgSetting : packages) {
+            if (filter.test(pkgSetting)) {
+                sortTemp.add(pkgSetting);
             }
         }
 
         sortPackagesByUsageDate(sortTemp, packageManagerService);
         packages.removeAll(sortTemp);
 
-        for (AndroidPackage pkg : sortTemp) {
-            result.add(pkg);
+        for (PackageSetting pkgSetting : sortTemp) {
+            result.add(pkgSetting);
 
-            Collection<AndroidPackage> deps =
-                    packageManagerService.findSharedNonSystemLibraries(pkg);
+            List<PackageSetting> deps =
+                    packageManagerService.findSharedNonSystemLibraries(pkgSetting);
             if (!deps.isEmpty()) {
                 deps.removeAll(result);
                 result.addAll(deps);
@@ -170,74 +178,79 @@
 
     // Sort apps by importance for dexopt ordering. Important apps are given
     // more priority in case the device runs out of space.
-    public static List<AndroidPackage> getPackagesForDexopt(
-            Collection<AndroidPackage> packages,
+    public static List<PackageSetting> getPackagesForDexopt(
+            Collection<PackageSetting> packages,
             PackageManagerService packageManagerService) {
         return getPackagesForDexopt(packages, packageManagerService, DEBUG_DEXOPT);
     }
 
-    public static List<AndroidPackage> getPackagesForDexopt(
-            Collection<AndroidPackage> packages,
+    public static List<PackageSetting> getPackagesForDexopt(
+            Collection<PackageSetting> pkgSettings,
             PackageManagerService packageManagerService,
             boolean debug) {
-        ArrayList<AndroidPackage> remainingPkgs = new ArrayList<>(packages);
-        LinkedList<AndroidPackage> result = new LinkedList<>();
-        ArrayList<AndroidPackage> sortTemp = new ArrayList<>(remainingPkgs.size());
+        List<PackageSetting> result = new LinkedList<>();
+        ArrayList<PackageSetting> remainingPkgSettings = new ArrayList<>(pkgSettings);
+
+        // First, remove all settings without available packages
+        remainingPkgSettings.removeIf(REMOVE_IF_NULL_PKG);
+
+        ArrayList<PackageSetting> sortTemp = new ArrayList<>(remainingPkgSettings.size());
 
         // Give priority to core apps.
-        applyPackageFilter((pkg) -> pkg.isCoreApp(), result, remainingPkgs, sortTemp,
+        applyPackageFilter(pkgSetting -> pkgSetting.pkg.isCoreApp(), result, remainingPkgSettings, sortTemp,
                 packageManagerService);
 
         // Give priority to system apps that listen for pre boot complete.
         Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED);
         final ArraySet<String> pkgNames = getPackageNamesForIntent(intent, UserHandle.USER_SYSTEM);
-        applyPackageFilter((pkg) -> pkgNames.contains(pkg.getPackageName()), result, remainingPkgs,
-                sortTemp, packageManagerService);
+        applyPackageFilter(pkgSetting -> pkgNames.contains(pkgSetting.name), result,
+                remainingPkgSettings, sortTemp, packageManagerService);
 
         // Give priority to apps used by other apps.
         DexManager dexManager = packageManagerService.getDexManager();
-        applyPackageFilter((pkg) ->
-                dexManager.getPackageUseInfoOrDefault(pkg.getPackageName())
+        applyPackageFilter(pkgSetting ->
+                dexManager.getPackageUseInfoOrDefault(pkgSetting.name)
                         .isAnyCodePathUsedByOtherApps(),
-                result, remainingPkgs, sortTemp, packageManagerService);
+                result, remainingPkgSettings, sortTemp, packageManagerService);
 
         // Filter out packages that aren't recently used, add all remaining apps.
         // TODO: add a property to control this?
-        Predicate<AndroidPackage> remainingPredicate;
-        if (!remainingPkgs.isEmpty() && packageManagerService.isHistoricalPackageUsageAvailable()) {
+        Predicate<PackageSetting> remainingPredicate;
+        if (!remainingPkgSettings.isEmpty() && packageManagerService.isHistoricalPackageUsageAvailable()) {
             if (debug) {
                 Log.i(TAG, "Looking at historical package use");
             }
             // Get the package that was used last.
-            AndroidPackage lastUsed = Collections.max(remainingPkgs, (pkg1, pkg2) ->
-                    Long.compare(pkg1.getLatestForegroundPackageUseTimeInMills(),
-                            pkg2.getLatestForegroundPackageUseTimeInMills()));
+            PackageSetting lastUsed = Collections.max(remainingPkgSettings,
+                    (pkgSetting1, pkgSetting2) -> Long.compare(
+                            pkgSetting1.getPkgState().getLatestForegroundPackageUseTimeInMills(),
+                            pkgSetting2.getPkgState().getLatestForegroundPackageUseTimeInMills()));
             if (debug) {
-                Log.i(TAG, "Taking package " + lastUsed.getPackageName()
+                Log.i(TAG, "Taking package " + lastUsed.name
                         + " as reference in time use");
             }
-            long estimatedPreviousSystemUseTime =
-                    lastUsed.getLatestForegroundPackageUseTimeInMills();
+            long estimatedPreviousSystemUseTime = lastUsed.getPkgState()
+                    .getLatestForegroundPackageUseTimeInMills();
             // Be defensive if for some reason package usage has bogus data.
             if (estimatedPreviousSystemUseTime != 0) {
                 final long cutoffTime = estimatedPreviousSystemUseTime - SEVEN_DAYS_IN_MILLISECONDS;
-                remainingPredicate =
-                        (pkg) -> pkg.getLatestForegroundPackageUseTimeInMills() >= cutoffTime;
+                remainingPredicate = pkgSetting -> pkgSetting.getPkgState()
+                        .getLatestForegroundPackageUseTimeInMills() >= cutoffTime;
             } else {
                 // No meaningful historical info. Take all.
-                remainingPredicate = (pkg) -> true;
+                remainingPredicate = pkgSetting -> true;
             }
-            sortPackagesByUsageDate(remainingPkgs, packageManagerService);
+            sortPackagesByUsageDate(remainingPkgSettings, packageManagerService);
         } else {
             // No historical info. Take all.
-            remainingPredicate = (pkg) -> true;
+            remainingPredicate = pkgSetting -> true;
         }
-        applyPackageFilter(remainingPredicate, result, remainingPkgs, sortTemp,
+        applyPackageFilter(remainingPredicate, result, remainingPkgSettings, sortTemp,
                 packageManagerService);
 
         if (debug) {
             Log.i(TAG, "Packages to be dexopted: " + packagesToString(result));
-            Log.i(TAG, "Packages skipped from dexopt: " + packagesToString(remainingPkgs));
+            Log.i(TAG, "Packages skipped from dexopt: " + packagesToString(remainingPkgSettings));
         }
 
         return result;
@@ -290,13 +303,13 @@
         }
     }
 
-    public static String packagesToString(Collection<AndroidPackage> c) {
+    public static String packagesToString(List<PackageSetting> pkgSettings) {
         StringBuilder sb = new StringBuilder();
-        for (AndroidPackage pkg : c) {
+        for (int index = 0; index < pkgSettings.size(); index++) {
             if (sb.length() > 0) {
                 sb.append(", ");
             }
-            sb.append(pkg.getPackageName());
+            sb.append(pkgSettings.get(index).name);
         }
         return sb.toString();
     }
@@ -543,23 +556,16 @@
      */
     private static boolean matchSignatureInSystem(PackageSetting pkgSetting,
             PackageSetting disabledPkgSetting) {
-        try {
-            ApkParseUtils.collectCertificates(disabledPkgSetting.pkg, true /* skipVerify */);
-            if (pkgSetting.signatures.mSigningDetails.checkCapability(
-                    disabledPkgSetting.signatures.mSigningDetails,
-                    PackageParser.SigningDetails.CertCapabilities.INSTALLED_DATA)
-                    || disabledPkgSetting.signatures.mSigningDetails.checkCapability(
-                            pkgSetting.signatures.mSigningDetails,
-                            PackageParser.SigningDetails.CertCapabilities.ROLLBACK)) {
-                return true;
-            } else {
-                logCriticalInfo(Log.ERROR, "Updated system app mismatches cert on /system: " +
-                        pkgSetting.name);
-                return false;
-            }
-        } catch (PackageParserException e) {
-            logCriticalInfo(Log.ERROR, "Failed to collect cert for " + pkgSetting.name + ": " +
-                    e.getMessage());
+        if (pkgSetting.signatures.mSigningDetails.checkCapability(
+                disabledPkgSetting.signatures.mSigningDetails,
+                PackageParser.SigningDetails.CertCapabilities.INSTALLED_DATA)
+                || disabledPkgSetting.signatures.mSigningDetails.checkCapability(
+                pkgSetting.signatures.mSigningDetails,
+                PackageParser.SigningDetails.CertCapabilities.ROLLBACK)) {
+            return true;
+        } else {
+            logCriticalInfo(Log.ERROR, "Updated system app mismatches cert on /system: " +
+                    pkgSetting.name);
             return false;
         }
     }
@@ -642,8 +648,8 @@
             }
         }
         // Check for shared user signatures
-        if (pkgSetting.sharedUser != null
-                && pkgSetting.sharedUser.signatures.mSigningDetails
+        if (pkgSetting.getSharedUser() != null
+                && pkgSetting.getSharedUser().signatures.mSigningDetails
                         != PackageParser.SigningDetails.UNKNOWN) {
 
             // Already existing package. Make sure signatures match.  In case of signing certificate
@@ -653,24 +659,24 @@
             // with being sharedUser with the existing signing cert.
             boolean match =
                     parsedSignatures.checkCapability(
-                            pkgSetting.sharedUser.signatures.mSigningDetails,
+                            pkgSetting.getSharedUser().signatures.mSigningDetails,
                             PackageParser.SigningDetails.CertCapabilities.SHARED_USER_ID)
-                    || pkgSetting.sharedUser.signatures.mSigningDetails.checkCapability(
+                    || pkgSetting.getSharedUser().signatures.mSigningDetails.checkCapability(
                             parsedSignatures,
                             PackageParser.SigningDetails.CertCapabilities.SHARED_USER_ID);
             if (!match && compareCompat) {
                 match = matchSignaturesCompat(
-                        packageName, pkgSetting.sharedUser.signatures, parsedSignatures);
+                        packageName, pkgSetting.getSharedUser().signatures, parsedSignatures);
             }
             if (!match && compareRecover) {
                 match =
                         matchSignaturesRecover(packageName,
-                                pkgSetting.sharedUser.signatures.mSigningDetails,
+                                pkgSetting.getSharedUser().signatures.mSigningDetails,
                                 parsedSignatures,
                                 PackageParser.SigningDetails.CertCapabilities.SHARED_USER_ID)
                         || matchSignaturesRecover(packageName,
                                 parsedSignatures,
-                                pkgSetting.sharedUser.signatures.mSigningDetails,
+                                pkgSetting.getSharedUser().signatures.mSigningDetails,
                                 PackageParser.SigningDetails.CertCapabilities.SHARED_USER_ID);
                 compatMatch |= match;
             }
@@ -678,7 +684,7 @@
                 throw new PackageManagerException(INSTALL_FAILED_SHARED_USER_INCOMPATIBLE,
                         "Package " + packageName
                         + " has no signatures that match those in shared user "
-                        + pkgSetting.sharedUser.name + "; ignoring!");
+                        + pkgSetting.getSharedUser().name + "; ignoring!");
             }
         }
         return compatMatch;
@@ -823,11 +829,11 @@
      * Checks whenever downgrade of an app is permitted.
      *
      * @param installFlags flags of the current install.
-     * @param applicationFlags flags of the currently installed version of the app.
+     * @param isAppDebuggable if the currently installed version of the app is debuggable.
      * @return {@code true} if downgrade is permitted according to the {@code installFlags} and
      *         {@code applicationFlags}.
      */
-    public static boolean isDowngradePermitted(int installFlags, int applicationFlags) {
+    public static boolean isDowngradePermitted(int installFlags, boolean isAppDebuggable) {
         // If installed, the package will get access to data left on the device by its
         // predecessor. As a security measure, this is permitted only if this is not a
         // version downgrade or if the predecessor package is marked as debuggable and
@@ -849,9 +855,7 @@
         if (!downgradeRequested) {
             return false;
         }
-        final boolean isDebuggable =
-                Build.IS_DEBUGGABLE || ((applicationFlags
-                        & ApplicationInfo.FLAG_DEBUGGABLE) != 0);
+        final boolean isDebuggable = Build.IS_DEBUGGABLE || isAppDebuggable;
         if (isDebuggable) {
             return true;
         }
@@ -915,8 +919,8 @@
      */
     public static PermissionsState getPermissionsState(
             PackageManagerInternal packageManagerInternal, AndroidPackage pkg) {
-        final PackageSetting packageSetting =
-                (PackageSetting) packageManagerInternal.getPackageSetting(pkg.getPackageName());
+        final PackageSetting packageSetting = packageManagerInternal.getPackageSetting(
+                pkg.getPackageName());
         if (packageSetting == null) {
             return null;
         }
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index d83e6f4..2bd1a26 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -16,18 +16,19 @@
 
 package com.android.server.pm;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 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 com.android.server.pm.pkg.PackageStateUnserialized;
 
 import java.io.File;
 import java.util.ArrayList;
@@ -39,8 +40,7 @@
 /**
  * Settings data for a particular package we know about.
  */
-public final class PackageSetting extends PackageSettingBase implements
-        ParsedPackage.PackageSettingCallback {
+public class PackageSetting extends PackageSettingBase {
     int appId;
 
     public AndroidPackage pkg;
@@ -65,6 +65,9 @@
     @Nullable
     Map<String, ArraySet<String>> mimeGroups;
 
+    @NonNull
+    private PackageStateUnserialized pkgState = new PackageStateUnserialized();
+
     PackageSetting(String name, String realName, File codePath, File resourcePath,
             String legacyNativeLibraryPathString, String primaryCpuAbiString,
             String secondaryCpuAbiString, String cpuAbiOverrideString,
@@ -223,10 +226,6 @@
         return (pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0;
     }
 
-    public boolean isUpdatedSystem() {
-        return (pkgFlags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0;
-    }
-
     @Override
     public boolean isSharedUser() {
         return sharedUser != null;
@@ -324,9 +323,8 @@
         updateMimeGroups(mimeGroupNames);
     }
 
-    // TODO(b/135203078): Move to constructor
-    @Override
-    public void setAndroidPackage(AndroidPackage pkg) {
-        this.pkg = pkg;
+    @NonNull
+    public PackageStateUnserialized getPkgState() {
+        return pkgState;
     }
 }
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index 7d95b19..18bc879 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -78,12 +78,12 @@
     /**
      * The primary CPU abi for this package.
      */
-    String primaryCpuAbiString;
+    public String primaryCpuAbiString;
 
     /**
      * The secondary CPU abi for this package.
      */
-    String secondaryCpuAbiString;
+    public String secondaryCpuAbiString;
 
     /**
      * The install time CPU override, if any. This value is written at install time
diff --git a/services/core/java/com/android/server/pm/PackageUsage.java b/services/core/java/com/android/server/pm/PackageUsage.java
index ce2c9e7..ef37a20 100644
--- a/services/core/java/com/android/server/pm/PackageUsage.java
+++ b/services/core/java/com/android/server/pm/PackageUsage.java
@@ -20,11 +20,12 @@
 import static android.os.Process.SYSTEM_UID;
 
 import android.content.pm.PackageManager;
-import android.content.pm.parsing.AndroidPackage;
 import android.os.FileUtils;
 import android.util.AtomicFile;
 import android.util.Log;
 
+import com.android.server.pm.parsing.pkg.AndroidPackage;
+
 import libcore.io.IoUtils;
 
 import java.io.BufferedInputStream;
@@ -36,7 +37,7 @@
 import java.nio.charset.StandardCharsets;
 import java.util.Map;
 
-class PackageUsage extends AbstractStatsBase<Map<String, AndroidPackage>> {
+class PackageUsage extends AbstractStatsBase<Map<String, PackageSetting>> {
 
     private static final String USAGE_FILE_MAGIC = "PACKAGE_USAGE__VERSION_";
     private static final String USAGE_FILE_MAGIC_VERSION_1 = USAGE_FILE_MAGIC + "1";
@@ -52,7 +53,7 @@
     }
 
     @Override
-    protected void writeInternal(Map<String, AndroidPackage> packages) {
+    protected void writeInternal(Map<String, PackageSetting> pkgSettings) {
         AtomicFile file = getFile();
         FileOutputStream f = null;
         try {
@@ -66,13 +67,14 @@
             sb.append('\n');
             out.write(sb.toString().getBytes(StandardCharsets.US_ASCII));
 
-            for (AndroidPackage pkg : packages.values()) {
-                if (pkg.getLatestPackageUseTimeInMills() == 0L) {
+            for (PackageSetting pkgSetting : pkgSettings.values()) {
+                if (pkgSetting.getPkgState().getLatestPackageUseTimeInMills() == 0L) {
                     continue;
                 }
                 sb.setLength(0);
-                sb.append(pkg.getPackageName());
-                for (long usageTimeInMillis : pkg.getLastPackageUsageTimeInMills()) {
+                sb.append(pkgSetting.name);
+                for (long usageTimeInMillis : pkgSetting.getPkgState()
+                        .getLastPackageUsageTimeInMills()) {
                     sb.append(' ');
                     sb.append(usageTimeInMillis);
                 }
@@ -90,7 +92,7 @@
     }
 
     @Override
-    protected void readInternal(Map<String, AndroidPackage> packages) {
+    protected void readInternal(Map<String, PackageSetting> pkgSettings) {
         AtomicFile file = getFile();
         BufferedInputStream in = null;
         try {
@@ -101,9 +103,9 @@
             if (firstLine == null) {
                 // Empty file. Do nothing.
             } else if (USAGE_FILE_MAGIC_VERSION_1.equals(firstLine)) {
-                readVersion1LP(packages, in, sb);
+                readVersion1LP(pkgSettings, in, sb);
             } else {
-                readVersion0LP(packages, in, sb, firstLine);
+                readVersion0LP(pkgSettings, in, sb, firstLine);
             }
         } catch (FileNotFoundException expected) {
             mIsHistoricalPackageUsageAvailable = false;
@@ -114,7 +116,7 @@
         }
     }
 
-    private void readVersion0LP(Map<String, AndroidPackage> packages, InputStream in,
+    private void readVersion0LP(Map<String, PackageSetting> pkgSettings, InputStream in,
             StringBuffer sb, String firstLine)
             throws IOException {
         // Initial version of the file had no version number and stored one
@@ -128,8 +130,8 @@
             }
 
             String packageName = tokens[0];
-            AndroidPackage pkg = packages.get(packageName);
-            if (pkg == null) {
+            PackageSetting pkgSetting = pkgSettings.get(packageName);
+            if (pkgSetting == null) {
                 continue;
             }
 
@@ -137,12 +139,12 @@
             for (int reason = 0;
                     reason < PackageManager.NOTIFY_PACKAGE_USE_REASONS_COUNT;
                     reason++) {
-                pkg.mutate().setLastPackageUsageTimeInMills(reason, timestamp);
+                pkgSetting.getPkgState().setLastPackageUsageTimeInMills(reason, timestamp);
             }
         }
     }
 
-    private void readVersion1LP(Map<String, AndroidPackage> packages, InputStream in,
+    private void readVersion1LP(Map<String, PackageSetting> pkgSettings, InputStream in,
             StringBuffer sb) throws IOException {
         // Version 1 of the file started with the corresponding version
         // number and then stored a package name and eight timestamps per line.
@@ -154,15 +156,15 @@
             }
 
             String packageName = tokens[0];
-            AndroidPackage pkg = packages.get(packageName);
-            if (pkg == null) {
+            PackageSetting pkgSetting = pkgSettings.get(packageName);
+            if (pkgSetting == null) {
                 continue;
             }
 
             for (int reason = 0;
                     reason < PackageManager.NOTIFY_PACKAGE_USE_REASONS_COUNT;
                     reason++) {
-                pkg.mutate().setLastPackageUsageTimeInMills(reason,
+                pkgSetting.getPkgState().setLastPackageUsageTimeInMills(reason,
                         parseAsLong(tokens[reason + 1]));
             }
         }
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/PersistentPreferredIntentResolver.java b/services/core/java/com/android/server/pm/PersistentPreferredIntentResolver.java
index ef29cb3..08a87d8 100644
--- a/services/core/java/com/android/server/pm/PersistentPreferredIntentResolver.java
+++ b/services/core/java/com/android/server/pm/PersistentPreferredIntentResolver.java
@@ -16,6 +16,9 @@
 
 package com.android.server.pm;
 
+import android.annotation.NonNull;
+import android.content.IntentFilter;
+
 import com.android.server.IntentResolver;
 
 public class PersistentPreferredIntentResolver
@@ -26,6 +29,11 @@
     }
 
     @Override
+    protected IntentFilter getIntentFilter(@NonNull PersistentPreferredActivity input) {
+        return input;
+    }
+
+    @Override
     protected boolean isPackageForFilter(String packageName, PersistentPreferredActivity filter) {
         return packageName.equals(filter.mComponent.getPackageName());
     }
diff --git a/services/core/java/com/android/server/pm/PreferredIntentResolver.java b/services/core/java/com/android/server/pm/PreferredIntentResolver.java
index bce24d7..a261e29 100644
--- a/services/core/java/com/android/server/pm/PreferredIntentResolver.java
+++ b/services/core/java/com/android/server/pm/PreferredIntentResolver.java
@@ -16,6 +16,9 @@
 
 package com.android.server.pm;
 
+import android.annotation.NonNull;
+import android.content.IntentFilter;
+
 import java.io.PrintWriter;
 
 import com.android.server.IntentResolver;
@@ -37,4 +40,9 @@
             PreferredActivity filter) {
         filter.mPref.dump(out, prefix, filter);
     }
+
+    @Override
+    protected IntentFilter getIntentFilter(@NonNull PreferredActivity input) {
+        return input;
+    }
 }
diff --git a/services/core/java/com/android/server/pm/SELinuxMMAC.java b/services/core/java/com/android/server/pm/SELinuxMMAC.java
index 466f19c..67e1994 100644
--- a/services/core/java/com/android/server/pm/SELinuxMMAC.java
+++ b/services/core/java/com/android/server/pm/SELinuxMMAC.java
@@ -18,15 +18,14 @@
 
 import android.compat.annotation.ChangeId;
 import android.compat.annotation.EnabledAfter;
-import android.content.pm.PackageParser;
 import android.content.pm.PackageParser.SigningDetails;
 import android.content.pm.Signature;
-import android.content.pm.parsing.AndroidPackage;
 import android.os.Environment;
 import android.util.Slog;
 import android.util.Xml;
 
 import com.android.server.compat.PlatformCompat;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
 
 import libcore.io.IoUtils;
 
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 60c8b94..42b2eeb 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -49,10 +49,12 @@
 import android.content.pm.SuspendDialogInfo;
 import android.content.pm.UserInfo;
 import android.content.pm.VerifierDeviceIdentity;
-import android.content.pm.parsing.AndroidPackage;
-import android.content.pm.parsing.ComponentParseUtils;
-import android.content.pm.parsing.ComponentParseUtils.ParsedComponent;
-import android.content.pm.parsing.ComponentParseUtils.ParsedPermission;
+import android.content.pm.parsing.PackageInfoWithoutStateUtils;
+import android.content.pm.parsing.component.ParsedComponent;
+import android.content.pm.parsing.component.ParsedIntentInfo;
+import android.content.pm.parsing.component.ParsedMainComponent;
+import android.content.pm.parsing.component.ParsedPermission;
+import android.content.pm.parsing.component.ParsedProcess;
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Build;
@@ -76,6 +78,7 @@
 import android.util.AtomicFile;
 import android.util.Log;
 import android.util.LogPrinter;
+import android.util.Pair;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
@@ -96,6 +99,9 @@
 import com.android.permission.persistence.RuntimePermissionsState;
 import com.android.server.LocalServices;
 import com.android.server.pm.Installer.InstallerException;
+import com.android.server.pm.parsing.PackageInfoUtils;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
 import com.android.server.pm.permission.BasePermission;
 import com.android.server.pm.permission.PermissionSettings;
 import com.android.server.pm.permission.PermissionsState;
@@ -479,10 +485,9 @@
         }
         final PackageSetting dp = mDisabledSysPackages.get(name);
         // always make sure the system package code and resource paths dont change
-        if (dp == null && p.pkg != null && p.pkg.isSystem() && !p.pkg.isUpdatedSystemApp()) {
-            if(p.pkg != null) {
-                p.pkg.mutate().setUpdatedSystemApp(true);
-            }
+        if (dp == null && p.pkg != null && p.pkg.isSystem()
+                && !p.getPkgState().isUpdatedSystemApp()) {
+            p.getPkgState().setUpdatedSystemApp(true);
             final PackageSetting disabled;
             if (replaced) {
                 // a little trick...  when we install the new package, we don't
@@ -506,10 +511,7 @@
             Log.w(PackageManagerService.TAG, "Package " + name + " is not disabled");
             return null;
         }
-        // Reset flag in ApplicationInfo object
-        if(p.pkg != null) {
-            p.pkg.mutate().setUpdatedSystemApp(false);
-        }
+        p.getPkgState().setUpdatedSystemApp(false);
         PackageSetting ret = addPackageLPw(name, p.realName, p.codePath, p.resourcePath,
                 p.legacyNativeLibraryPathString, p.primaryCpuAbiString,
                 p.secondaryCpuAbiString, p.cpuAbiOverrideString,
@@ -2673,15 +2675,19 @@
 
             StringBuilder sb = new StringBuilder();
             for (final PackageSetting pkg : mPackages.values()) {
-                if (pkg.pkg == null || pkg.pkg.getDataDir() == null) {
+                // TODO(b/135203078): This doesn't handle multiple users
+                final String dataPath = pkg.pkg == null ? null :
+                        PackageInfoWithoutStateUtils.getDataDir(pkg.pkg,
+                                UserHandle.USER_SYSTEM).getAbsolutePath();
+
+                if (pkg.pkg == null || dataPath == null) {
                     if (!"android".equals(pkg.name)) {
                         Slog.w(TAG, "Skipping " + pkg + " due to missing metadata");
                     }
                     continue;
                 }
 
-                final String dataPath = pkg.pkg.getDataDir();
-                final boolean isDebug = (pkg.pkg.getFlags() & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
+                final boolean isDebug = pkg.pkg.isDebuggable();
                 final int[] gids = pkg.getPermissionsState().computeGids(userIds);
 
                 // Avoid any application that has a space in its path.
@@ -2712,7 +2718,7 @@
                 sb.append(isDebug ? " 1 " : " 0 ");
                 sb.append(dataPath);
                 sb.append(" ");
-                sb.append(pkg.pkg.getSeInfo());
+                sb.append(AndroidPackageUtils.getSeInfo(pkg.pkg, pkg));
                 sb.append(" ");
                 if (gids != null && gids.length > 0) {
                     sb.append(gids[0]);
@@ -3154,14 +3160,14 @@
         final PackageManagerInternal pmInternal =
                 LocalServices.getService(PackageManagerInternal.class);
         for (PackageSetting ps : mPackages.values()) {
-            if ((ps.pkgFlags&ApplicationInfo.FLAG_SYSTEM) != 0 && ps.pkg != null
-                    && ps.pkg.getPreferredActivityFilters() != null) {
-                List<ComponentParseUtils.ParsedActivityIntentInfo> intents
+            if ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0 && ps.pkg != null
+                    && !ps.pkg.getPreferredActivityFilters().isEmpty()) {
+                List<Pair<String, ParsedIntentInfo>> intents
                         = ps.pkg.getPreferredActivityFilters();
                 for (int i=0; i<intents.size(); i++) {
-                    ComponentParseUtils.ParsedActivityIntentInfo aii = intents.get(i);
-                    applyDefaultPreferredActivityLPw(pmInternal, aii, new ComponentName(
-                                    ps.name, aii.getClassName()), userId);
+                    Pair<String, ParsedIntentInfo> pair = intents.get(i);
+                    applyDefaultPreferredActivityLPw(pmInternal, pair.second, new ComponentName(
+                            ps.name, pair.first), userId);
                 }
             }
         }
@@ -4129,7 +4135,7 @@
                 final boolean shouldInstall = ps.isSystem() &&
                         (skipPackageWhitelist || installablePackages.contains(ps.name)) &&
                         !ArrayUtils.contains(disallowedPackages, ps.name) &&
-                        !ps.pkg.isHiddenUntilInstalled();
+                        !ps.getPkgState().isHiddenUntilInstalled();
                 // Only system apps are initially installed.
                 ps.setInstalled(shouldInstall, userHandle);
                 if (!shouldInstall) {
@@ -4140,7 +4146,7 @@
                 volumeUuids[i] = ps.volumeUuid;
                 names[i] = ps.name;
                 appIds[i] = ps.appId;
-                seinfos[i] = ps.pkg.getSeInfo();
+                seinfos[i] = AndroidPackageUtils.getSeInfo(ps.pkg, ps);
                 targetSdkVersions[i] = ps.pkg.getTargetSdkVersion();
             }
         }
@@ -4281,7 +4287,7 @@
         return userState.isMatch(componentInfo, flags);
     }
 
-    boolean isEnabledAndMatchLPr(AndroidPackage pkg, ParsedComponent component, int flags,
+    boolean isEnabledAndMatchLPr(AndroidPackage pkg, ParsedMainComponent component, int flags,
             int userId) {
         final PackageSetting ps = mPackages.get(component.getPackageName());
         if (ps == null) return false;
@@ -4596,58 +4602,60 @@
             pw.print(prefix); pw.print("  apkSigningVersion="); pw.println(apkSigningVersion);
             // TODO(b/135203078): Is there anything to print here with AppInfo removed?
             pw.print(prefix); pw.print("  applicationInfo=");
-            pw.println(pkg.toAppInfoWithoutState().toString());
-            pw.print(prefix); pw.print("  flags="); printFlags(pw, pkg.getFlags(),
-                    FLAG_DUMP_SPEC); pw.println();
-            if (pkg.getPrivateFlags() != 0) {
+            pw.println(pkg.toAppInfoToString());
+            pw.print(prefix); pw.print("  flags=");
+            printFlags(pw, PackageInfoUtils.appInfoFlags(pkg, ps), FLAG_DUMP_SPEC); pw.println();
+            int privateFlags = PackageInfoUtils.appInfoPrivateFlags(pkg, ps);
+            if (privateFlags != 0) {
                 pw.print(prefix); pw.print("  privateFlags="); printFlags(pw,
-                        pkg.getPrivateFlags(), PRIVATE_FLAG_DUMP_SPEC); pw.println();
+                        privateFlags, PRIVATE_FLAG_DUMP_SPEC); pw.println();
             }
             pw.print(prefix); pw.print("  forceQueryable="); pw.print(ps.pkg.isForceQueryable());
             if (ps.forceQueryableOverride) {
                 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());
+            File dataDir = PackageInfoWithoutStateUtils.getDataDir(pkg, UserHandle.myUserId());
+            pw.print(prefix); pw.print("  dataDir="); pw.println(dataDir.getAbsolutePath());
             pw.print(prefix); pw.print("  supportsScreens=[");
             boolean first = true;
-            if ((pkg.getFlags() & ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS) != 0) {
+            if (pkg.isSupportsSmallScreens()) {
                 if (!first)
                     pw.print(", ");
                 first = false;
                 pw.print("small");
             }
-            if ((pkg.getFlags() & ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS) != 0) {
+            if (pkg.isSupportsNormalScreens()) {
                 if (!first)
                     pw.print(", ");
                 first = false;
                 pw.print("medium");
             }
-            if ((pkg.getFlags() & ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS) != 0) {
+            if (pkg.isSupportsLargeScreens()) {
                 if (!first)
                     pw.print(", ");
                 first = false;
                 pw.print("large");
             }
-            if ((pkg.getFlags() & ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS) != 0) {
+            if (pkg.isSupportsExtraLargeScreens()) {
                 if (!first)
                     pw.print(", ");
                 first = false;
                 pw.print("xlarge");
             }
-            if ((pkg.getFlags() & ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS) != 0) {
+            if (pkg.isResizeable()) {
                 if (!first)
                     pw.print(", ");
                 first = false;
                 pw.print("resizeable");
             }
-            if ((pkg.getFlags() & ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES) != 0) {
+            if (pkg.isAnyDensity()) {
                 if (!first)
                     pw.print(", ");
                 first = false;
@@ -4669,18 +4677,17 @@
                 pw.print(" version:"); pw.println(pkg.getStaticSharedLibVersion());
             }
 
-            final List<String> usesLibraries = pkg.getUsesLibraries();
-            if (usesLibraries != null && usesLibraries.size() > 0) {
+            List<String> usesLibraries = pkg.getUsesLibraries();
+            if (usesLibraries.size() > 0) {
                 pw.print(prefix); pw.println("  usesLibraries:");
                 for (int i=0; i< usesLibraries.size(); i++) {
                     pw.print(prefix); pw.print("    "); pw.println(usesLibraries.get(i));
                 }
             }
 
-            final List<String> usesStaticLibraries = pkg.getUsesStaticLibraries();
-            final long[] usesStaticLibrariesVersions = pkg.getUsesStaticLibrariesVersions();
-            if (usesStaticLibraries != null
-                    && usesStaticLibraries.size() > 0) {
+            List<String> usesStaticLibraries = pkg.getUsesStaticLibraries();
+            long[] usesStaticLibrariesVersions = pkg.getUsesStaticLibrariesVersions();
+            if (usesStaticLibraries.size() > 0) {
                 pw.print(prefix); pw.println("  usesStaticLibraries:");
                 for (int i=0; i< usesStaticLibraries.size(); i++) {
                     pw.print(prefix); pw.print("    ");
@@ -4689,9 +4696,8 @@
                 }
             }
 
-            final List<String> usesOptionalLibraries = pkg.getUsesOptionalLibraries();
-            if (usesOptionalLibraries != null
-                    && usesOptionalLibraries.size() > 0) {
+            List<String> usesOptionalLibraries = pkg.getUsesOptionalLibraries();
+            if (usesOptionalLibraries.size() > 0) {
                 pw.print(prefix); pw.println("  usesOptionalLibraries:");
                 for (int i=0; i< usesOptionalLibraries.size(); i++) {
                     pw.print(prefix); pw.print("    ");
@@ -4699,24 +4705,22 @@
                 }
             }
 
-            final String[] usesLibraryFiles = pkg.getUsesLibraryFiles();
-            if (usesLibraryFiles != null
-                    && usesLibraryFiles.length > 0) {
+            List<String> usesLibraryFiles = ps.getPkgState().getUsesLibraryFiles();
+            if (usesLibraryFiles.size() > 0) {
                 pw.print(prefix); pw.println("  usesLibraryFiles:");
-                for (int i=0; i< usesLibraryFiles.length; i++) {
-                    pw.print(prefix); pw.print("    "); pw.println(usesLibraryFiles[i]);
+                for (int i=0; i< usesLibraryFiles.size(); i++) {
+                    pw.print(prefix); pw.print("    "); pw.println(usesLibraryFiles.get(i));
                 }
             }
-            final ArrayMap<String, ComponentParseUtils.ParsedProcess> procs = pkg.getProcesses();
-            if (procs != null) {
+            final Map<String, 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);
-                    pw.print(prefix); pw.print("    "); pw.println(proc.name);
-                    if (proc.deniedPermissions != null) {
-                        for (int j = 0; j < proc.deniedPermissions.size(); j++) {
+                for (ParsedProcess proc : procs.values()) {
+                    pw.print(prefix); pw.print("    "); pw.println(proc.getName());
+                    if (proc.getDeniedPermissions() != null) {
+                        for (String deniedPermission : proc.getDeniedPermissions()) {
                             pw.print(prefix); pw.print("      deny: ");
-                            pw.println(proc.deniedPermissions.valueAt(j));
+                            pw.println(deniedPermission);
                         }
                     }
                 }
@@ -4751,7 +4755,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++) {
@@ -4762,14 +4766,14 @@
                 }
                 pw.print(prefix); pw.print("    "); pw.print(perm.getName());
                 pw.print(": prot=");
-                pw.print(PermissionInfo.protectionToString(perm.protectionLevel));
-                if ((perm.flags&PermissionInfo.FLAG_COSTS_MONEY) != 0) {
+                pw.print(PermissionInfo.protectionToString(perm.getProtectionLevel()));
+                if ((perm.getFlags() &PermissionInfo.FLAG_COSTS_MONEY) != 0) {
                     pw.print(", COSTS_MONEY");
                 }
-                if ((perm.flags&PermissionInfo.FLAG_REMOVED) != 0) {
+                if ((perm.getFlags() &PermissionInfo.FLAG_REMOVED) != 0) {
                     pw.print(", HIDDEN");
                 }
-                if ((perm.flags&PermissionInfo.FLAG_INSTALLED) != 0) {
+                if ((perm.getFlags() &PermissionInfo.FLAG_INSTALLED) != 0) {
                     pw.print(", INSTALLED");
                 }
                 pw.println();
@@ -5403,7 +5407,7 @@
                         packagePermissions, sharedUserPermissions);
             }
 
-            mPersistence.write(runtimePermissions, UserHandle.of(userId));
+            mPersistence.writeAsUser(runtimePermissions, UserHandle.of(userId));
         }
 
         @NonNull
@@ -5457,12 +5461,13 @@
         }
 
         public void deleteUserRuntimePermissionsFile(int userId) {
-            mPersistence.delete(UserHandle.of(userId));
+            mPersistence.deleteAsUser(UserHandle.of(userId));
         }
 
         @GuardedBy("Settings.this.mLock")
         public void readStateForUserSyncLPr(int userId) {
-            RuntimePermissionsState runtimePermissions = mPersistence.read(UserHandle.of(userId));
+            RuntimePermissionsState runtimePermissions = mPersistence.readAsUser(UserHandle.of(
+                    userId));
             if (runtimePermissions == null) {
                 readLegacyStateForUserSyncLPr(userId);
                 writePermissionsForUserAsyncLPr(userId);
diff --git a/services/core/java/com/android/server/pm/SharedUserSetting.java b/services/core/java/com/android/server/pm/SharedUserSetting.java
index bbd319c..6103f558 100644
--- a/services/core/java/com/android/server/pm/SharedUserSetting.java
+++ b/services/core/java/com/android/server/pm/SharedUserSetting.java
@@ -18,19 +18,20 @@
 
 import android.annotation.Nullable;
 import android.content.pm.ApplicationInfo;
-import android.content.pm.parsing.AndroidPackage;
-import android.content.pm.parsing.ComponentParseUtils;
+import android.content.pm.parsing.component.ParsedProcess;
 import android.service.pm.PackageServiceDumpProto;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.util.ArrayUtils;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
 
 import libcore.util.EmptyArray;
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Map;
 
 /**
  * Settings data for a particular shared user ID we know about.
@@ -53,7 +54,7 @@
     final PackageSignatures signatures = new PackageSignatures();
     Boolean signaturesChanged;
 
-    ArrayMap<String, ComponentParseUtils.ParsedProcess> processes;
+    ArrayMap<String, ParsedProcess> processes;
 
     SharedUserSetting(String _name, int _pkgFlags, int _pkgPrivateFlags) {
         super(_pkgFlags, _pkgPrivateFlags);
@@ -76,18 +77,18 @@
         proto.end(token);
     }
 
-    void addProcesses(ArrayMap<String, ComponentParseUtils.ParsedProcess> newProcs) {
+    void addProcesses(Map<String, ParsedProcess> newProcs) {
         if (newProcs != null) {
             final int numProcs = newProcs.size();
             if (processes == null) {
                 processes = new ArrayMap<>(numProcs);
             }
-            for (int i = 0; i < numProcs; i++) {
-                ComponentParseUtils.ParsedProcess newProc = newProcs.valueAt(i);
-                ComponentParseUtils.ParsedProcess proc = processes.get(newProc.name);
+            for (String key : newProcs.keySet()) {
+                ParsedProcess newProc = newProcs.get(key);
+                ParsedProcess proc = processes.get(newProc.getName());
                 if (proc == null) {
-                    proc = new ComponentParseUtils.ParsedProcess(newProc);
-                    processes.put(newProc.name, proc);
+                    proc = new ParsedProcess(newProc);
+                    processes.put(newProc.getName(), proc);
                 } else {
                     proc.addStateFrom(newProc);
                 }
@@ -159,19 +160,24 @@
      * restrictive selinux domain.
      */
     public void fixSeInfoLocked() {
-        final List<AndroidPackage> pkgList = getPackages();
-        if (pkgList == null || pkgList.size() == 0) {
+        if (packages == null || packages.size() == 0) {
             return;
         }
-
-        for (AndroidPackage pkg : pkgList) {
-            if (pkg.getTargetSdkVersion() < seInfoTargetSdkVersion) {
-                seInfoTargetSdkVersion = pkg.getTargetSdkVersion();
+        for (PackageSetting ps : packages) {
+            if ((ps == null) || (ps.pkg == null)) {
+                continue;
+            }
+            if (ps.pkg.getTargetSdkVersion() < seInfoTargetSdkVersion) {
+                seInfoTargetSdkVersion = ps.pkg.getTargetSdkVersion();
             }
         }
-        for (AndroidPackage pkg : pkgList) {
-            final boolean isPrivileged = isPrivileged() | pkg.isPrivileged();
-            pkg.mutate().setSeInfo(SELinuxMMAC.getSeInfo(pkg, isPrivileged,
+
+        for (PackageSetting ps : packages) {
+            if ((ps == null) || (ps.pkg == null)) {
+                continue;
+            }
+            final boolean isPrivileged = isPrivileged() | ps.pkg.isPrivileged();
+            ps.getPkgState().setOverrideSeInfo(SELinuxMMAC.getSeInfo(ps.pkg, isPrivileged,
                     seInfoTargetSdkVersion));
         }
     }
@@ -221,9 +227,9 @@
             final int numProcs = sharedUser.processes.size();
             this.processes = new ArrayMap<>(numProcs);
             for (int i = 0; i < numProcs; i++) {
-                ComponentParseUtils.ParsedProcess proc =
-                        new ComponentParseUtils.ParsedProcess(sharedUser.processes.valueAt(i));
-                this.processes.put(proc.name, proc);
+                ParsedProcess proc =
+                        new ParsedProcess(sharedUser.processes.valueAt(i));
+                this.processes.put(proc.getName(), proc);
             }
         } else {
             this.processes = null;
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index c37ceb3..c8df5c7 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -36,6 +36,7 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.CollectionUtils;
 import com.android.internal.util.Preconditions;
 import com.android.internal.util.XmlUtils;
 import com.android.server.pm.ShortcutService.DumpFilter;
@@ -310,10 +311,67 @@
     }
 
     /**
-     * Remove all shortcuts that aren't pinned, cached nor dynamic.
+     * Push a shortcut. If the max number of dynamic shortcuts is already reached, remove the
+     * shortcut with the lowest rank before adding the new shortcut.
      */
-    private void removeOrphans() {
+    public boolean pushDynamicShortcut(@NonNull ShortcutInfo newShortcut) {
+        Preconditions.checkArgument(newShortcut.isEnabled(),
+                "pushDynamicShortcuts() cannot publish disabled shortcuts");
+
+        newShortcut.addFlags(ShortcutInfo.FLAG_DYNAMIC);
+
+        final ShortcutInfo oldShortcut = mShortcuts.get(newShortcut.getId());
+        boolean wasPinned = false;
+
+        if (oldShortcut == null) {
+            final ShortcutService service = mShortcutUser.mService;
+            final int maxShortcuts = service.getMaxActivityShortcuts();
+
+            final ArrayMap<ComponentName, ArrayList<ShortcutInfo>> all =
+                    sortShortcutsToActivities();
+            final ArrayList<ShortcutInfo> activityShortcuts = all.get(newShortcut.getActivity());
+
+            if (activityShortcuts != null && activityShortcuts.size() == maxShortcuts) {
+                // Max has reached. Delete the shortcut with lowest rank.
+
+                // Sort by isManifestShortcut() and getRank().
+                Collections.sort(activityShortcuts, mShortcutTypeAndRankComparator);
+
+                final ShortcutInfo shortcut = activityShortcuts.get(maxShortcuts - 1);
+                if (shortcut.isManifestShortcut()) {
+                    // All shortcuts are manifest shortcuts and cannot be removed.
+                    Slog.e(TAG, "Failed to remove manifest shortcut while pushing dynamic shortcut "
+                            + newShortcut.getId());
+                    return false;
+                }
+
+                deleteDynamicWithId(shortcut.getId(), /*ignoreInvisible=*/ true);
+            }
+        } else {
+            // It's an update case.
+            // Make sure the target is updatable. (i.e. should be mutable.)
+            oldShortcut.ensureUpdatableWith(newShortcut, /*isUpdating=*/ false);
+
+            wasPinned = oldShortcut.isPinned();
+        }
+
+        // If it was originally pinned, the new one should be pinned too.
+        if (wasPinned) {
+            newShortcut.addFlags(ShortcutInfo.FLAG_PINNED);
+        }
+
+        forceReplaceShortcutInner(newShortcut);
+        return true;
+    }
+
+    /**
+     * Remove all shortcuts that aren't pinned, cached nor dynamic.
+     *
+     * @return List of removed shortcuts.
+     */
+    private List<ShortcutInfo> removeOrphans() {
         ArrayList<String> removeList = null; // Lazily initialize.
+        List<ShortcutInfo> removedShortcuts = null;
 
         for (int i = mShortcuts.size() - 1; i >= 0; i--) {
             final ShortcutInfo si = mShortcuts.valueAt(i);
@@ -322,20 +380,26 @@
 
             if (removeList == null) {
                 removeList = new ArrayList<>();
+                removedShortcuts = new ArrayList<>();
             }
             removeList.add(si.getId());
+            removedShortcuts.add(si);
         }
         if (removeList != null) {
             for (int i = removeList.size() - 1; i >= 0; i--) {
                 forceDeleteShortcutInner(removeList.get(i));
             }
         }
+
+        return removedShortcuts;
     }
 
     /**
      * Remove all dynamic shortcuts.
+     *
+     * @return List of shortcuts that actually got removed.
      */
-    public void deleteAllDynamicShortcuts(boolean ignoreInvisible) {
+    public List<ShortcutInfo> deleteAllDynamicShortcuts(boolean ignoreInvisible) {
         final long now = mShortcutUser.mService.injectCurrentTimeMillis();
 
         boolean changed = false;
@@ -350,8 +414,9 @@
             }
         }
         if (changed) {
-            removeOrphans();
+            return removeOrphans();
         }
+        return null;
     }
 
     /**
@@ -974,7 +1039,8 @@
         s.verifyStates();
 
         // This will send a notification to the launcher, and also save .
-        s.packageShortcutsChanged(getPackageName(), getPackageUserId());
+        // TODO: List changed and removed manifest shortcuts and pass to packageShortcutsChanged()
+        s.packageShortcutsChanged(getPackageName(), getPackageUserId(), null, null);
         return true; // true means changed.
     }
 
@@ -1245,15 +1311,14 @@
      */
     public void resolveResourceStrings() {
         final ShortcutService s = mShortcutUser.mService;
-        boolean changed = false;
+
+        List<ShortcutInfo> changedShortcuts = null;
 
         Resources publisherRes = null;
         for (int i = mShortcuts.size() - 1; i >= 0; i--) {
             final ShortcutInfo si = mShortcuts.valueAt(i);
 
             if (si.hasStringResources()) {
-                changed = true;
-
                 if (publisherRes == null) {
                     publisherRes = getPackageResources();
                     if (publisherRes == null) {
@@ -1263,10 +1328,15 @@
 
                 si.resolveResourceStrings(publisherRes);
                 si.setTimestamp(s.injectCurrentTimeMillis());
+
+                if (changedShortcuts == null) {
+                    changedShortcuts = new ArrayList<>(1);
+                }
+                changedShortcuts.add(si);
             }
         }
-        if (changed) {
-            s.packageShortcutsChanged(getPackageName(), getPackageUserId());
+        if (!CollectionUtils.isEmpty(changedShortcuts)) {
+            s.packageShortcutsChanged(getPackageName(), getPackageUserId(), changedShortcuts, null);
         }
     }
 
diff --git a/services/core/java/com/android/server/pm/ShortcutRequestPinProcessor.java b/services/core/java/com/android/server/pm/ShortcutRequestPinProcessor.java
index 3e44de9..6fd997d 100644
--- a/services/core/java/com/android/server/pm/ShortcutRequestPinProcessor.java
+++ b/services/core/java/com/android/server/pm/ShortcutRequestPinProcessor.java
@@ -26,7 +26,6 @@
 import android.content.pm.LauncherApps.PinItemRequest;
 import android.content.pm.ShortcutInfo;
 import android.os.Bundle;
-import android.os.RemoteException;
 import android.os.UserHandle;
 import android.util.Log;
 import android.util.Pair;
@@ -36,6 +35,9 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.Preconditions;
 
+import java.util.ArrayList;
+import java.util.List;
+
 /**
  * Handles {@link android.content.pm.ShortcutManager#requestPinShortcut} related tasks.
  */
@@ -452,6 +454,8 @@
         final String launcherPackage = request.launcherPackage;
         final String shortcutId = original.getId();
 
+        List<ShortcutInfo> changedShortcuts = null;
+
         synchronized (mLock) {
             if (!(mService.isUserUnlockedL(appUserId)
                     && mService.isUserUnlockedL(request.launcherUserId))) {
@@ -506,8 +510,13 @@
                 Slog.d(TAG, "Pinning " + shortcutId);
             }
 
+
             launcher.addPinnedShortcut(appPackageName, appUserId, shortcutId,
                     /*forPinRequest=*/ true);
+            if (changedShortcuts == null) {
+                changedShortcuts = new ArrayList<>(1);
+            }
+            changedShortcuts.add(original);
 
             if (current == null) {
                 if (DEBUG) {
@@ -520,7 +529,7 @@
         }
 
         mService.verifyStates();
-        mService.packageShortcutsChanged(appPackageName, appUserId);
+        mService.packageShortcutsChanged(appPackageName, appUserId, changedShortcuts, null);
 
         return true;
     }
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 12f7d5c..66f3574 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -98,6 +98,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.os.BackgroundThread;
+import com.android.internal.util.CollectionUtils;
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.Preconditions;
@@ -133,6 +134,7 @@
 import java.net.URISyntaxException;
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 import java.util.Objects;
@@ -276,6 +278,10 @@
     private final ArrayList<ShortcutChangeListener> mListeners = new ArrayList<>(1);
 
     @GuardedBy("mLock")
+    private final ArrayList<LauncherApps.ShortcutChangeCallback> mShortcutChangeCallbacks =
+            new ArrayList<>(1);
+
+    @GuardedBy("mLock")
     private long mRawLastResetTime;
 
     /**
@@ -1638,8 +1644,12 @@
      * - Sends a notification to LauncherApps
      * - Write to file
      */
-    void packageShortcutsChanged(@NonNull String packageName, @UserIdInt int userId) {
+    void packageShortcutsChanged(@NonNull String packageName, @UserIdInt int userId,
+            @Nullable List<ShortcutInfo> addedOrUpdatedShortcuts,
+            @Nullable List<ShortcutInfo> removedShortcuts) {
         notifyListeners(packageName, userId);
+        notifyShortcutChangeCallbacks(packageName, userId, addedOrUpdatedShortcuts,
+                removedShortcuts);
         scheduleSaveUser(userId);
     }
 
@@ -1667,6 +1677,34 @@
         });
     }
 
+    private void notifyShortcutChangeCallbacks(@NonNull String packageName, @UserIdInt int userId,
+            @Nullable List<ShortcutInfo> addedOrUpdatedShortcuts,
+            @Nullable List<ShortcutInfo> removedShortcuts) {
+        final UserHandle user = UserHandle.of(userId);
+        injectPostToHandler(() -> {
+            try {
+                final ArrayList<LauncherApps.ShortcutChangeCallback> copy;
+                synchronized (mLock) {
+                    if (!isUserUnlockedL(userId)) {
+                        return;
+                    }
+
+                    copy = new ArrayList<>(mShortcutChangeCallbacks);
+                }
+                for (int i = copy.size() - 1; i >= 0; i--) {
+                    if (!CollectionUtils.isEmpty(addedOrUpdatedShortcuts)) {
+                        copy.get(i).onShortcutsAddedOrUpdated(packageName, addedOrUpdatedShortcuts,
+                                user);
+                    }
+                    if (!CollectionUtils.isEmpty(removedShortcuts)) {
+                        copy.get(i).onShortcutsRemoved(packageName, removedShortcuts, user);
+                    }
+                }
+            } catch (Exception ignore) {
+            }
+        });
+    }
+
     /**
      * Clean up / validate an incoming shortcut.
      * - Make sure all mandatory fields are set.
@@ -1761,6 +1799,8 @@
         final boolean unlimited = injectHasUnlimitedShortcutsApiCallsPermission(
                 injectBinderCallingPid(), injectBinderCallingUid());
 
+        List<ShortcutInfo> removedShortcuts = null;
+
         synchronized (mLock) {
             throwIfUserLockedL(userId);
 
@@ -1786,7 +1826,7 @@
             }
 
             // First, remove all un-pinned; dynamic shortcuts
-            ps.deleteAllDynamicShortcuts(/*ignoreInvisible=*/ true);
+            removedShortcuts = ps.deleteAllDynamicShortcuts(/*ignoreInvisible=*/ true);
 
             // Then, add/update all.  We need to make sure to take over "pinned" flag.
             for (int i = 0; i < size; i++) {
@@ -1797,7 +1837,7 @@
             // Lastly, adjust the ranks.
             ps.adjustRanks();
         }
-        packageShortcutsChanged(packageName, userId);
+        packageShortcutsChanged(packageName, userId, newShortcuts, removedShortcuts);
 
         verifyStates();
 
@@ -1816,6 +1856,8 @@
         final boolean unlimited = injectHasUnlimitedShortcutsApiCallsPermission(
                 injectBinderCallingPid(), injectBinderCallingUid());
 
+        List<ShortcutInfo> changedShortcuts = null;
+
         synchronized (mLock) {
             throwIfUserLockedL(userId);
 
@@ -1878,12 +1920,17 @@
                 if (replacingIcon || source.hasStringResources()) {
                     fixUpShortcutResourceNamesAndValues(target);
                 }
+
+                if (changedShortcuts == null) {
+                    changedShortcuts = new ArrayList<>(1);
+                }
+                changedShortcuts.add(target);
             }
 
             // Lastly, adjust the ranks.
             ps.adjustRanks();
         }
-        packageShortcutsChanged(packageName, userId);
+        packageShortcutsChanged(packageName, userId, changedShortcuts, null);
 
         verifyStates();
 
@@ -1902,6 +1949,8 @@
         final boolean unlimited = injectHasUnlimitedShortcutsApiCallsPermission(
                 injectBinderCallingPid(), injectBinderCallingUid());
 
+        List<ShortcutInfo> changedShortcuts = null;
+
         synchronized (mLock) {
             throwIfUserLockedL(userId);
 
@@ -1933,12 +1982,17 @@
 
                 // Add it.
                 ps.addOrReplaceDynamicShortcut(newShortcut);
+
+                if (changedShortcuts == null) {
+                    changedShortcuts = new ArrayList<>(1);
+                }
+                changedShortcuts.add(newShortcut);
             }
 
             // Lastly, adjust the ranks.
             ps.adjustRanks();
         }
-        packageShortcutsChanged(packageName, userId);
+        packageShortcutsChanged(packageName, userId, changedShortcuts, null);
 
         verifyStates();
 
@@ -1946,6 +2000,50 @@
     }
 
     @Override
+    public void pushDynamicShortcut(String packageName, ShortcutInfo shortcut,
+            @UserIdInt int userId) {
+        verifyCaller(packageName, userId);
+        verifyShortcutInfoPackage(packageName, shortcut);
+
+        final boolean unlimited = injectHasUnlimitedShortcutsApiCallsPermission(
+                injectBinderCallingPid(), injectBinderCallingUid());
+
+        synchronized (mLock) {
+            throwIfUserLockedL(userId);
+
+            final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId);
+
+            ps.ensureNotImmutable(shortcut.getId(), /*ignoreInvisible=*/ true);
+            fillInDefaultActivity(Arrays.asList(shortcut));
+
+            if (!shortcut.hasRank()) {
+                shortcut.setRank(0);
+            }
+            // Initialize the implicit ranks for ShortcutPackage.adjustRanks().
+            ps.clearAllImplicitRanks();
+            shortcut.setImplicitRank(0);
+
+            // Validate the shortcut.
+            fixUpIncomingShortcutInfo(shortcut, /* forUpdate= */ false);
+
+            // When ranks are changing, we need to insert between ranks, so set the
+            // "rank changed" flag.
+            shortcut.setRankChanged();
+
+            // Push it.
+            if (!ps.pushDynamicShortcut(shortcut)) {
+                return;
+            }
+
+            // Lastly, adjust the ranks.
+            ps.adjustRanks();
+        }
+        packageShortcutsChanged(packageName, userId, Collections.singletonList(shortcut), null);
+
+        verifyStates();
+    }
+
+    @Override
     public boolean requestPinShortcut(String packageName, ShortcutInfo shortcut,
             IntentSender resultIntent, int userId) {
         Objects.requireNonNull(shortcut);
@@ -2007,7 +2105,8 @@
 
                     ps.updateInvisibleShortcutForPinRequestWith(shortcut);
 
-                    packageShortcutsChanged(shortcutPackage, userId);
+                    packageShortcutsChanged(shortcutPackage, userId,
+                            Collections.singletonList(shortcut), null);
                 }
             }
 
@@ -2052,7 +2151,8 @@
             // We may have removed dynamic shortcuts which may have left a gap, so adjust the ranks.
             ps.adjustRanks();
         }
-        packageShortcutsChanged(packageName, userId);
+        // TODO: Disabling dynamic shortcuts will removed them if not pinned. Cover all cases.
+        packageShortcutsChanged(packageName, userId, null, null);
 
         verifyStates();
     }
@@ -2062,6 +2162,8 @@
         verifyCaller(packageName, userId);
         Objects.requireNonNull(shortcutIds, "shortcutIds must be provided");
 
+        List<ShortcutInfo> changedShortcuts = null;
+
         synchronized (mLock) {
             throwIfUserLockedL(userId);
 
@@ -2076,9 +2178,18 @@
                     continue;
                 }
                 ps.enableWithId(id);
+
+                final ShortcutInfo si = ps.findShortcutById(id);
+                if (si != null) {
+                    if (changedShortcuts == null) {
+                        changedShortcuts = new ArrayList<>(1);
+                    }
+                    changedShortcuts.add(si);
+                }
             }
         }
-        packageShortcutsChanged(packageName, userId);
+
+        packageShortcutsChanged(packageName, userId, changedShortcuts, null);
 
         verifyStates();
     }
@@ -2089,6 +2200,9 @@
         verifyCaller(packageName, userId);
         Objects.requireNonNull(shortcutIds, "shortcutIds must be provided");
 
+        List<ShortcutInfo> changedShortcuts = null;
+        List<ShortcutInfo> removedShortcuts = null;
+
         synchronized (mLock) {
             throwIfUserLockedL(userId);
 
@@ -2102,13 +2216,25 @@
                 if (!ps.isShortcutExistsAndVisibleToPublisher(id)) {
                     continue;
                 }
-                ps.deleteDynamicWithId(id, /*ignoreInvisible=*/ true);
+                final ShortcutInfo si = ps.findShortcutById(id);
+                final boolean removed = ps.deleteDynamicWithId(id, /*ignoreInvisible=*/ true);
+                if (removed) {
+                    if (removedShortcuts == null) {
+                        removedShortcuts = new ArrayList<>(1);
+                    }
+                    removedShortcuts.add(si);
+                } else {
+                    if (changedShortcuts == null) {
+                        changedShortcuts = new ArrayList<>(1);
+                    }
+                    changedShortcuts.add(si);
+                }
             }
 
             // We may have removed dynamic shortcuts which may have left a gap, so adjust the ranks.
             ps.adjustRanks();
         }
-        packageShortcutsChanged(packageName, userId);
+        packageShortcutsChanged(packageName, userId, changedShortcuts, removedShortcuts);
 
         verifyStates();
     }
@@ -2117,13 +2243,19 @@
     public void removeAllDynamicShortcuts(String packageName, @UserIdInt int userId) {
         verifyCaller(packageName, userId);
 
+        List<ShortcutInfo> changedShortcuts = null;
+        List<ShortcutInfo> removedShortcuts = null;
+
         synchronized (mLock) {
             throwIfUserLockedL(userId);
 
             final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId);
-            ps.deleteAllDynamicShortcuts(/*ignoreInvisible=*/ true);
+
+            removedShortcuts = ps.deleteAllDynamicShortcuts(/*ignoreInvisible=*/ true);
         }
-        packageShortcutsChanged(packageName, userId);
+
+        // TODO: Pinned and cached shortcuts are not removed, add those to changedShortcuts list
+        packageShortcutsChanged(packageName, userId, changedShortcuts, removedShortcuts);
 
         verifyStates();
     }
@@ -2134,6 +2266,9 @@
         verifyCaller(packageName, userId);
         Objects.requireNonNull(shortcutIds, "shortcutIds must be provided");
 
+        List<ShortcutInfo> changedShortcuts = null;
+        List<ShortcutInfo> removedShortcuts = null;
+
         synchronized (mLock) {
             throwIfUserLockedL(userId);
 
@@ -2144,13 +2279,29 @@
 
             for (int i = shortcutIds.size() - 1; i >= 0; i--) {
                 final String id = Preconditions.checkStringNotEmpty((String) shortcutIds.get(i));
-                ps.deleteLongLivedWithId(id, /*ignoreInvisible=*/ true);
+
+                final ShortcutInfo si = ps.findShortcutById(id);
+                final boolean removed = ps.deleteLongLivedWithId(id, /*ignoreInvisible=*/ true);
+
+                if (si != null) {
+                    if (removed) {
+                        if (removedShortcuts == null) {
+                            removedShortcuts = new ArrayList<>(1);
+                        }
+                        removedShortcuts.add(si);
+                    } else {
+                        if (changedShortcuts == null) {
+                            changedShortcuts = new ArrayList<>(1);
+                        }
+                        changedShortcuts.add(si);
+                    }
+                }
             }
 
             // We may have removed dynamic shortcuts which may have left a gap, so adjust the ranks.
             ps.adjustRanks();
         }
-        packageShortcutsChanged(packageName, userId);
+        packageShortcutsChanged(packageName, userId, changedShortcuts, removedShortcuts);
 
         verifyStates();
     }
@@ -2742,6 +2893,8 @@
             Preconditions.checkStringNotEmpty(packageName, "packageName");
             Objects.requireNonNull(shortcutIds, "shortcutIds");
 
+            List<ShortcutInfo> changedShortcuts = null;
+
             synchronized (mLock) {
                 throwIfUserLockedL(userId);
                 throwIfUserLockedL(launcherUserId);
@@ -2751,8 +2904,23 @@
                 launcher.attemptToRestoreIfNeededAndSave();
 
                 launcher.pinShortcuts(userId, packageName, shortcutIds, /*forPinRequest=*/ false);
+
+                final ShortcutPackage sp = getUserShortcutsLocked(userId)
+                        .getPackageShortcutsIfExists(packageName);
+                if (sp != null) {
+                    for (int i = 0; i < shortcutIds.size(); i++) {
+                        final ShortcutInfo si = sp.findShortcutById(shortcutIds.get(i));
+                        if (si != null) {
+                            if (changedShortcuts == null) {
+                                changedShortcuts = new ArrayList<>(1);
+                            }
+                            changedShortcuts.add(si);
+                        }
+                    }
+                }
             }
-            packageShortcutsChanged(packageName, userId);
+            // TODO: Include previously pinned shortcuts since they are not pinned anymore.
+            packageShortcutsChanged(packageName, userId, changedShortcuts, null);
 
             verifyStates();
         }
@@ -2787,6 +2955,9 @@
             Preconditions.checkStringNotEmpty(packageName, "packageName");
             Objects.requireNonNull(shortcutIds, "shortcutIds");
 
+            List<ShortcutInfo> changedShortcuts = null;
+            List<ShortcutInfo> removedShortcuts = null;
+
             synchronized (mLock) {
                 throwIfUserLockedL(userId);
                 throwIfUserLockedL(launcherUserId);
@@ -2808,20 +2979,36 @@
                     if (doCache) {
                         if (si.isDynamic() && si.isLongLived()) {
                             si.addFlags(ShortcutInfo.FLAG_CACHED);
+                            if (changedShortcuts == null) {
+                                changedShortcuts = new ArrayList<>(1);
+                            }
+                            changedShortcuts.add(si);
                         } else {
                             Log.w(TAG, "Only dynamic long lived shortcuts can get cached. Ignoring"
                                     + "shortcut " + si.getId());
                         }
                     } else {
+                        boolean removed = false;
                         if (si.isDynamic()) {
                             si.clearFlags(ShortcutInfo.FLAG_CACHED);
                         } else {
-                            sp.deleteLongLivedWithId(id, /*ignoreInvisible=*/ true);
+                            removed = sp.deleteLongLivedWithId(id, /*ignoreInvisible=*/ true);
+                        }
+                        if (removed) {
+                            if (removedShortcuts == null) {
+                                removedShortcuts = new ArrayList<>(1);
+                            }
+                            removedShortcuts.add(si);
+                        } else {
+                            if (changedShortcuts == null) {
+                                changedShortcuts = new ArrayList<>(1);
+                            }
+                            changedShortcuts.add(si);
                         }
                     }
                 }
             }
-            packageShortcutsChanged(packageName, userId);
+            packageShortcutsChanged(packageName, userId, changedShortcuts, removedShortcuts);
 
             verifyStates();
         }
@@ -2867,6 +3054,14 @@
         }
 
         @Override
+        public void addShortcutChangeCallback(
+                @NonNull LauncherApps.ShortcutChangeCallback callback) {
+            synchronized (mLock) {
+                mShortcutChangeCallbacks.add(Objects.requireNonNull(callback));
+            }
+        }
+
+        @Override
         public int getShortcutIconResId(int launcherUserId, @NonNull String callingPackage,
                 @NonNull String packageName, @NonNull String shortcutId, int userId) {
             Objects.requireNonNull(callingPackage, "callingPackage");
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index 614cc3f..fe99229 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -29,6 +29,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.IntentSender;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageInstaller;
 import android.content.pm.PackageInstaller.SessionInfo;
@@ -39,7 +40,6 @@
 import android.content.pm.PackageParser.SigningDetails;
 import android.content.pm.PackageParser.SigningDetails.SignatureSchemeVersion;
 import android.content.pm.ParceledListSlice;
-import android.content.pm.parsing.AndroidPackage;
 import android.content.rollback.IRollbackManager;
 import android.content.rollback.RollbackInfo;
 import android.content.rollback.RollbackManager;
@@ -68,6 +68,8 @@
 import com.android.internal.content.PackageHelper;
 import com.android.internal.os.BackgroundThread;
 import com.android.server.LocalServices;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
 import com.android.server.rollback.WatchdogRollbackLogger;
 
 import java.io.File;
@@ -284,8 +286,10 @@
             throws PackageManagerException {
         final long activeVersion = activePackage.applicationInfo.longVersionCode;
         final long newVersionCode = newPackage.applicationInfo.longVersionCode;
+        boolean isAppDebuggable = (activePackage.applicationInfo.flags
+                & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
         final boolean allowsDowngrade = PackageManagerServiceUtils.isDowngradePermitted(
-                session.params.installFlags, activePackage.applicationInfo.flags);
+                session.params.installFlags, isAppDebuggable);
         if (activeVersion > newVersionCode && !allowsDowngrade) {
             if (!mApexManager.abortStagedSession(session.sessionId)) {
                 Slog.e(TAG, "Failed to abort apex session " + session.sessionId);
@@ -426,11 +430,10 @@
                     + "for snapshotting/restoring user data.");
             return;
         }
-        final String seInfo = pkg.getSeInfo();
 
         int appId = -1;
         long ceDataInode = -1;
-        final PackageSetting ps = (PackageSetting) mPmi.getPackageSetting(packageName);
+        final PackageSetting ps = mPmi.getPackageSetting(packageName);
         if (ps != null) {
             appId = ps.appId;
             ceDataInode = ps.getCeDataInode(UserHandle.USER_SYSTEM);
@@ -438,6 +441,7 @@
             // an update, and hence need to restore data for all installed users.
             final int[] installedUsers = ps.queryInstalledUsers(allUsers, true);
 
+            final String seInfo = AndroidPackageUtils.getSeInfo(pkg, ps);
             try {
                 rm.snapshotAndRestoreUserData(packageName, installedUsers, appId, ceDataInode,
                         seInfo, 0 /*token*/);
diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
index 67b1008..27e8b0b 100644
--- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
+++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
@@ -585,6 +585,9 @@
                             android.provider.Settings.Global.putStringForUser(cr,
                                     android.provider.Settings.Global.ADB_ENABLED, "0",
                                     userId);
+                            android.provider.Settings.Global.putStringForUser(cr,
+                                    android.provider.Settings.Global.ADB_WIFI_ENABLED, "0",
+                                    userId);
                         }
                     }
                     break;
@@ -721,6 +724,7 @@
                 break;
 
             case android.provider.Settings.Global.ADB_ENABLED:
+            case android.provider.Settings.Global.ADB_WIFI_ENABLED:
                 if ("0".equals(value)) {
                     return false;
                 }
diff --git a/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java b/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java
index 4c40448..d6480d3 100644
--- a/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java
+++ b/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java
@@ -22,7 +22,6 @@
 import android.annotation.UserIdInt;
 import android.content.pm.PackageManagerInternal;
 import android.content.pm.PackageParser;
-import android.content.pm.parsing.AndroidPackage;
 import android.content.res.Resources;
 import android.os.SystemProperties;
 import android.os.UserHandle;
@@ -33,6 +32,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.server.LocalServices;
 import com.android.server.SystemConfig;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
 
 import java.io.PrintWriter;
 import java.lang.annotation.Retention;
@@ -190,13 +190,14 @@
         // Install/uninstall system packages per user.
         for (int userId : mUm.getUserIds()) {
             final Set<String> userWhitelist = getInstallablePackagesForUserId(userId);
-            pmInt.forEachPackage(pkg -> {
-                if (!pkg.isSystem()) {
+            pmInt.forEachPackageSetting(pkgSetting -> {
+                AndroidPackage pkg = pkgSetting.pkg;
+                if (pkg == null || !pkg.isSystem()) {
                     return;
                 }
                 final boolean install =
                         (userWhitelist == null || userWhitelist.contains(pkg.getPackageName()))
-                        && !pkg.isHiddenUntilInstalled();
+                                && !pkgSetting.getPkgState().isHiddenUntilInstalled();
                 if (isConsideredUpgrade && !isFirstBoot && !install) {
                     return; // To be careful, we don’t uninstall apps during OTAs
                 }
diff --git a/services/core/java/com/android/server/pm/dex/ArtManagerService.java b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
index 0caab6d..51e07faf 100644
--- a/services/core/java/com/android/server/pm/dex/ArtManagerService.java
+++ b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
@@ -31,7 +31,7 @@
 import android.content.pm.dex.DexMetadataHelper;
 import android.content.pm.dex.ISnapshotRuntimeProfileCallback;
 import android.content.pm.dex.PackageOptimizationInfo;
-import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.PackageInfoWithoutStateUtils;
 import android.os.Binder;
 import android.os.Build;
 import android.os.Handler;
@@ -54,6 +54,7 @@
 import com.android.server.pm.Installer;
 import com.android.server.pm.Installer.InstallerException;
 import com.android.server.pm.PackageManagerServiceCompilerMapping;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
 
 import dalvik.system.DexFile;
 import dalvik.system.VMRuntime;
@@ -482,8 +483,10 @@
         try {
             final String packageName = pkg.getPackageName();
             final String apkPath = pkg.getBaseCodePath();
-            final String outDexFile = pkg.getDataDir() + "/code_cache/compiled_view.dex";
-            if (pkg.isPrivileged() || pkg.isEmbeddedDexUsed()
+            // TODO(b/143971007): Use a cross-user directory
+            File dataDir = PackageInfoWithoutStateUtils.getDataDir(pkg, UserHandle.myUserId());
+            final String outDexFile = dataDir.getAbsolutePath() + "/code_cache/compiled_view.dex";
+            if (pkg.isPrivileged() || pkg.isUseEmbeddedDex()
                     || pkg.isDefaultToDeviceProtectedStorage()) {
                 // Privileged apps prefer to load trusted code so they don't use compiled views.
                 // If the app is not privileged but prefers code integrity, also avoid compiling
@@ -516,7 +519,7 @@
      */
     private ArrayMap<String, String> getPackageProfileNames(AndroidPackage pkg) {
         ArrayMap<String, String> result = new ArrayMap<>();
-        if ((pkg.getFlags() & ApplicationInfo.FLAG_HAS_CODE) != 0) {
+        if (pkg.isHasCode()) {
             result.put(pkg.getBaseCodePath(), ArtManager.getProfileName(null));
         }
 
diff --git a/services/core/java/com/android/server/pm/dex/DexManager.java b/services/core/java/com/android/server/pm/dex/DexManager.java
index df24c013..117cc5e 100644
--- a/services/core/java/com/android/server/pm/dex/DexManager.java
+++ b/services/core/java/com/android/server/pm/dex/DexManager.java
@@ -41,6 +41,8 @@
 import com.android.server.pm.PackageManagerService;
 import com.android.server.pm.PackageManagerServiceUtils;
 
+import dalvik.system.VMRuntime;
+
 import java.io.File;
 import java.io.IOException;
 import java.util.Arrays;
@@ -136,22 +138,15 @@
      * return as fast as possible.
      *
      * @param loadingAppInfo the package performing the load
-     * @param classLoadersNames the names of the class loaders present in the loading chain. The
-     *    list encodes the class loader chain in the natural order. The first class loader has
-     *    the second one as its parent and so on. The dex files present in the class path of the
-     *    first class loader will be recorded in the usage file.
-     * @param classPaths the class paths corresponding to the class loaders names from
-     *     {@param classLoadersNames}. The the first element corresponds to the first class loader
-     *     and so on. A classpath is represented as a list of dex files separated by
-     *     {@code File.pathSeparator}, or null if the class loader's classpath is not known.
-     *     The dex files found in the first class path will be recorded in the usage file.
+     * @param classLoaderContextMap a map from file paths to dex files that have been loaded to
+     *     the class loader context that was used to load them.
      * @param loaderIsa the ISA of the app loading the dex files
      * @param loaderUserId the user id which runs the code loading the dex files
      */
-    public void notifyDexLoad(ApplicationInfo loadingAppInfo, List<String> classLoadersNames,
-            List<String> classPaths, String loaderIsa, int loaderUserId) {
+    public void notifyDexLoad(ApplicationInfo loadingAppInfo,
+            Map<String, String> classLoaderContextMap, String loaderIsa, int loaderUserId) {
         try {
-            notifyDexLoadInternal(loadingAppInfo, classLoadersNames, classPaths, loaderIsa,
+            notifyDexLoadInternal(loadingAppInfo, classLoaderContextMap, loaderIsa,
                     loaderUserId);
         } catch (Exception e) {
             Slog.w(TAG, "Exception while notifying dex load for package " +
@@ -161,46 +156,23 @@
 
     @VisibleForTesting
     /*package*/ void notifyDexLoadInternal(ApplicationInfo loadingAppInfo,
-            List<String> classLoaderNames, List<String> classPaths, String loaderIsa,
+            Map<String, String> classLoaderContextMap, String loaderIsa,
             int loaderUserId) {
-        if (classLoaderNames.size() != classPaths.size()) {
-            Slog.wtf(TAG, "Bad call to noitfyDexLoad: args have different size");
+        if (classLoaderContextMap == null) {
             return;
         }
-        if (classLoaderNames.isEmpty()) {
+        if (classLoaderContextMap.isEmpty()) {
             Slog.wtf(TAG, "Bad call to notifyDexLoad: class loaders list is empty");
             return;
         }
         if (!PackageManagerServiceUtils.checkISA(loaderIsa)) {
-            Slog.w(TAG, "Loading dex files " + classPaths + " in unsupported ISA: " +
-                    loaderIsa + "?");
+            Slog.w(TAG, "Loading dex files " + classLoaderContextMap.keySet()
+                    + " in unsupported ISA: " + loaderIsa + "?");
             return;
         }
 
-        // The first classpath should never be null because the first classloader
-        // should always be an instance of BaseDexClassLoader.
-        String firstClassPath = classPaths.get(0);
-        if (firstClassPath == null) {
-            return;
-        }
-        // The classpath is represented as a list of dex files separated by File.pathSeparator.
-        String[] dexPathsToRegister = firstClassPath.split(File.pathSeparator);
-
-        // Encode the class loader contexts for the dexPathsToRegister.
-        String[] classLoaderContexts = DexoptUtils.processContextForDexLoad(
-                classLoaderNames, classPaths);
-
-        // A null classLoaderContexts means that there are unsupported class loaders in the
-        // chain.
-        if (classLoaderContexts == null) {
-            if (DEBUG) {
-                Slog.i(TAG, loadingAppInfo.packageName +
-                        " uses unsupported class loader in " + classLoaderNames);
-            }
-        }
-
-        int dexPathIndex = 0;
-        for (String dexPath : dexPathsToRegister) {
+        for (Map.Entry<String, String> mapping : classLoaderContextMap.entrySet()) {
+            String dexPath = mapping.getKey();
             // Find the owning package name.
             DexSearchResult searchResult = getDexPackage(loadingAppInfo, dexPath, loaderUserId);
 
@@ -222,7 +194,6 @@
                     // If the dex file is the primary apk (or a split) and not isUsedByOtherApps
                     // do not record it. This case does not bring any new usable information
                     // and can be safely skipped.
-                    dexPathIndex++;
                     continue;
                 }
 
@@ -232,13 +203,13 @@
                             searchResult.mOwningPackageName, loadingAppInfo.packageName);
                 }
 
-                if (classLoaderContexts != null) {
-
+                String classLoaderContext = mapping.getValue();
+                if (classLoaderContext != null
+                        && VMRuntime.isValidClassLoaderContext(classLoaderContext)) {
                     // Record dex file usage. If the current usage is a new pattern (e.g. new
                     // secondary, or UsedByOtherApps), record will return true and we trigger an
                     // async write to disk to make sure we don't loose the data in case of a reboot.
 
-                    String classLoaderContext = classLoaderContexts[dexPathIndex];
                     if (mPackageDexUsage.record(searchResult.mOwningPackageName,
                             dexPath, loaderUserId, loaderIsa, isUsedByOtherApps, primaryOrSplit,
                             loadingAppInfo.packageName, classLoaderContext)) {
@@ -252,7 +223,6 @@
                     Slog.i(TAG, "Could not find owning package for dex file: " + dexPath);
                 }
             }
-            dexPathIndex++;
         }
     }
 
diff --git a/services/core/java/com/android/server/pm/dex/DexoptUtils.java b/services/core/java/com/android/server/pm/dex/DexoptUtils.java
index 6e6b137..6807388 100644
--- a/services/core/java/com/android/server/pm/dex/DexoptUtils.java
+++ b/services/core/java/com/android/server/pm/dex/DexoptUtils.java
@@ -18,7 +18,7 @@
 
 import android.content.pm.ApplicationInfo;
 import android.content.pm.SharedLibraryInfo;
-import android.content.pm.parsing.AndroidPackage;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
 import android.util.Slog;
 import android.util.SparseArray;
 
@@ -77,7 +77,7 @@
         }
 
         String baseApkContextClassLoader = encodeClassLoader(
-                "", pkg.getAppInfoClassLoaderName(), sharedLibrariesContext);
+                "", pkg.getClassLoaderName(), sharedLibrariesContext);
         if (pkg.getSplitCodePaths() == null) {
             // The application has no splits.
             return new String[] {baseApkContextClassLoader};
@@ -101,7 +101,7 @@
 
         SparseArray<int[]> splitDependencies = pkg.getSplitDependencies();
 
-        if (!pkg.requestsIsolatedSplitLoading()
+        if (!pkg.isIsolatedSplitLoading()
                 || splitDependencies == null
                 || splitDependencies.size() == 0) {
             // If the app didn't request for the splits to be loaded in isolation or if it does not
@@ -111,7 +111,7 @@
             for (int i = 1; i < classLoaderContexts.length; i++) {
                 if (pathsWithCode[i]) {
                     classLoaderContexts[i] = encodeClassLoader(
-                            classpath, pkg.getAppInfoClassLoaderName(), sharedLibrariesContext);
+                            classpath, pkg.getClassLoaderName(), sharedLibrariesContext);
                 } else {
                     classLoaderContexts[i] = null;
                 }
diff --git a/services/core/java/com/android/server/pm/dex/PackageDexUsage.java b/services/core/java/com/android/server/pm/dex/PackageDexUsage.java
index e68c238..08763e7 100644
--- a/services/core/java/com/android/server/pm/dex/PackageDexUsage.java
+++ b/services/core/java/com/android/server/pm/dex/PackageDexUsage.java
@@ -83,8 +83,9 @@
             "=UnknownClassLoaderContext=";
 
     // The marker used for unsupported class loader contexts (no longer written, may occur in old
-    // files so discarded on read).
-    private static final String UNSUPPORTED_CLASS_LOADER_CONTEXT =
+    // files so discarded on read). Note: this matches
+    // ClassLoaderContext::kUnsupportedClassLoaderContextEncoding in the runtime.
+    /*package*/ static final String UNSUPPORTED_CLASS_LOADER_CONTEXT =
             "=UnsupportedClassLoaderContext=";
 
     /**
@@ -133,6 +134,9 @@
         if (classLoaderContext == null) {
             throw new IllegalArgumentException("Null classLoaderContext");
         }
+        if (classLoaderContext.equals(UNSUPPORTED_CLASS_LOADER_CONTEXT)) {
+            return false;
+        }
 
         synchronized (mPackageUseInfoMap) {
             PackageUseInfo packageUseInfo = mPackageUseInfoMap.get(owningPackageName);
@@ -843,10 +847,11 @@
             boolean updateLoadingPackages = mLoadingPackages.addAll(dexUseInfo.mLoadingPackages);
 
             String oldClassLoaderContext = mClassLoaderContext;
-            if (UNKNOWN_CLASS_LOADER_CONTEXT.equals(mClassLoaderContext)) {
+            if (isUnknownOrUnsupportedContext(mClassLoaderContext)) {
                 // Can happen if we read a previous version.
                 mClassLoaderContext = dexUseInfo.mClassLoaderContext;
-            } else if (!Objects.equals(mClassLoaderContext, dexUseInfo.mClassLoaderContext)) {
+            } else if (!isUnknownOrUnsupportedContext(dexUseInfo.mClassLoaderContext)
+                        && !Objects.equals(mClassLoaderContext, dexUseInfo.mClassLoaderContext)) {
                 // We detected a context change.
                 mClassLoaderContext = VARIABLE_CLASS_LOADER_CONTEXT;
             }
@@ -857,6 +862,13 @@
                     || !Objects.equals(oldClassLoaderContext, mClassLoaderContext);
         }
 
+        private static boolean isUnknownOrUnsupportedContext(String context) {
+            // TODO: Merge UNKNOWN_CLASS_LOADER_CONTEXT & UNSUPPORTED_CLASS_LOADER_CONTEXT cases
+            // into UNSUPPORTED_CLASS_LOADER_CONTEXT.
+            return UNKNOWN_CLASS_LOADER_CONTEXT.equals(context)
+                    || UNSUPPORTED_CLASS_LOADER_CONTEXT.equals(context);
+        }
+
         public boolean isUsedByOtherApps() {
             return mIsUsedByOtherApps;
         }
@@ -878,7 +890,7 @@
         public boolean isUnknownClassLoaderContext() {
             // The class loader context may be unknown if we loaded the data from a previous version
             // which didn't save the context.
-            return UNKNOWN_CLASS_LOADER_CONTEXT.equals(mClassLoaderContext);
+            return isUnknownOrUnsupportedContext(mClassLoaderContext);
         }
 
         public boolean isVariableClassLoaderContext() {
diff --git a/services/core/java/com/android/server/pm/dex/ViewCompiler.java b/services/core/java/com/android/server/pm/dex/ViewCompiler.java
index b7443f3..5506a52 100644
--- a/services/core/java/com/android/server/pm/dex/ViewCompiler.java
+++ b/services/core/java/com/android/server/pm/dex/ViewCompiler.java
@@ -16,12 +16,16 @@
 
 package com.android.server.pm.dex;
 
-import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.PackageInfoWithoutStateUtils;
 import android.os.Binder;
+import android.os.UserHandle;
 import android.util.Log;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.server.pm.Installer;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
+
+import java.io.File;
 
 public class ViewCompiler {
     private final Object mInstallLock;
@@ -37,7 +41,9 @@
         try {
             final String packageName = pkg.getPackageName();
             final String apkPath = pkg.getBaseCodePath();
-            final String outDexFile = pkg.getDataDir() + "/code_cache/compiled_view.dex";
+            // TODO(b/143971007): Use a cross-user directory
+            File dataDir = PackageInfoWithoutStateUtils.getDataDir(pkg, UserHandle.myUserId());
+            final String outDexFile = dataDir.getAbsolutePath() + "/code_cache/compiled_view.dex";
             Log.i("PackageManager", "Compiling layouts in " + packageName + " (" + apkPath +
                 ") to " + outDexFile);
             long callingId = Binder.clearCallingIdentity();
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..23bdf5f
--- /dev/null
+++ b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
@@ -0,0 +1,483 @@
+/*
+ * 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.SharedLibraryInfo;
+import android.content.pm.parsing.PackageInfoWithoutStateUtils;
+import android.content.pm.parsing.component.ComponentParseUtils;
+import android.content.pm.parsing.component.ParsedActivity;
+import android.content.pm.parsing.component.ParsedComponent;
+import android.content.pm.parsing.component.ParsedInstrumentation;
+import android.content.pm.parsing.component.ParsedMainComponent;
+import android.content.pm.parsing.component.ParsedPermission;
+import android.content.pm.parsing.component.ParsedPermissionGroup;
+import android.content.pm.parsing.component.ParsedProcess;
+import android.content.pm.parsing.component.ParsedProvider;
+import android.content.pm.parsing.component.ParsedService;
+import android.os.UserHandle;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.Pair;
+
+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 com.android.server.pm.pkg.PackageStateUnserialized;
+
+import libcore.util.EmptyArray;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+
+/**
+ * Methods that use a {@link PackageSetting} use it to override information provided from the raw
+ * package, or to provide information that would otherwise be missing. Null can be passed if none
+ * of the state values should be applied.
+ *
+ * @hide
+ **/
+public class PackageInfoUtils {
+
+    /**
+     * @param pkgSetting See {@link PackageInfoUtils} for description of pkgSetting usage.
+     */
+    @Nullable
+    public static PackageInfo generate(AndroidPackage pkg, int[] gids,
+            @PackageManager.PackageInfoFlags int flags, long firstInstallTime, long lastUpdateTime,
+            Set<String> grantedPermissions, PackageUserState state, int userId,
+            @Nullable PackageSetting pkgSetting) {
+        return generateWithComponents(pkg, gids, flags, firstInstallTime, lastUpdateTime,
+                grantedPermissions, state, userId, null, pkgSetting);
+    }
+
+    /**
+     * @param pkgSetting See {@link PackageInfoUtils} for description of pkgSetting usage.
+     */
+    @Nullable
+    public static PackageInfo generate(AndroidPackage pkg, ApexInfo apexInfo, int flags,
+            @Nullable PackageSetting pkgSetting) {
+        return generateWithComponents(pkg, EmptyArray.INT, flags, 0, 0, Collections.emptySet(),
+                new PackageUserState(), UserHandle.getCallingUserId(), apexInfo, pkgSetting);
+    }
+
+    /**
+     * @param pkgSetting See {@link PackageInfoUtils} for description of pkgSetting usage.
+     */
+    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,
+                pkgSetting);
+        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 (ComponentParseUtils.isMatch(state, 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 (ComponentParseUtils.isMatch(state, 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 (ComponentParseUtils.isMatch(state, 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 (ComponentParseUtils.isMatch(state, 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, pkgSetting);
+                }
+            }
+        }
+
+        return info;
+    }
+
+    /**
+     * @param pkgSetting See {@link PackageInfoUtils} for description of pkgSetting usage.
+     */
+    @Nullable
+    public static ApplicationInfo generateApplicationInfo(AndroidPackage pkg,
+            @PackageManager.ApplicationInfoFlags int flags, PackageUserState state, int userId,
+            @Nullable PackageSetting pkgSetting) {
+        // 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;
+        }
+
+        if (pkgSetting != null) {
+            // TODO(b/135203078): Remove PackageParser1/toAppInfoWithoutState and clean all this up
+            PackageStateUnserialized pkgState = pkgSetting.getPkgState();
+            info.hiddenUntilInstalled = pkgState.isHiddenUntilInstalled();
+            List<String> usesLibraryFiles = pkgState.getUsesLibraryFiles();
+            List<SharedLibraryInfo> usesLibraryInfos = pkgState.getUsesLibraryInfos();
+            info.sharedLibraryFiles = usesLibraryFiles.isEmpty()
+                    ? null : usesLibraryFiles.toArray(new String[0]);
+            info.sharedLibraryInfos = usesLibraryInfos.isEmpty() ? null : usesLibraryInfos;
+        }
+
+        info.flags |= appInfoFlags(pkg, pkgSetting);
+        info.privateFlags |= appInfoPrivateFlags(pkg, pkgSetting);
+        return info;
+    }
+
+    /**
+     * @param pkgSetting See {@link PackageInfoUtils} for description of pkgSetting usage.
+     */
+    @Nullable
+    public static ActivityInfo generateActivityInfo(AndroidPackage pkg, ParsedActivity a,
+            @PackageManager.ComponentInfoFlags int flags, PackageUserState state, int userId,
+            @Nullable PackageSetting pkgSetting) {
+        return generateActivityInfo(pkg, a, flags, state, null, userId, pkgSetting);
+    }
+
+    /**
+     * @param pkgSetting See {@link PackageInfoUtils} for description of pkgSetting usage.
+     */
+    @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, pkgSetting);
+        }
+        ActivityInfo info = PackageInfoWithoutStateUtils.generateActivityInfo(pkg, a, flags, state,
+                applicationInfo, userId);
+        if (info == null) {
+            return null;
+        }
+
+        assignSharedFieldsForComponentInfo(info, a, pkgSetting);
+        return info;
+    }
+
+    /**
+     * @param pkgSetting See {@link PackageInfoUtils} for description of pkgSetting usage.
+     */
+    @Nullable
+    public static ServiceInfo generateServiceInfo(AndroidPackage pkg, ParsedService s,
+            @PackageManager.ComponentInfoFlags int flags, PackageUserState state, int userId,
+            @Nullable PackageSetting pkgSetting) {
+        return generateServiceInfo(pkg, s, flags, state, null, userId, pkgSetting);
+    }
+
+    /**
+     * @param pkgSetting See {@link PackageInfoUtils} for description of pkgSetting usage.
+     */
+    @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, pkgSetting);
+        }
+        ServiceInfo info = PackageInfoWithoutStateUtils.generateServiceInfo(pkg, s, flags, state,
+                applicationInfo, userId);
+        if (info == null) {
+            return null;
+        }
+
+        assignSharedFieldsForComponentInfo(info, s, pkgSetting);
+        return info;
+    }
+
+    /**
+     * @param pkgSetting See {@link PackageInfoUtils} for description of pkgSetting usage.
+     */
+    @Nullable
+    public static ProviderInfo generateProviderInfo(AndroidPackage pkg, ParsedProvider p,
+            @PackageManager.ComponentInfoFlags int flags, PackageUserState state, int userId,
+            @Nullable PackageSetting pkgSetting) {
+        return generateProviderInfo(pkg, p, flags, state, null, userId, pkgSetting);
+    }
+
+    /**
+     * @param pkgSetting See {@link PackageInfoUtils} for description of pkgSetting usage.
+     */
+    @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, pkgSetting);
+        }
+        ProviderInfo info = PackageInfoWithoutStateUtils.generateProviderInfo(pkg, p, flags, state,
+                applicationInfo, userId);
+        if (info == null) {
+            return null;
+        }
+
+        assignSharedFieldsForComponentInfo(info, p, pkgSetting);
+        return info;
+    }
+
+    /**
+     * @param pkgSetting See {@link PackageInfoUtils} for description of pkgSetting usage.
+     */
+    @Nullable
+    public static InstrumentationInfo generateInstrumentationInfo(ParsedInstrumentation i,
+            AndroidPackage pkg, @PackageManager.ComponentInfoFlags int flags, int userId,
+            @Nullable PackageSetting pkgSetting) {
+        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 = AndroidPackageUtils.getPrimaryCpuAbi(pkg, pkgSetting);
+        info.secondaryCpuAbi = AndroidPackageUtils.getSecondaryCpuAbi(pkg, pkgSetting);
+        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.getName(), new ProcessInfo(proc.getName(),
+                    new ArraySet<>(proc.getDeniedPermissions())));
+        }
+        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
+                && pkgSetting != null
+                && pkgSetting.getPkgState().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.getDescriptionRes();
+        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
+        int flags = PackageInfoWithoutStateUtils.appInfoFlags(pkg)
+                | flag(pkg.isSystem(), ApplicationInfo.FLAG_SYSTEM)
+                | flag(pkg.isFactoryTest(), ApplicationInfo.FLAG_FACTORY_TEST);
+        if (pkgSetting != null) {
+            flags |= flag(pkgSetting.getPkgState().isUpdatedSystemApp(), ApplicationInfo.FLAG_UPDATED_SYSTEM_APP);
+        }
+        return flags;
+        // @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..f99791a
--- /dev/null
+++ b/services/core/java/com/android/server/pm/parsing/PackageParser2.java
@@ -0,0 +1,138 @@
+/*
+ * 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.PackageParser.PackageParserException;
+import android.content.pm.parsing.ParsingPackage;
+import android.content.pm.parsing.ParsingPackageUtils;
+import android.content.pm.parsing.result.ParseInput;
+import android.content.pm.parsing.result.ParseResult;
+import android.content.pm.parsing.result.ParseTypeImpl;
+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<ParseTypeImpl> mSharedResult = ThreadLocal.withInitial(ParseTypeImpl::new);
+
+    private final String[] mSeparateProcesses;
+    private final boolean mOnlyCoreApps;
+    private final DisplayMetrics mDisplayMetrics;
+
+    @Nullable
+    protected PackageCacher mCacher;
+
+    private ParsingPackageUtils parsingUtils;
+
+    /**
+     * @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
+        callback = callback != null ? callback : new Callback() {
+            @Override
+            public boolean hasFeature(String feature) {
+                return false;
+            }
+        };
+
+        parsingUtils = new ParsingPackageUtils(onlyCoreApps, separateProcesses, displayMetrics, callback);
+    }
+
+    /**
+     * TODO(b/135203078): Document new package parsing
+     */
+    @AnyThread
+    public ParsedPackage parsePackage(File packageFile, int flags, boolean useCaches)
+            throws PackageParserException {
+        if (useCaches && mCacher != null) {
+            ParsedPackage parsed = mCacher.getCachedResult(packageFile, flags);
+            if (parsed != null) {
+                return parsed;
+            }
+        }
+
+        long parseTime = LOG_PARSE_TIMINGS ? SystemClock.uptimeMillis() : 0;
+        ParseInput input = mSharedResult.get().reset();
+        ParseResult<ParsingPackage> result = parsingUtils.parsePackage(input, packageFile, flags);
+        if (result.isError()) {
+            throw new PackageParserException(result.getErrorCode(), result.getErrorMessage(),
+                    result.getException());
+        }
+
+        ParsedPackage parsed = (ParsedPackage) result.getResult().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/core/java/android/content/pm/parsing/library/AndroidHidlUpdater.java b/services/core/java/com/android/server/pm/parsing/library/AndroidHidlUpdater.java
similarity index 71%
rename from core/java/android/content/pm/parsing/library/AndroidHidlUpdater.java
rename to services/core/java/com/android/server/pm/parsing/library/AndroidHidlUpdater.java
index 81b4bc5..ebb96bb 100644
--- a/core/java/android/content/pm/parsing/library/AndroidHidlUpdater.java
+++ b/services/core/java/com/android/server/pm/parsing/library/AndroidHidlUpdater.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2019 The Android Open Source Project
+ * 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.
@@ -13,31 +13,33 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.content.pm.parsing.library;
+package com.android.server.pm.parsing.library;
 
-import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_HIDL_BASE;
-import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_HIDL_MANAGER;
+import static com.android.server.pm.parsing.library.SharedLibraryNames.ANDROID_HIDL_BASE;
+import static com.android.server.pm.parsing.library.SharedLibraryNames.ANDROID_HIDL_MANAGER;
 
-import android.content.pm.parsing.ParsedPackage;
 import android.os.Build;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.pm.parsing.pkg.ParsedPackage;
 
 /**
  * Updates a package to ensure that if it targets <= P that the android.hidl.base-V1.0-java
  * and android.hidl.manager-V1.0-java libraries are included by default.
  *
+ * TODO(b/135203078): See if this class can be removed, thus removing the isUpdatedSystemApp param
+ *
  * @hide
  */
 @VisibleForTesting
 public class AndroidHidlUpdater extends PackageSharedLibraryUpdater {
 
     @Override
-    public void updatePackage(ParsedPackage parsedPackage) {
+    public void updatePackage(ParsedPackage parsedPackage, boolean isUpdatedSystemApp) {
         // This was the default <= P and is maintained for backwards compatibility.
         boolean isLegacy = parsedPackage.getTargetSdkVersion() <= Build.VERSION_CODES.P;
         // Only system apps use these libraries
-        boolean isSystem = parsedPackage.isSystemApp() || parsedPackage.isUpdatedSystemApp();
+        boolean isSystem = parsedPackage.isSystem() || isUpdatedSystemApp;
 
         if (isLegacy && isSystem) {
             prefixRequiredLibrary(parsedPackage, ANDROID_HIDL_BASE);
diff --git a/core/java/android/content/pm/parsing/library/AndroidTestBaseUpdater.java b/services/core/java/com/android/server/pm/parsing/library/AndroidTestBaseUpdater.java
similarity index 87%
rename from core/java/android/content/pm/parsing/library/AndroidTestBaseUpdater.java
rename to services/core/java/com/android/server/pm/parsing/library/AndroidTestBaseUpdater.java
index 5fbe5b9..432394a 100644
--- a/core/java/android/content/pm/parsing/library/AndroidTestBaseUpdater.java
+++ b/services/core/java/com/android/server/pm/parsing/library/AndroidTestBaseUpdater.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2019 The Android Open Source Project
+ * 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.
@@ -13,16 +13,14 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.content.pm.parsing.library;
+package com.android.server.pm.parsing.library;
 
-import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_BASE;
-import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_RUNNER;
+import static com.android.server.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_BASE;
+import static com.android.server.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_RUNNER;
 
 import android.compat.annotation.ChangeId;
 import android.compat.annotation.EnabledAfter;
 import android.content.Context;
-import android.content.pm.parsing.AndroidPackage;
-import android.content.pm.parsing.ParsedPackage;
 import android.os.Build;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -30,6 +28,8 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.compat.IPlatformCompat;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.parsing.pkg.ParsedPackage;
 
 /**
  * Updates a package to ensure that if it targets <= Q that the android.test.base library is
@@ -73,7 +73,7 @@
     }
 
     @Override
-    public void updatePackage(ParsedPackage pkg) {
+    public void updatePackage(ParsedPackage pkg, boolean isUpdatedSystemApp) {
         // Packages targeted at <= Q expect the classes in the android.test.base library
         // to be accessible so this maintains backward compatibility by adding the
         // android.test.base library to those packages.
diff --git a/core/java/android/content/pm/parsing/library/OrgApacheHttpLegacyUpdater.java b/services/core/java/com/android/server/pm/parsing/library/OrgApacheHttpLegacyUpdater.java
similarity index 78%
rename from core/java/android/content/pm/parsing/library/OrgApacheHttpLegacyUpdater.java
rename to services/core/java/com/android/server/pm/parsing/library/OrgApacheHttpLegacyUpdater.java
index 613a06b..7de457e 100644
--- a/core/java/android/content/pm/parsing/library/OrgApacheHttpLegacyUpdater.java
+++ b/services/core/java/com/android/server/pm/parsing/library/OrgApacheHttpLegacyUpdater.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2019 The Android Open Source Project
+ * 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.
@@ -13,15 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.content.pm.parsing.library;
+package com.android.server.pm.parsing.library;
 
-import static android.content.pm.parsing.library.SharedLibraryNames.ORG_APACHE_HTTP_LEGACY;
+import static com.android.server.pm.parsing.library.SharedLibraryNames.ORG_APACHE_HTTP_LEGACY;
 
-import android.content.pm.parsing.AndroidPackage;
-import android.content.pm.parsing.ParsedPackage;
 import android.os.Build;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.parsing.pkg.ParsedPackage;
 
 /**
  * Updates a package to ensure that if it targets < P that the org.apache.http.legacy library is
@@ -37,7 +37,7 @@
     }
 
     @Override
-    public void updatePackage(ParsedPackage parsedPackage) {
+    public void updatePackage(ParsedPackage parsedPackage, boolean isUpdatedSystemApp) {
         // Packages targeted at <= O_MR1 expect the classes in the org.apache.http.legacy library
         // to be accessible so this maintains backward compatibility by adding the
         // org.apache.http.legacy library to those packages.
diff --git a/core/java/android/content/pm/parsing/library/PackageBackwardCompatibility.java b/services/core/java/com/android/server/pm/parsing/library/PackageBackwardCompatibility.java
similarity index 62%
rename from core/java/android/content/pm/parsing/library/PackageBackwardCompatibility.java
rename to services/core/java/com/android/server/pm/parsing/library/PackageBackwardCompatibility.java
index 1220fc4..1d018c4 100644
--- a/core/java/android/content/pm/parsing/library/PackageBackwardCompatibility.java
+++ b/services/core/java/com/android/server/pm/parsing/library/PackageBackwardCompatibility.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2019 The Android Open Source Project
+ * 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.
@@ -14,21 +14,21 @@
  * limitations under the License.
  */
 
-package android.content.pm.parsing.library;
+package com.android.server.pm.parsing.library;
 
-import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_BASE;
-import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_MOCK;
-import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_RUNNER;
-import static android.content.pm.parsing.library.SharedLibraryNames.ORG_APACHE_HTTP_LEGACY;
+import static com.android.server.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_BASE;
+import static com.android.server.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_MOCK;
+import static com.android.server.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_RUNNER;
+import static com.android.server.pm.parsing.library.SharedLibraryNames.ORG_APACHE_HTTP_LEGACY;
 
-import android.content.pm.parsing.ParsedPackage;
+import android.content.pm.PackageParser;
 import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.pm.parsing.pkg.ParsedPackage;
 
 import java.util.ArrayList;
 import java.util.List;
-import java.util.function.Supplier;
 
 /**
  * Modifies {@link ParsedPackage} in order to maintain backwards compatibility.
@@ -55,13 +55,7 @@
         // android.test.mock.
         packageUpdaters.add(new AndroidTestRunnerSplitUpdater());
 
-        // Attempt to load and add the optional updater that will only be available when
-        // REMOVE_ATB_FROM_BCP=true. If that could not be found then add the default updater that
-        // will remove any references to org.apache.http.library from the package so that it does
-        // not try and load the library when it is on the bootclasspath.
-        boolean bootClassPathContainsATB = !addOptionalUpdater(packageUpdaters,
-                "android.content.pm.parsing.library.AndroidTestBaseUpdater",
-                RemoveUnnecessaryAndroidTestBaseLibrary::new);
+        boolean bootClassPathContainsATB = !addUpdaterForAndroidTestBase(packageUpdaters);
 
         PackageSharedLibraryUpdater[] updaterArray = packageUpdaters
                 .toArray(new PackageSharedLibraryUpdater[0]);
@@ -70,41 +64,31 @@
     }
 
     /**
-     * Add an optional {@link PackageSharedLibraryUpdater} instance to the list, if it could not be
-     * found then add a default instance instead.
+     * Attempt to load and add the optional updater that will only be available when
+     * REMOVE_ATB_FROM_BCP=true. If that could not be found then add the default updater that
+     * will remove any references to org.apache.http.library from the package so that
+     * it does not try and load the library when it is on the bootclasspath.
      *
-     * @param packageUpdaters the list to update.
-     * @param className the name of the optional class.
-     * @param defaultUpdater the supplier of the default instance.
-     * @return true if the optional updater was added false otherwise.
+     * TODO:(b/135203078): Find a better way to do this.
      */
-    private static boolean addOptionalUpdater(List<PackageSharedLibraryUpdater> packageUpdaters,
-            String className, Supplier<PackageSharedLibraryUpdater> defaultUpdater) {
-        Class<? extends PackageSharedLibraryUpdater> clazz;
+    private static boolean addUpdaterForAndroidTestBase(
+            List<PackageSharedLibraryUpdater> packageUpdaters) {
+        boolean hasClass = false;
+        String className = "android.content.pm.AndroidTestBaseUpdater";
         try {
-            clazz = (PackageBackwardCompatibility.class.getClassLoader()
-                    .loadClass(className)
-                    .asSubclass(PackageSharedLibraryUpdater.class));
+            Class clazz = (PackageParser.class.getClassLoader().loadClass(className));
+            hasClass = clazz != null;
             Log.i(TAG, "Loaded " + className);
         } catch (ClassNotFoundException e) {
             Log.i(TAG, "Could not find " + className + ", ignoring");
-            clazz = null;
         }
 
-        boolean usedOptional = false;
-        PackageSharedLibraryUpdater updater;
-        if (clazz == null) {
-            updater = defaultUpdater.get();
+        if (hasClass) {
+            packageUpdaters.add(new AndroidTestBaseUpdater());
         } else {
-            try {
-                updater = clazz.getConstructor().newInstance();
-                usedOptional = true;
-            } catch (ReflectiveOperationException e) {
-                throw new IllegalStateException("Could not create instance of " + className, e);
-            }
+            packageUpdaters.add(new RemoveUnnecessaryAndroidTestBaseLibrary());
         }
-        packageUpdaters.add(updater);
-        return usedOptional;
+        return hasClass;
     }
 
     @VisibleForTesting
@@ -129,14 +113,15 @@
      * @param parsedPackage the {@link ParsedPackage} to modify.
      */
     @VisibleForTesting
-    public static void modifySharedLibraries(ParsedPackage parsedPackage) {
-        INSTANCE.updatePackage(parsedPackage);
+    public static void modifySharedLibraries(ParsedPackage parsedPackage,
+            boolean isUpdatedSystemApp) {
+        INSTANCE.updatePackage(parsedPackage, isUpdatedSystemApp);
     }
 
     @Override
-    public void updatePackage(ParsedPackage parsedPackage) {
+    public void updatePackage(ParsedPackage parsedPackage, boolean isUpdatedSystemApp) {
         for (PackageSharedLibraryUpdater packageUpdater : mPackageUpdaters) {
-            packageUpdater.updatePackage(parsedPackage);
+            packageUpdater.updatePackage(parsedPackage, isUpdatedSystemApp);
         }
     }
 
@@ -161,7 +146,7 @@
     public static class AndroidTestRunnerSplitUpdater extends PackageSharedLibraryUpdater {
 
         @Override
-        public void updatePackage(ParsedPackage parsedPackage) {
+        public void updatePackage(ParsedPackage parsedPackage, boolean isUpdatedSystemApp) {
             // android.test.runner has a dependency on android.test.mock so if android.test.runner
             // is present but android.test.mock is not then add android.test.mock.
             prefixImplicitDependency(parsedPackage, ANDROID_TEST_RUNNER, ANDROID_TEST_MOCK);
@@ -177,7 +162,7 @@
             extends PackageSharedLibraryUpdater {
 
         @Override
-        public void updatePackage(ParsedPackage parsedPackage) {
+        public void updatePackage(ParsedPackage parsedPackage, boolean isUpdatedSystemApp) {
             removeLibrary(parsedPackage, ORG_APACHE_HTTP_LEGACY);
         }
 
@@ -192,7 +177,7 @@
             extends PackageSharedLibraryUpdater {
 
         @Override
-        public void updatePackage(ParsedPackage parsedPackage) {
+        public void updatePackage(ParsedPackage parsedPackage, boolean isUpdatedSystemApp) {
             removeLibrary(parsedPackage, ANDROID_TEST_BASE);
         }
     }
diff --git a/core/java/android/content/pm/parsing/library/PackageSharedLibraryUpdater.java b/services/core/java/com/android/server/pm/parsing/library/PackageSharedLibraryUpdater.java
similarity index 94%
rename from core/java/android/content/pm/parsing/library/PackageSharedLibraryUpdater.java
rename to services/core/java/com/android/server/pm/parsing/library/PackageSharedLibraryUpdater.java
index 8b27d14..123b808 100644
--- a/core/java/android/content/pm/parsing/library/PackageSharedLibraryUpdater.java
+++ b/services/core/java/com/android/server/pm/parsing/library/PackageSharedLibraryUpdater.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2019 The Android Open Source Project
+ * 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.
@@ -13,14 +13,14 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.content.pm.parsing.library;
+package com.android.server.pm.parsing.library;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.content.pm.parsing.ParsedPackage;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ArrayUtils;
+import com.android.server.pm.parsing.pkg.ParsedPackage;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -38,7 +38,7 @@
      *
      * @param parsedPackage the package to update.
      */
-    public abstract void updatePackage(ParsedPackage parsedPackage);
+    public abstract void updatePackage(ParsedPackage parsedPackage, boolean isUpdatedSystemApp);
 
     static void removeLibrary(ParsedPackage parsedPackage, String libraryName) {
         parsedPackage.removeUsesLibrary(libraryName)
diff --git a/core/java/android/content/pm/parsing/library/SharedLibraryNames.java b/services/core/java/com/android/server/pm/parsing/library/SharedLibraryNames.java
similarity index 91%
rename from core/java/android/content/pm/parsing/library/SharedLibraryNames.java
rename to services/core/java/com/android/server/pm/parsing/library/SharedLibraryNames.java
index 7b691c0..f62f014 100644
--- a/core/java/android/content/pm/parsing/library/SharedLibraryNames.java
+++ b/services/core/java/com/android/server/pm/parsing/library/SharedLibraryNames.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2019 The Android Open Source Project
+ * 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.
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.content.pm.parsing.library;
+package com.android.server.pm.parsing.library;
 
 /**
  * A set of shared library names
diff --git a/core/java/android/content/pm/parsing/AndroidPackage.aidl b/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackage.aidl
similarity index 100%
rename from core/java/android/content/pm/parsing/AndroidPackage.aidl
rename to services/core/java/com/android/server/pm/parsing/pkg/AndroidPackage.aidl
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
new file mode 100644
index 0000000..7929579
--- /dev/null
+++ b/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackage.java
@@ -0,0 +1,311 @@
+/*
+ * 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.pkg;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageParser;
+import android.content.pm.PermissionGroupInfo;
+import android.content.pm.SharedLibraryInfo;
+import android.content.pm.parsing.ParsingPackageRead;
+import android.content.pm.parsing.component.ParsedFeature;
+import android.content.pm.parsing.component.ParsedIntentInfo;
+import android.content.pm.parsing.component.ParsedPermissionGroup;
+import android.os.Bundle;
+import android.os.Parcelable;
+import android.util.ArraySet;
+import android.util.Pair;
+
+import com.android.internal.R;
+
+import java.security.PublicKey;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
+
+/**
+ * The last state of a package during parsing/install before it is available in
+ * {@link com.android.server.pm.PackageManagerService#mPackages}.
+ *
+ * It is the responsibility of the caller to understand what data is available at what step of the
+ * parsing or install process.
+ *
+ * TODO(b/135203078): Nullability annotations
+ * TODO(b/135203078): Remove get/setAppInfo differences
+ *
+ * @hide
+ */
+public interface AndroidPackage extends PkgAppInfo, PkgPackageInfo, ParsingPackageRead, Parcelable {
+
+    /**
+     * The names of packages to adopt ownership of permissions from, parsed under
+     * {@link PackageParser#TAG_ADOPT_PERMISSIONS}.
+     * @see R.styleable#AndroidManifestOriginalPackage_name
+     */
+    @NonNull
+    List<String> getAdoptPermissions();
+
+    /** Path of base APK */
+    @NonNull
+    String getBaseCodePath();
+
+    /** Revision code of base APK */
+    int getBaseRevisionCode();
+
+    /**
+     * Path where this package was found on disk. For monolithic packages
+     * this is path to single base APK file; for cluster packages this is
+     * path to the cluster directory.
+     */
+    @NonNull
+    String getCodePath();
+
+    /**
+     * Permissions requested but not in the manifest. These may have been split or migrated from
+     * previous versions/definitions.
+     */
+    @NonNull
+    List<String> getImplicitPermissions();
+
+    /**
+     * For use with {@link com.android.server.pm.KeySetManagerService}. Parsed in
+     * {@link PackageParser#TAG_KEY_SETS}.
+     * @see R.styleable#AndroidManifestKeySet
+     * @see R.styleable#AndroidManifestPublicKey
+     */
+    @NonNull
+    Map<String, ArraySet<PublicKey>> getKeySetMapping();
+
+    /**
+     * Library names this package is declared as, for use by other packages with "uses-library".
+     * @see R.styleable#AndroidManifestLibrary
+     */
+    @NonNull
+    List<String> getLibraryNames();
+
+    /**
+     * The package name as declared in the manifest, since the package can be renamed. For example,
+     * static shared libs use synthetic package names.
+     */
+    @NonNull
+    String getManifestPackageName();
+
+    /**
+     * We store the application meta-data independently to avoid multiple unwanted references
+     * TODO(b/135203078): What does this comment mean?
+     * TODO(b/135203078): Make all the Bundles immutable (and non-null by shared empty reference?)
+     */
+    @Nullable
+    Bundle getMetaData();
+
+    /**
+     * For system use to migrate from an old package name to a new one, moving over data
+     * if available.
+     * @see R.styleable#AndroidManifestOriginalPackage}
+     */
+    @NonNull
+    List<String> getOriginalPackages();
+
+    /**
+     * Map of overlayable name to actor name.
+     */
+    @NonNull
+    Map<String, String> getOverlayables();
+
+    /**
+     * The name of the package as used to identify it in the system. This may be adjusted by the
+     * system from the value declared in the manifest, and may not correspond to a Java code
+     * package.
+     * @see ApplicationInfo#packageName
+     * @see PackageInfo#packageName
+     */
+    @NonNull
+    String getPackageName();
+
+    /**
+     * @see PermissionGroupInfo
+     */
+    @NonNull
+    List<ParsedPermissionGroup> getPermissionGroups();
+
+    @NonNull
+    List<ParsedFeature> getFeatures();
+
+    /**
+     * Used to determine the default preferred handler of an {@link Intent}.
+     *
+     * Map of component className to intent info inside that component.
+     * TODO(b/135203078): Is this actually used/working?
+     */
+    @NonNull
+    List<Pair<String, ParsedIntentInfo>> getPreferredActivityFilters();
+
+    /**
+     * System protected broadcasts.
+     * @see R.styleable#AndroidManifestProtectedBroadcast
+     */
+    @NonNull
+    List<String> getProtectedBroadcasts();
+
+    /**
+     * Intents that this package may query or require and thus requires visibility into.
+     * @see R.styleable#AndroidManifestQueriesIntent
+     */
+    @NonNull
+    List<Intent> getQueriesIntents();
+
+    /**
+     * Other packages that this package may query or require and thus requires visibility into.
+     * @see R.styleable#AndroidManifestQueriesPackage
+     */
+    @NonNull
+    List<String> getQueriesPackages();
+
+    /**
+     * If a system app declares {@link #getOriginalPackages()}, and the app was previously installed
+     * under one of those original package names, the {@link #getPackageName()} system identifier
+     * will be changed to that previously installed name. This will then be non-null, set to the
+     * manifest package name, for tracking the package under its true name.
+     *
+     * TODO(b/135203078): Remove this in favor of checking originalPackages.isEmpty and
+     *  getManifestPackageName
+     */
+    @Nullable
+    String getRealPackage();
+
+    /**
+     * SHA-512 hash of the only APK that can be used to update a system package.
+     * @see R.styleable#AndroidManifestRestrictUpdate
+     */
+    @Nullable
+    byte[] getRestrictUpdateHash();
+
+    /**
+     * The signature data of all APKs in this package, which must be exactly the same across the
+     * base and splits.
+     */
+    PackageParser.SigningDetails getSigningDetails();
+
+    /**
+     * TODO(b/135203078): Move split stuff to an inner data class
+     * @see ApplicationInfo#splitNames
+     * @see PackageInfo#splitNames
+     */
+    @Nullable
+    String[] getSplitNames();
+
+    /** Flags of any split APKs; ordered by parsed splitName */
+    @Nullable
+    int[] getSplitFlags();
+
+    /** @see R.styleable#AndroidManifestStaticLibrary_name */
+    @Nullable
+    String getStaticSharedLibName();
+
+    /** @see R.styleable#AndroidManifestStaticLibrary_version */
+    long getStaticSharedLibVersion();
+
+    /**
+     * {@link android.os.storage.StorageManager#convert(String)} version of
+     * {@link #getVolumeUuid()}.
+     * TODO(b/135203078): All usages call toString() on this. Can the string be returned directly,
+     *  or does the parsing logic in StorageManager have to run?
+     */
+    UUID getStorageUuid();
+
+    /**
+     * For use with {@link com.android.server.pm.KeySetManagerService}. Parsed in
+     * {@link PackageParser#TAG_KEY_SETS}.
+     * @see R.styleable#AndroidManifestUpgradeKeySet
+     */
+    @NonNull
+    Set<String> getUpgradeKeySets();
+
+    /** @see R.styleable#AndroidManifestUsesLibrary */
+    @NonNull
+    List<String> getUsesLibraries();
+
+    /**
+     * Like {@link #getUsesLibraries()}, but marked optional by setting
+     * {@link R.styleable#AndroidManifestUsesLibrary_required} to false . Application is expected
+     * to handle absence manually.
+     * @see R.styleable#AndroidManifestUsesLibrary
+     */
+    @NonNull
+    List<String> getUsesOptionalLibraries();
+
+    /**
+     * TODO(b/135203078): Move static library stuff to an inner data class
+     * @see R.styleable#AndroidManifestUsesStaticLibrary
+     */
+    @NonNull
+    List<String> getUsesStaticLibraries();
+
+    /** @see R.styleable#AndroidManifestUsesStaticLibrary_certDigest */
+    @Nullable
+    String[][] getUsesStaticLibrariesCertDigests();
+
+    /** @see R.styleable#AndroidManifestUsesStaticLibrary_version */
+    @Nullable
+    long[] getUsesStaticLibrariesVersions();
+
+    /** @see R.styleable#AndroidManifestApplication_forceQueryable */
+    boolean isForceQueryable();
+
+    boolean isCrossProfile();
+
+    /**
+     * The install time abi override to choose 32bit abi's when multiple abi's
+     * are present. This is only meaningfull for multiarch applications.
+     */
+    boolean isUse32BitAbi();
+
+    /**
+     * Set if the any of components are visible to instant applications.
+     * @see R.styleable#AndroidManifestActivity_visibleToInstantApps
+     * @see R.styleable#AndroidManifestProvider_visibleToInstantApps
+     * @see R.styleable#AndroidManifestService_visibleToInstantApps
+     */
+    boolean isVisibleToInstantApps();
+
+    /**
+     * Generates an {@link ApplicationInfo} object with only the data available in this object.
+     *
+     * TODO(b/135203078): Actually add this
+     * This does not contain any system or user state data, and should be avoided. Prefer
+     * com.android.server.pm.parsing.PackageInfoUtils#generateApplicationInfo(
+     * AndroidPackage, int, PackageUserState, int, com.android.server.pm.PackageSetting)
+     *
+     * @deprecated Access AndroidPackage fields directly.
+     */
+    @Deprecated
+    @NonNull
+    ApplicationInfo toAppInfoWithoutState();
+
+    /**
+     * TODO(b/135203078): Remove usages?
+     * @return a mock of what the previous package.applicationInfo would've returned for logging
+     * @deprecated don't use this in any new code, just print package name directly
+     */
+    @Deprecated
+    @NonNull
+    String toAppInfoToString();
+}
diff --git a/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java b/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java
new file mode 100644
index 0000000..780b234
--- /dev/null
+++ b/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java
@@ -0,0 +1,291 @@
+/*
+ * 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.pkg;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageParser;
+import android.content.pm.PackageParser.PackageParserException;
+import android.content.pm.SharedLibraryInfo;
+import android.content.pm.VersionedPackage;
+import android.content.pm.dex.DexMetadataHelper;
+import android.content.pm.parsing.ParsingPackageRead;
+import android.content.pm.parsing.component.ParsedActivity;
+import android.content.pm.parsing.component.ParsedInstrumentation;
+import android.content.pm.parsing.component.ParsedProvider;
+import android.content.pm.parsing.component.ParsedService;
+import android.text.TextUtils;
+
+import com.android.internal.content.NativeLibraryHelper;
+import com.android.internal.util.ArrayUtils;
+import com.android.server.SystemConfig;
+import com.android.server.pm.PackageSetting;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+/** @hide */
+public class AndroidPackageUtils {
+
+    private AndroidPackageUtils() {
+    }
+
+    public static List<String> getAllCodePathsExcludingResourceOnly(
+            AndroidPackage aPkg) {
+        PackageImpl pkg = (PackageImpl) aPkg;
+        ArrayList<String> paths = new ArrayList<>();
+        if (pkg.isHasCode()) {
+            paths.add(pkg.getBaseCodePath());
+        }
+        String[] splitCodePaths = pkg.getSplitCodePaths();
+        if (!ArrayUtils.isEmpty(splitCodePaths)) {
+            for (int i = 0; i < splitCodePaths.length; i++) {
+                if ((pkg.getSplitFlags()[i] & ApplicationInfo.FLAG_HAS_CODE) != 0) {
+                    paths.add(splitCodePaths[i]);
+                }
+            }
+        }
+        return paths;
+    }
+
+    /**
+     * @return a list of the base and split code paths.
+     */
+    public static List<String> getAllCodePaths(AndroidPackage aPkg) {
+        PackageImpl pkg = (PackageImpl) aPkg;
+        ArrayList<String> paths = new ArrayList<>();
+        paths.add(pkg.getBaseCodePath());
+
+        String[] splitCodePaths = pkg.getSplitCodePaths();
+        if (!ArrayUtils.isEmpty(splitCodePaths)) {
+            Collections.addAll(paths, splitCodePaths);
+        }
+        return paths;
+    }
+
+    public static SharedLibraryInfo createSharedLibraryForStatic(AndroidPackage pkg) {
+        return new SharedLibraryInfo(null, pkg.getPackageName(),
+                AndroidPackageUtils.getAllCodePaths(pkg),
+                pkg.getStaticSharedLibName(),
+                pkg.getStaticSharedLibVersion(),
+                SharedLibraryInfo.TYPE_STATIC,
+                new VersionedPackage(pkg.getManifestPackageName(),
+                        pkg.getLongVersionCode()),
+                null, null);
+    }
+
+    public static SharedLibraryInfo createSharedLibraryForDynamic(AndroidPackage pkg, String name) {
+        return new SharedLibraryInfo(null, pkg.getPackageName(),
+                AndroidPackageUtils.getAllCodePaths(pkg), name,
+                SharedLibraryInfo.VERSION_UNDEFINED,
+                SharedLibraryInfo.TYPE_DYNAMIC, new VersionedPackage(pkg.getPackageName(),
+                pkg.getLongVersionCode()),
+                null, null);
+    }
+
+    /**
+     * Return the dex metadata files for the given package as a map
+     * [code path -> dex metadata path].
+     *
+     * NOTE: involves I/O checks.
+     */
+    public static Map<String, String> getPackageDexMetadata(AndroidPackage pkg) {
+        return DexMetadataHelper.buildPackageApkToDexMetadataMap
+                (AndroidPackageUtils.getAllCodePaths(pkg));
+    }
+
+    /**
+     * Validate the dex metadata files installed for the given package.
+     *
+     * @throws PackageParserException in case of errors.
+     */
+    public static void validatePackageDexMetadata(AndroidPackage pkg)
+            throws PackageParserException {
+        Collection<String> apkToDexMetadataList = getPackageDexMetadata(pkg).values();
+        for (String dexMetadata : apkToDexMetadataList) {
+            DexMetadataHelper.validateDexMetadataFile(dexMetadata);
+        }
+    }
+
+    public static NativeLibraryHelper.Handle createNativeLibraryHandle(AndroidPackage pkg)
+            throws IOException {
+        return NativeLibraryHelper.Handle.create(
+                AndroidPackageUtils.getAllCodePaths(pkg),
+                pkg.isMultiArch(),
+                pkg.isExtractNativeLibs(),
+                pkg.isDebuggable()
+        );
+    }
+
+    public static boolean canHaveOatDir(AndroidPackage pkg, boolean isUpdatedSystemApp) {
+        // The following app types CANNOT have oat directory
+        // - non-updated system apps
+        return !pkg.isSystem() || isUpdatedSystemApp;
+    }
+
+    public static boolean hasComponentClassName(AndroidPackage pkg, String className) {
+        List<ParsedActivity> activities = pkg.getActivities();
+        int activitiesSize = activities.size();
+        for (int index = 0; index < activitiesSize; index++) {
+            if (Objects.equals(className, activities.get(index).getName())) {
+                return true;
+            }
+        }
+
+        List<ParsedActivity> receivers = pkg.getReceivers();
+        int receiversSize = receivers.size();
+        for (int index = 0; index < receiversSize; index++) {
+            if (Objects.equals(className, receivers.get(index).getName())) {
+                return true;
+            }
+        }
+
+        List<ParsedProvider> providers = pkg.getProviders();
+        int providersSize = providers.size();
+        for (int index = 0; index < providersSize; index++) {
+            if (Objects.equals(className, providers.get(index).getName())) {
+                return true;
+            }
+        }
+
+        List<ParsedService> services = pkg.getServices();
+        int servicesSize = services.size();
+        for (int index = 0; index < servicesSize; index++) {
+            if (Objects.equals(className, services.get(index).getName())) {
+                return true;
+            }
+        }
+
+        List<ParsedInstrumentation> instrumentations = pkg.getInstrumentations();
+        int instrumentationsSize = instrumentations.size();
+        for (int index = 0; index < instrumentationsSize; index++) {
+            if (Objects.equals(className, instrumentations.get(index).getName())) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    public static boolean isEncryptionAware(AndroidPackage pkg) {
+        return pkg.isDirectBootAware() || pkg.isPartiallyDirectBootAware();
+    }
+
+    public static boolean isLibrary(AndroidPackage pkg) {
+        // TODO(b/135203078): Can parsing just enforce these always match?
+        return pkg.getStaticSharedLibName() != null || !pkg.getLibraryNames().isEmpty();
+    }
+
+    public static int getHiddenApiEnforcementPolicy(AndroidPackage pkg,
+            @NonNull PackageSetting pkgSetting) {
+        boolean isAllowedToUseHiddenApis;
+        if (pkg.isSignedWithPlatformKey()) {
+            isAllowedToUseHiddenApis = true;
+        } else if (pkg.isSystem() || pkgSetting.getPkgState().isUpdatedSystemApp()) {
+            isAllowedToUseHiddenApis = pkg.isUsesNonSdkApi()
+                    || SystemConfig.getInstance().getHiddenApiWhitelistedApps().contains(
+                    pkg.getPackageName());
+        } else {
+            isAllowedToUseHiddenApis = false;
+        }
+
+        if (isAllowedToUseHiddenApis) {
+            return ApplicationInfo.HIDDEN_API_ENFORCEMENT_DISABLED;
+        }
+
+        // TODO(b/135203078): Handle maybeUpdateHiddenApiEnforcementPolicy. Right now it's done
+        //  entirely through ApplicationInfo and shouldn't touch this specific class, but that
+        //  may not always hold true.
+//        if (mHiddenApiPolicy != ApplicationInfo.HIDDEN_API_ENFORCEMENT_DEFAULT) {
+//            return mHiddenApiPolicy;
+//        }
+        return ApplicationInfo.HIDDEN_API_ENFORCEMENT_ENABLED;
+    }
+
+    public static int getIcon(ParsingPackageRead pkg) {
+        return (PackageParser.sUseRoundIcon && pkg.getRoundIconRes() != 0)
+                ? pkg.getRoundIconRes() : pkg.getIconRes();
+    }
+
+    public static long getLongVersionCode(AndroidPackage pkg) {
+        return PackageInfo.composeLongVersionCode(pkg.getVersionCodeMajor(), pkg.getVersionCode());
+    }
+
+    public static boolean isMatchForSystemOnly(AndroidPackage pkg, int flags) {
+        if ((flags & PackageManager.MATCH_SYSTEM_ONLY) != 0) {
+            return pkg.isSystem();
+        }
+        return true;
+    }
+
+    public static String getPrimaryCpuAbi(AndroidPackage pkg, @Nullable PackageSetting pkgSetting) {
+        if (pkgSetting == null || TextUtils.isEmpty(pkgSetting.primaryCpuAbiString)) {
+            return pkg.getPrimaryCpuAbi();
+        }
+
+        return pkgSetting.primaryCpuAbiString;
+    }
+
+    public static String getSecondaryCpuAbi(AndroidPackage pkg,
+            @Nullable PackageSetting pkgSetting) {
+        if (pkgSetting == null || TextUtils.isEmpty(pkgSetting.secondaryCpuAbiString)) {
+            return pkg.getSecondaryCpuAbi();
+        }
+
+        return pkgSetting.secondaryCpuAbiString;
+    }
+
+    /**
+     * Returns the primary ABI as parsed from the package. Used only during parsing and derivation.
+     * Otherwise prefer {@link #getPrimaryCpuAbi(AndroidPackage, PackageSetting)}.
+     *
+     * TODO(b/135203078): Actually hide the method
+     * Placed in the utility to hide the method on the interface.
+     */
+    public static String getRawPrimaryCpuAbi(AndroidPackage pkg) {
+        return pkg.getPrimaryCpuAbi();
+    }
+
+    /**
+     * Returns the secondary ABI as parsed from the package. Used only during parsing and
+     * derivation. Otherwise prefer {@link #getSecondaryCpuAbi(AndroidPackage, PackageSetting)}.
+     *
+     * TODO(b/135203078): Actually hide the method
+     * Placed in the utility to hide the method on the interface.
+     */
+    public static String getRawSecondaryCpuAbi(AndroidPackage pkg) {
+        return pkg.getSecondaryCpuAbi();
+    }
+
+    public static String getSeInfo(AndroidPackage pkg, @Nullable PackageSetting pkgSetting) {
+        if (pkgSetting != null) {
+            String overrideSeInfo = pkgSetting.getPkgState().getOverrideSeInfo();
+            if (!TextUtils.isEmpty(overrideSeInfo)) {
+                return overrideSeInfo;
+            }
+        }
+        return pkg.getSeInfo();
+    }
+}
diff --git a/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java b/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java
new file mode 100644
index 0000000..2b508ea
--- /dev/null
+++ b/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java
@@ -0,0 +1,752 @@
+/*
+ * 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.pkg;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageParser;
+import android.content.pm.SharedLibraryInfo;
+import android.content.pm.parsing.ParsingPackage;
+import android.content.pm.parsing.ParsingPackageImpl;
+import android.content.pm.parsing.component.ParsedActivity;
+import android.content.pm.parsing.component.ParsedMainComponent;
+import android.content.pm.parsing.component.ParsedProvider;
+import android.content.pm.parsing.component.ParsedService;
+import android.content.res.TypedArray;
+import android.os.Environment;
+import android.os.Parcel;
+import android.os.UserHandle;
+import android.os.storage.StorageManager;
+import android.text.TextUtils;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.CollectionUtils;
+import com.android.internal.util.DataClass;
+import com.android.internal.util.Parcelling;
+import com.android.internal.util.Parcelling.BuiltIn.ForInternedString;
+import com.android.server.pm.parsing.PackageInfoUtils;
+
+import java.util.Comparator;
+import java.util.List;
+import java.util.UUID;
+
+/**
+ * Extensions to {@link ParsingPackageImpl} including fields/state contained in the system server
+ * and not exposed to the core SDK.
+ *
+ * Many of the fields contained here will eventually be moved inside
+ * {@link com.android.server.pm.PackageSetting} or {@link android.content.pm.PackageUserState}.
+ *
+ * @hide
+ */
+public final class PackageImpl extends ParsingPackageImpl implements ParsedPackage, AndroidPackage {
+
+    public static PackageImpl forParsing(@NonNull String packageName, @NonNull String baseCodePath,
+            @NonNull String codePath, @NonNull TypedArray manifestArray, boolean isCoreApp) {
+        return new PackageImpl(packageName, baseCodePath, codePath, manifestArray, isCoreApp);
+    }
+
+    /**
+     * Mock an unavailable {@link AndroidPackage} to use when
+     * removing
+     * a package from the system.
+     * This can occur if the package was installed on a storage device that has since been removed.
+     * Since the infrastructure uses {@link AndroidPackage}, but
+     * for
+     * this case only cares about
+     * volumeUuid, just fake it rather than having separate method paths.
+     */
+    public static AndroidPackage buildFakeForDeletion(String packageName, String volumeUuid) {
+        return ((ParsedPackage) PackageImpl.forTesting(packageName)
+                .setVolumeUuid(volumeUuid)
+                .hideAsParsed())
+                .hideAsFinal();
+    }
+
+    @VisibleForTesting
+    public static ParsingPackage forTesting(String packageName) {
+        return forTesting(packageName, "");
+    }
+
+    @VisibleForTesting
+    public static ParsingPackage forTesting(String packageName, String baseCodePath) {
+        return new PackageImpl(packageName, baseCodePath, baseCodePath, null, false);
+    }
+
+    @NonNull
+    @DataClass.ParcelWith(ForInternedString.class)
+    private final String manifestPackageName;
+
+    private boolean stub;
+
+    @Nullable
+    @DataClass.ParcelWith(ForInternedString.class)
+    protected String nativeLibraryDir;
+
+    @Nullable
+    @DataClass.ParcelWith(ForInternedString.class)
+    protected String nativeLibraryRootDir;
+
+    private boolean nativeLibraryRootRequiresIsa;
+
+    @Nullable
+    @DataClass.ParcelWith(ForInternedString.class)
+    protected String primaryCpuAbi;
+    @Nullable
+    @DataClass.ParcelWith(ForInternedString.class)
+    protected String secondaryCpuAbi;
+    @Nullable
+    @DataClass.ParcelWith(ForInternedString.class)
+    protected String secondaryNativeLibraryDir;
+
+    @Nullable
+    @DataClass.ParcelWith(ForInternedString.class)
+    protected String seInfo;
+    @Nullable
+    @DataClass.ParcelWith(ForInternedString.class)
+    protected String seInfoUser;
+
+    private boolean coreApp;
+
+    private boolean system;
+    private boolean factoryTest;
+
+    private boolean systemExt;
+    private boolean privileged;
+    private boolean oem;
+    private boolean vendor;
+    private boolean product;
+    private boolean odm;
+
+    private boolean signedWithPlatformKey;
+
+    /**
+     * This is an appId, the uid if the userId is == USER_SYSTEM
+     */
+    private int uid = -1;
+
+    @VisibleForTesting
+    public PackageImpl(@NonNull String packageName, @NonNull String baseCodePath,
+            @NonNull String codePath, @Nullable TypedArray manifestArray, boolean isCoreApp) {
+        super(packageName, baseCodePath, codePath, manifestArray);
+        this.manifestPackageName = this.packageName;
+        this.coreApp = isCoreApp;
+    }
+
+    @Override
+    public ParsedPackage hideAsParsed() {
+        return this;
+    }
+
+    @Override
+    public AndroidPackage hideAsFinal() {
+        // TODO(b/135203078): Lock as immutable
+        return this;
+    }
+
+    @Override
+    public long getLongVersionCode() {
+        return PackageInfo.composeLongVersionCode(versionCodeMajor, versionCode);
+    }
+
+    @Override
+    public PackageImpl removePermission(int index) {
+        this.permissions.remove(index);
+        return this;
+    }
+
+    @Override
+    public PackageImpl addUsesOptionalLibrary(int index, String libraryName) {
+        this.usesOptionalLibraries = CollectionUtils.add(usesOptionalLibraries, index,
+                TextUtils.safeIntern(libraryName));
+        return this;
+    }
+
+    @Override
+    public PackageImpl addUsesLibrary(int index, String libraryName) {
+        this.usesLibraries = CollectionUtils.add(usesLibraries, index,
+                TextUtils.safeIntern(libraryName));
+        return this;
+    }
+
+    @Override
+    public PackageImpl removeUsesLibrary(String libraryName) {
+        this.usesLibraries = CollectionUtils.remove(this.usesLibraries, libraryName);
+        return this;
+    }
+
+    @Override
+    public PackageImpl removeUsesOptionalLibrary(String libraryName) {
+        super.removeUsesOptionalLibrary(libraryName);
+        return this;
+    }
+
+    @Override
+    public PackageImpl setSigningDetails(@Nullable PackageParser.SigningDetails value) {
+        super.setSigningDetails(value);
+        return this;
+    }
+
+    @Override
+    public PackageImpl setRestrictUpdateHash(@Nullable byte... value) {
+        super.setRestrictUpdateHash(value);
+        return this;
+    }
+
+    @Override
+    public PackageImpl setRealPackage(@Nullable String realPackage) {
+        super.setRealPackage(realPackage);
+        return this;
+    }
+
+    @Override
+    public PackageImpl setPersistent(boolean value) {
+        super.setPersistent(value);
+        return this;
+    }
+
+    @Override
+    public PackageImpl setDefaultToDeviceProtectedStorage(boolean value) {
+        super.setDefaultToDeviceProtectedStorage(value);
+        return this;
+    }
+
+    @Override
+    public PackageImpl setDirectBootAware(boolean value) {
+        super.setDirectBootAware(value);
+        return this;
+    }
+
+    @Override
+    public PackageImpl clearProtectedBroadcasts() {
+        protectedBroadcasts.clear();
+        return this;
+    }
+
+    @Override
+    public PackageImpl clearOriginalPackages() {
+        originalPackages.clear();
+        return this;
+    }
+
+    @Override
+    public PackageImpl clearAdoptPermissions() {
+        adoptPermissions.clear();
+        return this;
+    }
+
+    @Override
+    public PackageImpl setCodePath(@NonNull String value) {
+        this.codePath = value;
+        return this;
+    }
+
+    // TODO(b/135203078): Move PackageManagerService#renameStaticSharedLibraryPackage
+    //  into initial package parsing
+    @Override
+    public PackageImpl setPackageName(@NonNull String packageName) {
+        this.packageName = TextUtils.safeIntern(packageName);
+
+        int permissionsSize = permissions.size();
+        for (int index = 0; index < permissionsSize; index++) {
+            permissions.get(index).setPackageName(this.packageName);
+        }
+
+        int permissionGroupsSize = permissionGroups.size();
+        for (int index = 0; index < permissionGroupsSize; index++) {
+            permissionGroups.get(index).setPackageName(this.packageName);
+        }
+
+        int activitiesSize = activities.size();
+        for (int index = 0; index < activitiesSize; index++) {
+            activities.get(index).setPackageName(this.packageName);
+        }
+
+        int receiversSize = receivers.size();
+        for (int index = 0; index < receiversSize; index++) {
+            receivers.get(index).setPackageName(this.packageName);
+        }
+
+        int providersSize = providers.size();
+        for (int index = 0; index < providersSize; index++) {
+            providers.get(index).setPackageName(this.packageName);
+        }
+
+        int servicesSize = services.size();
+        for (int index = 0; index < servicesSize; index++) {
+            services.get(index).setPackageName(this.packageName);
+        }
+
+        int instrumentationsSize = instrumentations.size();
+        for (int index = 0; index < instrumentationsSize; index++) {
+            instrumentations.get(index).setPackageName(this.packageName);
+        }
+
+        return this;
+    }
+
+    @Override
+    public PackageImpl setAllComponentsDirectBootAware(boolean allComponentsDirectBootAware) {
+        int activitiesSize = activities.size();
+        for (int index = 0; index < activitiesSize; index++) {
+            activities.get(index).setDirectBootAware(allComponentsDirectBootAware);
+        }
+
+        int receiversSize = receivers.size();
+        for (int index = 0; index < receiversSize; index++) {
+            receivers.get(index).setDirectBootAware(allComponentsDirectBootAware);
+        }
+
+        int providersSize = providers.size();
+        for (int index = 0; index < providersSize; index++) {
+            providers.get(index).setDirectBootAware(allComponentsDirectBootAware);
+        }
+
+        int servicesSize = services.size();
+        for (int index = 0; index < servicesSize; index++) {
+            services.get(index).setDirectBootAware(allComponentsDirectBootAware);
+        }
+
+        return this;
+    }
+
+    @Override
+    public PackageImpl setBaseCodePath(@NonNull String baseCodePath) {
+        this.baseCodePath = TextUtils.safeIntern(baseCodePath);
+        return this;
+    }
+
+    @Override
+    public PackageImpl setNativeLibraryDir(@Nullable String nativeLibraryDir) {
+        this.nativeLibraryDir = TextUtils.safeIntern(nativeLibraryDir);
+        return this;
+    }
+
+    @Override
+    public PackageImpl setNativeLibraryRootDir(@Nullable String nativeLibraryRootDir) {
+        this.nativeLibraryRootDir = TextUtils.safeIntern(nativeLibraryRootDir);
+        return this;
+    }
+
+    @Override
+    public PackageImpl setPrimaryCpuAbi(@Nullable String primaryCpuAbi) {
+        this.primaryCpuAbi = TextUtils.safeIntern(primaryCpuAbi);
+        return this;
+    }
+
+    @Override
+    public PackageImpl setSecondaryCpuAbi(@Nullable String secondaryCpuAbi) {
+        this.secondaryCpuAbi = TextUtils.safeIntern(secondaryCpuAbi);
+        return this;
+    }
+
+    @Override
+    public PackageImpl setSecondaryNativeLibraryDir(@Nullable String secondaryNativeLibraryDir) {
+        this.secondaryNativeLibraryDir = TextUtils.safeIntern(secondaryNativeLibraryDir);
+        return this;
+    }
+
+    @Override
+    public PackageImpl setSeInfo(@Nullable String seInfo) {
+        this.seInfo = TextUtils.safeIntern(seInfo);
+        return this;
+    }
+
+    @Override
+    public PackageImpl setSeInfoUser(@Nullable String seInfoUser) {
+        this.seInfoUser = TextUtils.safeIntern(seInfoUser);
+        return this;
+    }
+
+    @Override
+    public PackageImpl setSplitCodePaths(@Nullable String[] splitCodePaths) {
+        this.splitCodePaths = splitCodePaths;
+        if (splitCodePaths != null) {
+            int size = splitCodePaths.length;
+            for (int index = 0; index < size; index++) {
+                this.splitCodePaths[index] = TextUtils.safeIntern(this.splitCodePaths[index]);
+            }
+        }
+        return this;
+    }
+
+    @Override
+    public PackageImpl capPermissionPriorities() {
+        int size = permissionGroups.size();
+        for (int index = size - 1; index >= 0; --index) {
+            // TODO(b/135203078): Builder/immutability
+            permissionGroups.get(index).setPriority(0);
+        }
+        return this;
+    }
+
+    @Override
+    public PackageImpl markNotActivitiesAsNotExportedIfSingleUser() {
+        // ignore export request for single user receivers
+        int receiversSize = receivers.size();
+        for (int index = 0; index < receiversSize; index++) {
+            ParsedActivity receiver = receivers.get(index);
+            if ((receiver.getFlags() & ActivityInfo.FLAG_SINGLE_USER) != 0) {
+                receiver.setExported(false);
+            }
+        }
+
+        // ignore export request for single user services
+        int servicesSize = services.size();
+        for (int index = 0; index < servicesSize; index++) {
+            ParsedService service = services.get(index);
+            if ((service.getFlags() & ActivityInfo.FLAG_SINGLE_USER) != 0) {
+                service.setExported(false);
+            }
+        }
+
+        // ignore export request for single user providers
+        int providersSize = providers.size();
+        for (int index = 0; index < providersSize; index++) {
+            ParsedProvider provider = providers.get(index);
+            if ((provider.getFlags() & ActivityInfo.FLAG_SINGLE_USER) != 0) {
+                provider.setExported(false);
+            }
+        }
+
+        return this;
+    }
+
+    @Override
+    public UUID getStorageUuid() {
+        return StorageManager.convert(volumeUuid);
+    }
+
+    @Deprecated
+    @Override
+    public String toAppInfoToString() {
+        return "ApplicationInfo{"
+                + Integer.toHexString(System.identityHashCode(this))
+                + " " + getPackageName() + "}";
+    }
+
+    @Override
+    public ParsedPackage setCoreApp(boolean coreApp) {
+        this.coreApp = coreApp;
+        return this;
+    }
+
+    @Override
+    public ParsedPackage setVersionCode(int versionCode) {
+        this.versionCode = versionCode;
+        return this;
+    }
+
+    @Override
+    public ParsedPackage setVersionCodeMajor(int versionCodeMajor) {
+        this.versionCodeMajor = versionCodeMajor;
+        return this;
+    }
+
+    @Override
+    public ApplicationInfo toAppInfoWithoutState() {
+        ApplicationInfo appInfo = super.toAppInfoWithoutState();
+        appInfo.flags = PackageInfoUtils.appInfoFlags(this, null);
+        appInfo.privateFlags = PackageInfoUtils.appInfoPrivateFlags(this, null);
+        appInfo.nativeLibraryDir = nativeLibraryDir;
+        appInfo.nativeLibraryRootDir = nativeLibraryRootDir;
+        appInfo.nativeLibraryRootRequiresIsa = nativeLibraryRootRequiresIsa;
+        appInfo.primaryCpuAbi = primaryCpuAbi;
+        appInfo.secondaryCpuAbi = secondaryCpuAbi;
+        appInfo.secondaryNativeLibraryDir = secondaryNativeLibraryDir;
+        appInfo.seInfo = seInfo;
+        appInfo.seInfoUser = seInfoUser;
+        appInfo.uid = uid;
+        return appInfo;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        super.writeToParcel(dest, flags);
+        sForString.parcel(this.manifestPackageName, dest, flags);
+        dest.writeBoolean(this.stub);
+        sForString.parcel(this.nativeLibraryDir, dest, flags);
+        sForString.parcel(this.nativeLibraryRootDir, dest, flags);
+        dest.writeBoolean(this.nativeLibraryRootRequiresIsa);
+        sForString.parcel(this.primaryCpuAbi, dest, flags);
+        sForString.parcel(this.secondaryCpuAbi, dest, flags);
+        sForString.parcel(this.secondaryNativeLibraryDir, dest, flags);
+        sForString.parcel(this.seInfo, dest, flags);
+        sForString.parcel(this.seInfoUser, dest, flags);
+        dest.writeInt(this.uid);
+        dest.writeBoolean(this.coreApp);
+        dest.writeBoolean(this.system);
+        dest.writeBoolean(this.factoryTest);
+        dest.writeBoolean(this.systemExt);
+        dest.writeBoolean(this.privileged);
+        dest.writeBoolean(this.oem);
+        dest.writeBoolean(this.vendor);
+        dest.writeBoolean(this.product);
+        dest.writeBoolean(this.odm);
+        dest.writeBoolean(this.signedWithPlatformKey);
+    }
+
+    public PackageImpl(Parcel in) {
+        super(in);
+        this.manifestPackageName = sForString.unparcel(in);
+        this.stub = in.readBoolean();
+        this.nativeLibraryDir = sForString.unparcel(in);
+        this.nativeLibraryRootDir = sForString.unparcel(in);
+        this.nativeLibraryRootRequiresIsa = in.readBoolean();
+        this.primaryCpuAbi = sForString.unparcel(in);
+        this.secondaryCpuAbi = sForString.unparcel(in);
+        this.secondaryNativeLibraryDir = sForString.unparcel(in);
+        this.seInfo = sForString.unparcel(in);
+        this.seInfoUser = sForString.unparcel(in);
+        this.uid = in.readInt();
+        this.coreApp = in.readBoolean();
+        this.system = in.readBoolean();
+        this.factoryTest = in.readBoolean();
+        this.systemExt = in.readBoolean();
+        this.privileged = in.readBoolean();
+        this.oem = in.readBoolean();
+        this.vendor = in.readBoolean();
+        this.product = in.readBoolean();
+        this.odm = in.readBoolean();
+        this.signedWithPlatformKey = in.readBoolean();
+    }
+
+    public static final Creator<PackageImpl> CREATOR = new Creator<PackageImpl>() {
+        @Override
+        public PackageImpl createFromParcel(Parcel source) {
+            return new PackageImpl(source);
+        }
+
+        @Override
+        public PackageImpl[] newArray(int size) {
+            return new PackageImpl[size];
+        }
+    };
+
+    @NonNull
+    @Override
+    public String getManifestPackageName() {
+        return manifestPackageName;
+    }
+
+    @DataClass.Generated.Member
+    public boolean isStub() {
+        return stub;
+    }
+
+    @Nullable
+    @Override
+    public String getNativeLibraryDir() {
+        return nativeLibraryDir;
+    }
+
+    @Nullable
+    @Override
+    public String getNativeLibraryRootDir() {
+        return nativeLibraryRootDir;
+    }
+
+    @Override
+    public boolean isNativeLibraryRootRequiresIsa() {
+        return nativeLibraryRootRequiresIsa;
+    }
+
+    @Nullable
+    @Override
+    public String getPrimaryCpuAbi() {
+        return primaryCpuAbi;
+    }
+
+    @Nullable
+    @Override
+    public String getSecondaryCpuAbi() {
+        return secondaryCpuAbi;
+    }
+
+    @Nullable
+    @Override
+    public String getSecondaryNativeLibraryDir() {
+        return secondaryNativeLibraryDir;
+    }
+
+    @Nullable
+    @Override
+    public String getSeInfo() {
+        return seInfo;
+    }
+
+    @Nullable
+    @Override
+    public String getSeInfoUser() {
+        return seInfoUser;
+    }
+
+    @Override
+    public boolean isCoreApp() {
+        return coreApp;
+    }
+
+    @Override
+    public boolean isSystem() {
+        return system;
+    }
+
+    @Override
+    public boolean isFactoryTest() {
+        return factoryTest;
+    }
+
+    @Override
+    public boolean isSystemExt() {
+        return systemExt;
+    }
+
+    @Override
+    public boolean isPrivileged() {
+        return privileged;
+    }
+
+    @Override
+    public boolean isOem() {
+        return oem;
+    }
+
+    @Override
+    public boolean isVendor() {
+        return vendor;
+    }
+
+    @Override
+    public boolean isProduct() {
+        return product;
+    }
+
+    @Override
+    public boolean isOdm() {
+        return odm;
+    }
+
+    @Override
+    public boolean isSignedWithPlatformKey() {
+        return signedWithPlatformKey;
+    }
+
+    /**
+     * This is an appId, the uid if the userId is == USER_SYSTEM
+     */
+    @Override
+    public int getUid() {
+        return uid;
+    }
+
+    @DataClass.Generated.Member
+    public PackageImpl setStub(boolean value) {
+        stub = value;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setNativeLibraryRootRequiresIsa(boolean value) {
+        nativeLibraryRootRequiresIsa = value;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setSystem(boolean value) {
+        system = value;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setFactoryTest(boolean value) {
+        factoryTest = value;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setSystemExt(boolean value) {
+        systemExt = value;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setPrivileged(boolean value) {
+        privileged = value;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setOem(boolean value) {
+        oem = value;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setVendor(boolean value) {
+        vendor = value;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setProduct(boolean value) {
+        product = value;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setOdm(boolean value) {
+        odm = value;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setSignedWithPlatformKey(boolean value) {
+        signedWithPlatformKey = value;
+        return this;
+    }
+
+    /**
+     * This is an appId, the uid if the userId is == USER_SYSTEM
+     */
+    @Override
+    public PackageImpl setUid(int value) {
+        uid = value;
+        return this;
+    }
+
+    @DataClass.Generated(
+            time = 1580517688900L,
+            codegenVersion = "1.0.14",
+            sourceFile = "frameworks/base/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java",
+            inputSignatures = "private final @android.annotation.NonNull @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String manifestPackageName\nprivate  boolean stub\nprotected @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String nativeLibraryDir\nprotected @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String nativeLibraryRootDir\nprivate  boolean nativeLibraryRootRequiresIsa\nprotected @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String primaryCpuAbi\nprotected @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String secondaryCpuAbi\nprotected @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String secondaryNativeLibraryDir\nprotected @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String seInfo\nprotected @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String seInfoUser\nprivate  boolean system\nprivate  boolean factoryTest\nprivate  boolean systemExt\nprivate  boolean privileged\nprivate  boolean oem\nprivate  boolean vendor\nprivate  boolean product\nprivate  boolean odm\nprivate  boolean signedWithPlatformKey\nprivate  int uid\npublic static final  com.android.server.pm.parsing.pkg.Creator<com.android.server.pm.parsing.pkg.PackageImpl> CREATOR\npublic static  com.android.server.pm.parsing.pkg.PackageImpl forParsing(java.lang.String,java.lang.String,java.lang.String,android.content.res.TypedArray,boolean)\npublic static  com.android.server.pm.parsing.pkg.AndroidPackage buildFakeForDeletion(java.lang.String,java.lang.String)\npublic static @com.android.internal.annotations.VisibleForTesting android.content.pm.parsing.ParsingPackage forTesting(java.lang.String)\npublic static @com.android.internal.annotations.VisibleForTesting android.content.pm.parsing.ParsingPackage forTesting(java.lang.String,java.lang.String)\npublic @java.lang.Override com.android.server.pm.parsing.pkg.ParsedPackage hideAsParsed()\npublic @java.lang.Override com.android.server.pm.parsing.pkg.AndroidPackage hideAsFinal()\npublic @java.lang.Override long getLongVersionCode()\npublic @java.lang.Override com.android.server.pm.parsing.pkg.PackageImpl removePermission(int)\npublic @java.lang.Override com.android.server.pm.parsing.pkg.PackageImpl addUsesOptionalLibrary(int,java.lang.String)\npublic @java.lang.Override com.android.server.pm.parsing.pkg.PackageImpl addUsesLibrary(int,java.lang.String)\npublic @java.lang.Override com.android.server.pm.parsing.pkg.PackageImpl removeUsesLibrary(java.lang.String)\npublic @java.lang.Override com.android.server.pm.parsing.pkg.PackageImpl removeUsesOptionalLibrary(java.lang.String)\npublic @java.lang.Override com.android.server.pm.parsing.pkg.PackageImpl setSigningDetails(android.content.pm.PackageParser.SigningDetails)\npublic @java.lang.Override com.android.server.pm.parsing.pkg.PackageImpl setRestrictUpdateHash(byte)\npublic @java.lang.Override com.android.server.pm.parsing.pkg.PackageImpl setRealPackage(java.lang.String)\npublic @java.lang.Override com.android.server.pm.parsing.pkg.PackageImpl setPersistent(boolean)\npublic @java.lang.Override com.android.server.pm.parsing.pkg.PackageImpl setDefaultToDeviceProtectedStorage(boolean)\npublic @java.lang.Override com.android.server.pm.parsing.pkg.PackageImpl setDirectBootAware(boolean)\npublic @java.lang.Override com.android.server.pm.parsing.pkg.PackageImpl clearProtectedBroadcasts()\npublic @java.lang.Override com.android.server.pm.parsing.pkg.PackageImpl clearOriginalPackages()\npublic @java.lang.Override com.android.server.pm.parsing.pkg.PackageImpl clearAdoptPermissions()\npublic @java.lang.Override com.android.server.pm.parsing.pkg.PackageImpl setCodePath(java.lang.String)\npublic @java.lang.Override com.android.server.pm.parsing.pkg.PackageImpl setPackageName(java.lang.String)\npublic @java.lang.Override com.android.server.pm.parsing.pkg.PackageImpl setAllComponentsDirectBootAware(boolean)\npublic @java.lang.Override com.android.server.pm.parsing.pkg.PackageImpl setBaseCodePath(java.lang.String)\npublic @java.lang.Override com.android.server.pm.parsing.pkg.PackageImpl setNativeLibraryDir(java.lang.String)\npublic @java.lang.Override com.android.server.pm.parsing.pkg.PackageImpl setNativeLibraryRootDir(java.lang.String)\npublic @java.lang.Override com.android.server.pm.parsing.pkg.PackageImpl setPrimaryCpuAbi(java.lang.String)\npublic @java.lang.Override com.android.server.pm.parsing.pkg.PackageImpl setSecondaryCpuAbi(java.lang.String)\npublic @java.lang.Override com.android.server.pm.parsing.pkg.PackageImpl setSecondaryNativeLibraryDir(java.lang.String)\npublic @java.lang.Override com.android.server.pm.parsing.pkg.PackageImpl setSeInfo(java.lang.String)\npublic @java.lang.Override com.android.server.pm.parsing.pkg.PackageImpl setSeInfoUser(java.lang.String)\npublic @java.lang.Override com.android.server.pm.parsing.pkg.PackageImpl setSplitCodePaths(java.lang.String[])\npublic @java.lang.Override com.android.server.pm.parsing.pkg.PackageImpl capPermissionPriorities()\npublic @java.lang.Override com.android.server.pm.parsing.pkg.PackageImpl markNotActivitiesAsNotExportedIfSingleUser()\npublic @java.lang.Override java.util.UUID getStorageUuid()\npublic @java.lang.Deprecated @java.lang.Override java.lang.String toAppInfoToString()\npublic @java.lang.Override com.android.server.pm.parsing.pkg.ParsedPackage setCoreApp(boolean)\npublic @java.lang.Override com.android.server.pm.parsing.pkg.ParsedPackage setVersionCode(int)\npublic @java.lang.Override com.android.server.pm.parsing.pkg.ParsedPackage setVersionCodeMajor(int)\npublic @java.lang.Override android.content.pm.ApplicationInfo toAppInfoWithoutState()\npublic @java.lang.Override int describeContents()\npublic @java.lang.Override void writeToParcel(android.os.Parcel,int)\nclass PackageImpl extends android.content.pm.parsing.ParsingPackageImpl implements [com.android.server.pm.parsing.pkg.ParsedPackage, com.android.server.pm.parsing.pkg.AndroidPackage]\n@com.android.internal.util.DataClass(genConstructor=false, genParcelable=false, genAidl=false, genBuilder=false, genHiddenConstructor=false, genCopyConstructor=false)")
+    @Deprecated
+    private void __metadata() {}
+
+
+    //@formatter:on
+    // End of generated code
+
+}
diff --git a/core/java/android/content/pm/parsing/ParsedPackage.java b/services/core/java/com/android/server/pm/parsing/pkg/ParsedPackage.java
similarity index 71%
rename from core/java/android/content/pm/parsing/ParsedPackage.java
rename to services/core/java/com/android/server/pm/parsing/pkg/ParsedPackage.java
index 05cf586..2660f2b 100644
--- a/core/java/android/content/pm/parsing/ParsedPackage.java
+++ b/services/core/java/com/android/server/pm/parsing/pkg/ParsedPackage.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2019 The Android Open Source Project
+ * 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.
@@ -14,8 +14,9 @@
  * limitations under the License.
  */
 
-package android.content.pm.parsing;
+package com.android.server.pm.parsing.pkg;
 
+import android.annotation.Nullable;
 import android.content.pm.PackageParser;
 
 /**
@@ -42,26 +43,10 @@
 
     ParsedPackage clearProtectedBroadcasts();
 
-    /**
-     * TODO(b/135203078): Use non-AppInfo method
-     * @deprecated use {@link #setCodePath(String)}
-     */
-    @Deprecated
-    ParsedPackage setApplicationInfoCodePath(String applicationInfoCodePath);
-
-    /**
-     * TODO(b/135203078): Use non-AppInfo method
-     * @deprecated use {@link #setCodePath(String)}
-     */
-    @Deprecated
-    ParsedPackage setApplicationInfoResourcePath(String applicationInfoResourcePath);
-
     ParsedPackage setBaseCodePath(String baseCodePath);
 
     ParsedPackage setCodePath(String codePath);
 
-    ParsedPackage setCpuAbiOverride(String cpuAbiOverride);
-
     ParsedPackage setNativeLibraryDir(String nativeLibraryDir);
 
     ParsedPackage setNativeLibraryRootDir(String nativeLibraryRootDir);
@@ -70,9 +55,7 @@
 
     ParsedPackage setPrimaryCpuAbi(String primaryCpuAbi);
 
-    ParsedPackage setProcessName(String processName);
-
-    ParsedPackage setRealPackage(String realPackage);
+    ParsedPackage setRealPackage(@Nullable String realPackage);
 
     ParsedPackage setSecondaryCpuAbi(String secondaryCpuAbi);
 
@@ -80,8 +63,6 @@
 
     ParsedPackage setSplitCodePaths(String[] splitCodePaths);
 
-    ParsedPackage initForUser(int userId);
-
     ParsedPackage setNativeLibraryRootRequiresIsa(boolean nativeLibraryRootRequiresIsa);
 
     ParsedPackage setAllComponentsDirectBootAware(boolean allComponentsDirectBootAware);
@@ -104,8 +85,6 @@
 
     ParsedPackage setSystemExt(boolean systemExt);
 
-    ParsedPackage setUpdatedSystemApp(boolean updatedSystemApp);
-
     ParsedPackage setVendor(boolean vendor);
 
     ParsedPackage removePermission(int index);
@@ -114,19 +93,9 @@
 
     ParsedPackage removeUsesOptionalLibrary(String libraryName);
 
-    ParsedPackage setApplicationInfoBaseResourcePath(String applicationInfoBaseResourcePath);
-
-    ParsedPackage setApplicationInfoSplitResourcePaths(
-            String[] applicationInfoSplitResourcePaths);
-
-    ParsedPackage setApplicationVolumeUuid(String applicationVolumeUuid);
-
     ParsedPackage setCoreApp(boolean coreApp);
 
-    ParsedPackage setIsStub(boolean isStub);
-
-    // TODO(b/135203078): Remove entirely
-    ParsedPackage setPackageSettingCallback(PackageSettingCallback packageSettingCallback);
+    ParsedPackage setStub(boolean isStub);
 
     ParsedPackage setRestrictUpdateHash(byte[] restrictUpdateHash);
 
@@ -148,8 +117,4 @@
     ParsedPackage setDirectBootAware(boolean directBootAware);
 
     ParsedPackage setPersistent(boolean persistent);
-
-    interface PackageSettingCallback {
-        default void setAndroidPackage(AndroidPackage pkg){}
-    }
 }
diff --git a/services/core/java/com/android/server/pm/parsing/pkg/PkgAppInfo.java b/services/core/java/com/android/server/pm/parsing/pkg/PkgAppInfo.java
new file mode 100644
index 0000000..0cb425f
--- /dev/null
+++ b/services/core/java/com/android/server/pm/parsing/pkg/PkgAppInfo.java
@@ -0,0 +1,493 @@
+/*
+ * 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.pkg;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.pm.ApplicationInfo;
+import android.util.SparseArray;
+
+import com.android.internal.R;
+
+/**
+ * Container for fields that are eventually exposed through {@link ApplicationInfo}.
+ *
+ * Done to separate the meaningless, re-directed JavaDoc for methods and to separate what's
+ * exposed vs not exposed to core.
+ *
+ * @hide
+ */
+interface PkgAppInfo {
+
+    /** @see ApplicationInfo#PRIVATE_FLAG_CANT_SAVE_STATE */
+    boolean isCantSaveState();
+
+    /**
+     * @see ApplicationInfo#appComponentFactory
+     * @see R.styleable#AndroidManifestApplication_appComponentFactory
+     */
+    @Nullable
+    String getAppComponentFactory();
+
+    /**
+     * @see ApplicationInfo#backupAgentName
+     * @see R.styleable#AndroidManifestApplication_backupAgent
+     */
+    @Nullable
+    String getBackupAgentName();
+
+    /**
+     * @see ApplicationInfo#banner
+     * @see R.styleable#AndroidManifestApplication_banner
+     */
+    int getBanner();
+
+    /**
+     * @see ApplicationInfo#category
+     * @see R.styleable#AndroidManifestApplication_appCategory
+     */
+    int getCategory();
+
+    /**
+     * @see ApplicationInfo#classLoaderName
+     * @see R.styleable#AndroidManifestApplication_classLoader
+     */
+    @Nullable
+    String getClassLoaderName();
+
+    /**
+     * @see ApplicationInfo#className
+     * @see R.styleable#AndroidManifestApplication_name
+     */
+    @Nullable
+    String getClassName();
+
+    /**
+     * @see ApplicationInfo#compatibleWidthLimitDp
+     * @see R.styleable#AndroidManifestSupportsScreens_compatibleWidthLimitDp
+     */
+    int getCompatibleWidthLimitDp();
+
+    /**
+     * @see ApplicationInfo#compileSdkVersion
+     * @see R.styleable#AndroidManifest_compileSdkVersion
+     */
+    int getCompileSdkVersion();
+
+    /**
+     * @see ApplicationInfo#compileSdkVersionCodename
+     * @see R.styleable#AndroidManifest_compileSdkVersionCodename
+     */
+    @Nullable
+    String getCompileSdkVersionCodeName();
+
+    /**
+     * @see ApplicationInfo#descriptionRes
+     * @see R.styleable#AndroidManifestApplication_description
+     */
+    int getDescriptionRes();
+
+    /**
+     * @see ApplicationInfo#fullBackupContent
+     * @see R.styleable#AndroidManifestApplication_fullBackupContent
+     */
+    int getFullBackupContent();
+
+    /**
+     * @see ApplicationInfo#iconRes
+     * @see R.styleable#AndroidManifestApplication_icon
+     */
+    int getIconRes();
+
+    /**
+     * @see ApplicationInfo#labelRes
+     * @see R.styleable#AndroidManifestApplication_label
+     */
+    int getLabelRes();
+
+    /**
+     * @see ApplicationInfo#largestWidthLimitDp
+     * @see R.styleable#AndroidManifestSupportsScreens_largestWidthLimitDp
+     */
+    int getLargestWidthLimitDp();
+
+    /**
+     * @see ApplicationInfo#logo
+     * @see R.styleable#AndroidManifestApplication_logo
+     */
+    int getLogo();
+
+    /**
+     * @see ApplicationInfo#manageSpaceActivityName
+     * @see R.styleable#AndroidManifestApplication_manageSpaceActivity
+     */
+    @Nullable
+    String getManageSpaceActivityName();
+
+    /**
+     * @see ApplicationInfo#maxAspectRatio
+     * @see R.styleable#AndroidManifestApplication_maxAspectRatio
+     */
+    float getMaxAspectRatio();
+
+    /**
+     * @see ApplicationInfo#minAspectRatio
+     * @see R.styleable#AndroidManifestApplication_minAspectRatio
+     */
+    float getMinAspectRatio();
+
+    /**
+     * @see ApplicationInfo#minSdkVersion
+     * @see R.styleable#AndroidManifestUsesSdk_minSdkVersion
+     */
+    int getMinSdkVersion();
+
+    /** @see ApplicationInfo#nativeLibraryDir */
+    @Nullable
+    String getNativeLibraryDir();
+
+    /** @see ApplicationInfo#nativeLibraryRootDir */
+    @Nullable
+    String getNativeLibraryRootDir();
+
+    /**
+     * @see ApplicationInfo#networkSecurityConfigRes
+     * @see R.styleable#AndroidManifestApplication_networkSecurityConfig
+     */
+    int getNetworkSecurityConfigRes();
+
+    /**
+     * If {@link R.styleable#AndroidManifestApplication_label} is a string literal, this is it.
+     * Otherwise, it's stored as {@link #getLabelRes()}.
+     * @see ApplicationInfo#nonLocalizedLabel
+     * @see R.styleable#AndroidManifestApplication_label
+     */
+    @Nullable
+    CharSequence getNonLocalizedLabel();
+
+    /**
+     * @see ApplicationInfo#permission
+     * @see R.styleable#AndroidManifestApplication_permission
+     */
+    @Nullable
+    String getPermission();
+
+    /**
+     * TODO(b/135203078): Hide this in the utility, should never be accessed directly
+     * @see ApplicationInfo#primaryCpuAbi
+     */
+    @Nullable
+    String getPrimaryCpuAbi();
+
+    /**
+     * @see ApplicationInfo#processName
+     * @see R.styleable#AndroidManifestApplication_process
+     */
+    @NonNull
+    String getProcessName();
+
+    /**
+     * @see ApplicationInfo#requiresSmallestWidthDp
+     * @see R.styleable#AndroidManifestSupportsScreens_requiresSmallestWidthDp
+     */
+    int getRequiresSmallestWidthDp();
+
+    /**
+     * @see ApplicationInfo#roundIconRes
+     * @see R.styleable#AndroidManifestApplication_roundIcon
+     */
+    int getRoundIconRes();
+
+    /** @see ApplicationInfo#seInfo */
+    @Nullable
+    String getSeInfo();
+
+    /** @see ApplicationInfo#seInfoUser */
+    @Nullable
+    String getSeInfoUser();
+
+    /** @see ApplicationInfo#secondaryCpuAbi */
+    @Nullable
+    String getSecondaryCpuAbi();
+
+    /** @see ApplicationInfo#secondaryNativeLibraryDir */
+    @Nullable
+    String getSecondaryNativeLibraryDir();
+
+    /**
+     * @see ApplicationInfo#installLocation
+     * @see R.styleable#AndroidManifest_installLocation
+     */
+    int getInstallLocation();
+
+    /**
+     * @see ApplicationInfo#splitClassLoaderNames
+     * @see R.styleable#AndroidManifestApplication_classLoader
+     */
+    @Nullable
+    String[] getSplitClassLoaderNames();
+
+    /** @see ApplicationInfo#splitSourceDirs */
+    @Nullable
+    String[] getSplitCodePaths();
+
+    /** @see ApplicationInfo#splitDependencies */
+    @Nullable
+    SparseArray<int[]> getSplitDependencies();
+
+    /**
+     * @see ApplicationInfo#targetSandboxVersion
+     * @see R.styleable#AndroidManifest_targetSandboxVersion
+     */
+    @Deprecated
+    int getTargetSandboxVersion();
+
+    /**
+     * @see ApplicationInfo#targetSdkVersion
+     * @see R.styleable#AndroidManifestUsesSdk_targetSdkVersion
+     */
+    int getTargetSdkVersion();
+
+    /**
+     * @see ApplicationInfo#taskAffinity
+     * @see R.styleable#AndroidManifestApplication_taskAffinity
+     */
+    @Nullable
+    String getTaskAffinity();
+
+    /**
+     * @see ApplicationInfo#theme
+     * @see R.styleable#AndroidManifestApplication_theme
+     */
+    int getTheme();
+
+    /**
+     * @see ApplicationInfo#uiOptions
+     * @see R.styleable#AndroidManifestApplication_uiOptions
+     */
+    int getUiOptions();
+
+    /** @see ApplicationInfo#uid */
+    int getUid();
+
+    /** @see ApplicationInfo#longVersionCode */
+    long getLongVersionCode();
+
+    /** @see ApplicationInfo#versionCode */
+    @Deprecated
+    int getVersionCode();
+
+    /** @see ApplicationInfo#volumeUuid */
+    @Nullable
+    String getVolumeUuid();
+
+    /** @see ApplicationInfo#zygotePreloadName */
+    @Nullable
+    String getZygotePreloadName();
+
+    /** @see ApplicationInfo#FLAG_HAS_CODE */
+    boolean isHasCode();
+
+    /** @see ApplicationInfo#FLAG_ALLOW_TASK_REPARENTING */
+    boolean isAllowTaskReparenting();
+
+    /** @see ApplicationInfo#FLAG_MULTIARCH */
+    boolean isMultiArch();
+
+    /** @see ApplicationInfo#FLAG_EXTRACT_NATIVE_LIBS */
+    boolean isExtractNativeLibs();
+
+    /** @see ApplicationInfo#FLAG_DEBUGGABLE */
+    boolean isDebuggable();
+
+    /** @see ApplicationInfo#FLAG_VM_SAFE_MODE */
+    boolean isVmSafeMode();
+
+    /** @see ApplicationInfo#FLAG_PERSISTENT */
+    boolean isPersistent();
+
+    /** @see ApplicationInfo#FLAG_ALLOW_BACKUP */
+    boolean isAllowBackup();
+
+    /** @see ApplicationInfo#FLAG_TEST_ONLY */
+    boolean isTestOnly();
+
+    /** @see ApplicationInfo#PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION */
+    boolean isResizeableActivityViaSdkVersion();
+
+    /** @see ApplicationInfo#PRIVATE_FLAG_HAS_DOMAIN_URLS */
+    boolean isHasDomainUrls();
+
+    /** @see ApplicationInfo#PRIVATE_FLAG_REQUEST_LEGACY_EXTERNAL_STORAGE */
+    boolean isRequestLegacyExternalStorage();
+
+    /** @see ApplicationInfo#FLAG_HARDWARE_ACCELERATED */
+    boolean isBaseHardwareAccelerated();
+
+    /** @see ApplicationInfo#PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE */
+    boolean isDefaultToDeviceProtectedStorage();
+
+    /** @see ApplicationInfo#PRIVATE_FLAG_DIRECT_BOOT_AWARE */
+    boolean isDirectBootAware();
+
+    /** @see ApplicationInfo#PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE */
+    boolean isPartiallyDirectBootAware();
+
+    /** @see ApplicationInfo#PRIVATE_FLAG_USE_EMBEDDED_DEX */
+    boolean isUseEmbeddedDex();
+
+    /** @see ApplicationInfo#FLAG_EXTERNAL_STORAGE */
+    boolean isExternalStorage();
+
+    /** @see ApplicationInfo#nativeLibraryRootRequiresIsa */
+    boolean isNativeLibraryRootRequiresIsa();
+
+    /** @see ApplicationInfo#PRIVATE_FLAG_ODM */
+    boolean isOdm();
+
+    /** @see ApplicationInfo#PRIVATE_FLAG_OEM */
+    boolean isOem();
+
+    /** @see ApplicationInfo#PRIVATE_FLAG_PRIVILEGED */
+    boolean isPrivileged();
+
+    /** @see ApplicationInfo#PRIVATE_FLAG_PRODUCT */
+    boolean isProduct();
+
+    /** @see ApplicationInfo#PRIVATE_FLAG_PROFILEABLE_BY_SHELL */
+    boolean isProfileableByShell();
+
+    /** @see ApplicationInfo#PRIVATE_FLAG_STATIC_SHARED_LIBRARY */
+    boolean isStaticSharedLibrary();
+
+    /** @see ApplicationInfo#FLAG_SYSTEM */
+    boolean isSystem();
+
+    /** @see ApplicationInfo#PRIVATE_FLAG_SYSTEM_EXT */
+    boolean isSystemExt();
+
+    /** @see ApplicationInfo#PRIVATE_FLAG_VENDOR */
+    boolean isVendor();
+
+    /** @see ApplicationInfo#PRIVATE_FLAG_ISOLATED_SPLIT_LOADING */
+    boolean isIsolatedSplitLoading();
+
+    /**
+     * @see ApplicationInfo#enabled
+     * @see R.styleable#AndroidManifestApplication_enabled
+     */
+    boolean isEnabled();
+
+    /**
+     * @see ApplicationInfo#PRIVATE_FLAG_IS_RESOURCE_OVERLAY
+     * @see ApplicationInfo#isResourceOverlay()
+     */
+    boolean isOverlay();
+
+    /** @see ApplicationInfo#PRIVATE_FLAG_USES_NON_SDK_API */
+    boolean isUsesNonSdkApi();
+
+    /** @see ApplicationInfo#PRIVATE_FLAG_SIGNED_WITH_PLATFORM_KEY */
+    boolean isSignedWithPlatformKey();
+
+    /** @see ApplicationInfo#FLAG_KILL_AFTER_RESTORE */
+    boolean isKillAfterRestore();
+
+    /** @see ApplicationInfo#FLAG_RESTORE_ANY_VERSION */
+    boolean isRestoreAnyVersion();
+
+    /** @see ApplicationInfo#FLAG_FULL_BACKUP_ONLY */
+    boolean isFullBackupOnly();
+
+    /** @see ApplicationInfo#FLAG_ALLOW_CLEAR_USER_DATA */
+    boolean isAllowClearUserData();
+
+    /** @see ApplicationInfo#FLAG_LARGE_HEAP */
+    boolean isLargeHeap();
+
+    /** @see ApplicationInfo#FLAG_USES_CLEARTEXT_TRAFFIC */
+    boolean isUsesCleartextTraffic();
+
+    /** @see ApplicationInfo#FLAG_SUPPORTS_RTL */
+    boolean isSupportsRtl();
+
+    /** @see ApplicationInfo#FLAG_IS_GAME */
+    @Deprecated
+    boolean isGame();
+
+    /** @see ApplicationInfo#FLAG_FACTORY_TEST */
+    boolean isFactoryTest();
+
+    /**
+     * If omitted from manifest, returns true if {@link #getTargetSdkVersion()} >=
+     * {@link android.os.Build.VERSION_CODES#DONUT}.
+     * @see R.styleable#AndroidManifestSupportsScreens_smallScreens
+     * @see ApplicationInfo#FLAG_SUPPORTS_SMALL_SCREENS
+     */
+    boolean isSupportsSmallScreens();
+
+    /**
+     * If omitted from manifest, returns true.
+     * @see R.styleable#AndroidManifestSupportsScreens_normalScreens
+     * @see ApplicationInfo#FLAG_SUPPORTS_NORMAL_SCREENS
+     */
+    boolean isSupportsNormalScreens();
+
+    /**
+     * If omitted from manifest, returns true if {@link #getTargetSdkVersion()} >=
+     * {@link android.os.Build.VERSION_CODES#DONUT}.
+     * @see R.styleable#AndroidManifestSupportsScreens_largeScreens
+     * @see ApplicationInfo#FLAG_SUPPORTS_LARGE_SCREENS
+     */
+    boolean isSupportsLargeScreens();
+
+    /**
+     * If omitted from manifest, returns true if {@link #getTargetSdkVersion()} >=
+     * {@link android.os.Build.VERSION_CODES#GINGERBREAD}.
+     * @see R.styleable#AndroidManifestSupportsScreens_xlargeScreens
+     * @see ApplicationInfo#FLAG_SUPPORTS_XLARGE_SCREENS
+     */
+    boolean isSupportsExtraLargeScreens();
+
+    /**
+     * If omitted from manifest, returns true if {@link #getTargetSdkVersion()} >=
+     * {@link android.os.Build.VERSION_CODES#DONUT}.
+     * @see R.styleable#AndroidManifestSupportsScreens_resizeable
+     * @see ApplicationInfo#FLAG_RESIZEABLE_FOR_SCREENS
+     */
+    boolean isResizeable();
+
+    /**
+     * If omitted from manifest, returns true if {@link #getTargetSdkVersion()} >=
+     * {@link android.os.Build.VERSION_CODES#DONUT}.
+     * @see R.styleable#AndroidManifestSupportsScreens_anyDensity
+     * @see ApplicationInfo#FLAG_SUPPORTS_SCREEN_DENSITIES
+     */
+    boolean isAnyDensity();
+
+    /** @see ApplicationInfo#PRIVATE_FLAG_BACKUP_IN_FOREGROUND */
+    boolean isBackupInForeground();
+
+    /** @see ApplicationInfo#PRIVATE_FLAG_ALLOW_CLEAR_USER_DATA_ON_FAILED_RESTORE */
+    boolean isAllowClearUserDataOnFailedRestore();
+
+    /** @see ApplicationInfo#PRIVATE_FLAG_ALLOW_AUDIO_PLAYBACK_CAPTURE */
+    boolean isAllowAudioPlaybackCapture();
+
+    /** @see ApplicationInfo#PRIVATE_FLAG_HAS_FRAGILE_USER_DATA */
+    boolean isHasFragileUserData();
+}
diff --git a/services/core/java/com/android/server/pm/parsing/pkg/PkgPackageInfo.java b/services/core/java/com/android/server/pm/parsing/pkg/PkgPackageInfo.java
new file mode 100644
index 0000000..89330a9
--- /dev/null
+++ b/services/core/java/com/android/server/pm/parsing/pkg/PkgPackageInfo.java
@@ -0,0 +1,225 @@
+/*
+ * 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.pkg;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ConfigurationInfo;
+import android.content.pm.FeatureGroupInfo;
+import android.content.pm.FeatureInfo;
+import android.content.pm.InstrumentationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PermissionInfo;
+import android.content.pm.ProviderInfo;
+import android.content.pm.ServiceInfo;
+import android.content.pm.parsing.component.ParsedActivity;
+import android.content.pm.parsing.component.ParsedInstrumentation;
+import android.content.pm.parsing.component.ParsedPermission;
+import android.content.pm.parsing.component.ParsedProvider;
+import android.content.pm.parsing.component.ParsedService;
+
+import com.android.internal.R;
+
+import java.util.List;
+
+/**
+ * Container for fields that are eventually exposed through {@link PackageInfo}.
+ *
+ * Done to separate the meaningless, re-directed JavaDoc for methods and to separate what's
+ * exposed vs not exposed to core.
+ *
+ * @hide
+ */
+interface PkgPackageInfo {
+
+    /**
+     * @see PackageInfo#overlayCategory
+     * @see R.styleable#AndroidManifestResourceOverlay_category
+     */
+    @Nullable
+    String getOverlayCategory();
+
+    /**
+     * @see PackageInfo#overlayPriority
+     * @see R.styleable#AndroidManifestResourceOverlay_priority
+     */
+    int getOverlayPriority();
+
+    /**
+     * @see PackageInfo#overlayTarget
+     * @see R.styleable#AndroidManifestResourceOverlay_targetPackage
+     */
+    @Nullable
+    String getOverlayTarget();
+
+    /**
+     * @see PackageInfo#targetOverlayableName
+     * @see R.styleable#AndroidManifestResourceOverlay_targetName
+     */
+    @Nullable
+    String getOverlayTargetName();
+
+    /**
+     * @see PackageInfo#sharedUserId
+     * @see R.styleable#AndroidManifest_sharedUserId
+     */
+    @Deprecated
+    @Nullable
+    String getSharedUserId();
+
+    /**
+     * @see PackageInfo#sharedUserLabel
+     * @see R.styleable#AndroidManifest_sharedUserLabel
+     */
+    @Deprecated
+    int getSharedUserLabel();
+
+    /**
+     * The required account type without which this application will not function.
+     *
+     * @see PackageInfo#requiredAccountType
+     * @see R.styleable#AndroidManifestApplication_requiredAccountType
+     */
+    @Nullable
+    String getRequiredAccountType();
+
+    /**
+     * The restricted account authenticator type that is used by this application
+     *
+     * @see PackageInfo#restrictedAccountType
+     * @see R.styleable#AndroidManifestApplication_restrictedAccountType
+     */
+    @Nullable
+    String getRestrictedAccountType();
+
+    /** @see PackageInfo#splitRevisionCodes */
+    int[] getSplitRevisionCodes();
+
+    /** @see PackageInfo#getLongVersionCode() */
+    long getLongVersionCode();
+
+    /** @see PackageInfo#versionCode */
+    @Deprecated
+    int getVersionCode();
+
+    /** @see PackageInfo#versionCodeMajor */
+    int getVersionCodeMajor();
+
+    /** @see PackageInfo#versionName */
+    @Nullable
+    String getVersionName();
+
+    /** @see PackageInfo#mOverlayIsStatic */
+    boolean isOverlayIsStatic();
+
+    /**
+     * @see PackageInfo#requiredForAllUsers
+     * @see R.styleable#AndroidManifestApplication_requiredForAllUsers
+     */
+    boolean isRequiredForAllUsers();
+
+    /**
+     * @see PackageInfo#reqFeatures
+     * @see R.styleable#AndroidManifestUsesFeature
+     */
+    @NonNull
+    List<FeatureInfo> getReqFeatures();
+
+    /**
+     * @see PackageInfo#configPreferences
+     * @see R.styleable#AndroidManifestUsesConfiguration
+     */
+    @NonNull
+    List<ConfigurationInfo> getConfigPreferences();
+
+    /**
+     * @see PackageInfo#featureGroups
+     * @see R.styleable#AndroidManifestUsesFeature
+     */
+    @NonNull
+    List<FeatureGroupInfo> getFeatureGroups();
+
+    /**
+     * Whether or not the package is a stub and must be replaced by the full version.
+     *
+     * @see PackageInfo#isStub
+     */
+    boolean isStub();
+
+    /**
+     * For marking packages required for a minimal boot state, through the "coreApp" manifest
+     * attribute.
+     * @see PackageInfo#coreApp
+     */
+    boolean isCoreApp();
+
+    /**
+     * All the permissions declared. This is an effective set, and may include permissions
+     * transformed from split/migrated permissions from previous versions, so may not be exactly
+     * what the package declares in its manifest.
+     * @see PackageInfo#requestedPermissions
+     * @see R.styleable#AndroidManifestUsesPermission
+     */
+    @NonNull
+    List<String> getRequestedPermissions();
+
+    /**
+     * @see ActivityInfo
+     * @see PackageInfo#activities
+     */
+    @NonNull
+    List<ParsedActivity> getActivities();
+
+    /**
+     * @see InstrumentationInfo
+     * @see PackageInfo#instrumentation
+     */
+    @NonNull
+    List<ParsedInstrumentation> getInstrumentations();
+
+    /**
+     * @see PermissionInfo
+     * @see PackageInfo#permissions
+     */
+    @NonNull
+    List<ParsedPermission> getPermissions();
+
+    /**
+     * @see ProviderInfo
+     * @see PackageInfo#providers
+     */
+    @NonNull
+    List<ParsedProvider> getProviders();
+
+    /**
+     * Since they share several attributes, receivers are parsed as {@link ParsedActivity}, even
+     * though they represent different functionality.
+     * TODO(b/135203078): Reconsider this and maybe make ParsedReceiver so it's not so confusing
+     * @see ActivityInfo
+     * @see PackageInfo#receivers
+     */
+    @NonNull
+    List<ParsedActivity> getReceivers();
+
+    /**
+     * @see ServiceInfo
+     * @see PackageInfo#services
+     */
+    @NonNull
+    List<ParsedService> getServices();
+}
diff --git a/services/core/java/com/android/server/pm/permission/BasePermission.java b/services/core/java/com/android/server/pm/permission/BasePermission.java
index e323c98..f8e5082 100644
--- a/services/core/java/com/android/server/pm/permission/BasePermission.java
+++ b/services/core/java/com/android/server/pm/permission/BasePermission.java
@@ -32,9 +32,7 @@
 import android.content.pm.PackageManagerInternal;
 import android.content.pm.PermissionInfo;
 import android.content.pm.Signature;
-import android.content.pm.parsing.AndroidPackage;
-import android.content.pm.parsing.ComponentParseUtils.ParsedPermission;
-import android.content.pm.parsing.PackageInfoUtils;
+import android.content.pm.parsing.component.ParsedPermission;
 import android.os.UserHandle;
 import android.util.Log;
 import android.util.Slog;
@@ -43,6 +41,8 @@
 import com.android.server.pm.PackageManagerService;
 import com.android.server.pm.PackageSetting;
 import com.android.server.pm.PackageSettingBase;
+import com.android.server.pm.parsing.PackageInfoUtils;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlSerializer;
@@ -172,12 +172,12 @@
         return 0;
     }
 
-    public boolean isPermission(@NonNull ParsedPermission perm) {
+    public boolean isPermission(ParsedPermission perm) {
         if (this.perm == null) {
             return false;
         }
         return Objects.equals(this.perm.getPackageName(), perm.getPackageName())
-                && Objects.equals(this.perm.className, perm.className);
+                && Objects.equals(this.perm.getName(), perm.getName());
     }
 
     public boolean isDynamic() {
@@ -195,24 +195,24 @@
     }
 
     public boolean isRemoved() {
-        return perm != null && (perm.flags & PermissionInfo.FLAG_REMOVED) != 0;
+        return perm != null && (perm.getFlags() & PermissionInfo.FLAG_REMOVED) != 0;
     }
 
     public boolean isSoftRestricted() {
-        return perm != null && (perm.flags & PermissionInfo.FLAG_SOFT_RESTRICTED) != 0;
+        return perm != null && (perm.getFlags() & PermissionInfo.FLAG_SOFT_RESTRICTED) != 0;
     }
 
     public boolean isHardRestricted() {
-        return perm != null && (perm.flags & PermissionInfo.FLAG_HARD_RESTRICTED) != 0;
+        return perm != null && (perm.getFlags() & PermissionInfo.FLAG_HARD_RESTRICTED) != 0;
     }
 
     public boolean isHardOrSoftRestricted() {
-        return perm != null && (perm.flags & (PermissionInfo.FLAG_HARD_RESTRICTED
+        return perm != null && (perm.getFlags() & (PermissionInfo.FLAG_HARD_RESTRICTED
                 | PermissionInfo.FLAG_SOFT_RESTRICTED)) != 0;
     }
 
     public boolean isImmutablyRestricted() {
-        return perm != null && (perm.flags & PermissionInfo.FLAG_IMMUTABLY_RESTRICTED) != 0;
+        return perm != null && (perm.getFlags() & PermissionInfo.FLAG_IMMUTABLY_RESTRICTED) != 0;
     }
 
     public boolean isSignature() {
@@ -326,15 +326,8 @@
             final BasePermission tree = findPermissionTree(permissionTrees, name);
             if (tree != null && tree.perm != null) {
                 sourcePackageSetting = tree.sourcePackageSetting;
-                perm = new ParsedPermission(tree.perm);
-                perm.protectionLevel = pendingPermissionInfo.protectionLevel;
-                perm.flags = pendingPermissionInfo.flags;
-                perm.setGroup(pendingPermissionInfo.group);
-                perm.backgroundPermission = pendingPermissionInfo.backgroundPermission;
-                perm.descriptionRes = pendingPermissionInfo.descriptionRes;
-                perm.requestRes = pendingPermissionInfo.requestRes;
-                perm.setPackageName(tree.perm.getPackageName());
-                perm.setName(name);
+                perm = new ParsedPermission(tree.perm, pendingPermissionInfo,
+                        tree.perm.getPackageName(), name);
                 uid = tree.uid;
             }
         }
@@ -364,7 +357,7 @@
             if (pkg.isSystem()) {
                 if (bp.type == BasePermission.TYPE_BUILTIN && bp.perm == null) {
                     // It's a built-in permission and no owner, take ownership now
-                    p.flags |= PermissionInfo.FLAG_INSTALLED;
+                    p.setFlags(p.getFlags() | PermissionInfo.FLAG_INSTALLED);
                     bp.sourcePackageSetting = pkgSetting;
                     bp.perm = p;
                     bp.uid = pkg.getUid();
@@ -387,7 +380,7 @@
                 final BasePermission tree = findPermissionTree(permissionTrees, p.getName());
                 if (tree == null
                         || tree.sourcePackageName.equals(p.getPackageName())) {
-                    p.flags |= PermissionInfo.FLAG_INSTALLED;
+                    p.setFlags(p.getFlags() | PermissionInfo.FLAG_INSTALLED);
                     bp.sourcePackageSetting = pkgSetting;
                     bp.perm = p;
                     bp.uid = pkg.getUid();
@@ -421,8 +414,8 @@
             r.append(p.getName());
         }
         if (bp.perm != null && Objects.equals(bp.perm.getPackageName(), p.getPackageName())
-                && Objects.equals(bp.perm.className, p.className)) {
-            bp.protectionLevel = p.protectionLevel;
+                && Objects.equals(bp.perm.getName(), p.getName())) {
+            bp.protectionLevel = p.getProtectionLevel();
         }
         if (PackageManagerService.DEBUG_PACKAGE_SCANNING && r != null) {
             Log.d(TAG, "  Permissions: " + r);
@@ -572,9 +565,9 @@
         if (type == BasePermission.TYPE_DYNAMIC) {
             if (perm != null || pendingPermissionInfo != null) {
                 serializer.attribute(null, "type", "dynamic");
-                int icon = perm != null ? perm.icon : pendingPermissionInfo.icon;
+                int icon = perm != null ? perm.getIcon() : pendingPermissionInfo.icon;
                 CharSequence nonLocalizedLabel = perm != null
-                        ? perm.nonLocalizedLabel
+                        ? perm.getNonLocalizedLabel()
                         : pendingPermissionInfo.nonLocalizedLabel;
 
                 if (icon != 0) {
@@ -602,11 +595,11 @@
     }
 
     private static boolean comparePermissionInfos(ParsedPermission pi1, PermissionInfo pi2) {
-        if (pi1.icon != pi2.icon) return false;
-        if (pi1.logo != pi2.logo) return false;
-        if (pi1.protectionLevel != pi2.protectionLevel) return false;
+        if (pi1.getIcon() != pi2.icon) return false;
+        if (pi1.getLogo() != pi2.logo) return false;
+        if (pi1.getProtectionLevel() != pi2.protectionLevel) return false;
         if (!compareStrings(pi1.getName(), pi2.name)) return false;
-        if (!compareStrings(pi1.nonLocalizedLabel, pi2.nonLocalizedLabel)) return false;
+        if (!compareStrings(pi1.getNonLocalizedLabel(), pi2.nonLocalizedLabel)) return false;
         // We'll take care of setting this one.
         if (!compareStrings(pi1.getPackageName(), pi2.packageName)) return false;
         // These are not currently stored in settings.
@@ -644,9 +637,9 @@
                 pw.println(PermissionInfo.protectionToString(protectionLevel));
         if (perm != null) {
             pw.print("    perm="); pw.println(perm);
-            if ((perm.flags & PermissionInfo.FLAG_INSTALLED) == 0
-                    || (perm.flags & PermissionInfo.FLAG_REMOVED) != 0) {
-                pw.print("    flags=0x"); pw.println(Integer.toHexString(perm.flags));
+            if ((perm.getFlags() & PermissionInfo.FLAG_INSTALLED) == 0
+                    || (perm.getFlags() & PermissionInfo.FLAG_REMOVED) != 0) {
+                pw.print("    flags=0x"); pw.println(Integer.toHexString(perm.getFlags()));
             }
         }
         if (sourcePackageSetting != null) {
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..980aaed 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -71,10 +71,8 @@
 import android.content.pm.ParceledListSlice;
 import android.content.pm.PermissionGroupInfo;
 import android.content.pm.PermissionInfo;
-import android.content.pm.parsing.AndroidPackage;
-import android.content.pm.parsing.ComponentParseUtils.ParsedPermission;
-import android.content.pm.parsing.ComponentParseUtils.ParsedPermissionGroup;
-import android.content.pm.parsing.PackageInfoUtils;
+import android.content.pm.parsing.component.ParsedPermission;
+import android.content.pm.parsing.component.ParsedPermissionGroup;
 import android.content.pm.permission.SplitPermissionInfoParcelable;
 import android.metrics.LogMaker;
 import android.os.Binder;
@@ -129,6 +127,8 @@
 import com.android.server.pm.PackageSetting;
 import com.android.server.pm.SharedUserSetting;
 import com.android.server.pm.UserManagerService;
+import com.android.server.pm.parsing.PackageInfoUtils;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.permission.PermissionManagerServiceInternal.DefaultBrowserProvider;
 import com.android.server.pm.permission.PermissionManagerServiceInternal.DefaultDialerProvider;
 import com.android.server.pm.permission.PermissionManagerServiceInternal.DefaultHomeProvider;
@@ -1282,7 +1282,7 @@
         }
 
         if (bp.isSoftRestricted() && !SoftRestrictedPermissionPolicy.forPermission(mContext,
-                pkg.toAppInfoWithoutState(), UserHandle.of(userId), permName)
+                pkg.toAppInfoWithoutState(), pkg, UserHandle.of(userId), permName)
                 .mayGrantPermission()) {
             Log.e(TAG, "Cannot grant soft restricted permission " + permName + " for package "
                     + packageName);
@@ -2082,9 +2082,9 @@
         for (int i = 0; i < numOldPackagePermissions; i++) {
             final ParsedPermission permission = oldPackage.getPermissions().get(i);
 
-            if (permission.parsedPermissionGroup != null) {
+            if (permission.getParsedPermissionGroup() != null) {
                 oldPermissionNameToGroupName.put(permission.getName(),
-                        permission.parsedPermissionGroup.getName());
+                        permission.getParsedPermissionGroup().getName());
             }
         }
 
@@ -2098,8 +2098,9 @@
 
             if ((newProtection & PermissionInfo.PROTECTION_DANGEROUS) != 0) {
                 final String permissionName = newPermission.getName();
-                final String newPermissionGroupName = newPermission.parsedPermissionGroup == null
-                        ? null : newPermission.parsedPermissionGroup.getName();
+                final String newPermissionGroupName =
+                        newPermission.getParsedPermissionGroup() == null
+                                ? null : newPermission.getParsedPermissionGroup().getName();
                 final String oldPermissionGroupName = oldPermissionNameToGroupName.get(
                         permissionName);
 
@@ -2144,7 +2145,7 @@
             ParsedPermission p = pkg.getPermissions().get(i);
 
             // Assume by default that we did not install this permission into the system.
-            p.flags &= ~PermissionInfo.FLAG_INSTALLED;
+            p.setFlags(p.getFlags() & ~PermissionInfo.FLAG_INSTALLED);
 
             synchronized (PermissionManagerService.this.mLock) {
                 // Now that permission groups have a special meaning, we ignore permission
@@ -2152,16 +2153,16 @@
                 // permissions for one app being granted to someone just because they happen
                 // to be in a group defined by another app (before this had no implications).
                 if (pkg.getTargetSdkVersion() > Build.VERSION_CODES.LOLLIPOP_MR1) {
-                    p.parsedPermissionGroup = mSettings.mPermissionGroups.get(p.getGroup());
+                    p.setParsedPermissionGroup(mSettings.mPermissionGroups.get(p.getGroup()));
                     // Warn for a permission in an unknown group.
                     if (DEBUG_PERMISSIONS
-                            && p.getGroup() != null && p.parsedPermissionGroup == null) {
+                            && p.getGroup() != null && p.getParsedPermissionGroup() == null) {
                         Slog.i(TAG, "Permission " + p.getName() + " from package "
                                 + p.getPackageName() + " in an unknown group " + p.getGroup());
                     }
                 }
 
-                if (p.tree) {
+                if (p.isTree()) {
                     final BasePermission bp = BasePermission.createOrUpdate(
                             mPackageManagerInt,
                             mSettings.getPermissionTreeLocked(p.getName()), p, pkg,
@@ -2409,14 +2410,16 @@
                     }
                 }
 
+                // TODO(b/140256621): The package instant app method has been removed
+                //  as part of work in b/135203078, so this has been commented out in the meantime
                 // Limit ephemeral apps to ephemeral allowed permissions.
-                if (pkg.isInstantApp() && !bp.isInstant()) {
-                    if (DEBUG_PERMISSIONS) {
-                        Log.i(TAG, "Denying non-ephemeral permission " + bp.getName()
-                                + " for package " + pkg.getPackageName());
-                    }
-                    continue;
-                }
+//                if (/*pkg.isInstantApp()*/ false && !bp.isInstant()) {
+//                    if (DEBUG_PERMISSIONS) {
+//                        Log.i(TAG, "Denying non-ephemeral permission " + bp.getName()
+//                                + " for package " + pkg.getPackageName());
+//                    }
+//                    continue;
+//                }
 
                 if (bp.isRuntimeOnly() && !appSupportsRuntimePermissions) {
                     if (DEBUG_PERMISSIONS) {
@@ -2450,7 +2453,7 @@
                     }
                 } else if (bp.isSignature()) {
                     // For all apps signature permissions are install time ones.
-                    allowedSig = grantSignaturePermission(perm, pkg, bp, origPermissions);
+                    allowedSig = grantSignaturePermission(perm, pkg, ps, bp, origPermissions);
                     if (allowedSig) {
                         grant = GRANT_INSTALL;
                     }
@@ -2764,7 +2767,8 @@
                             Slog.i(TAG, "Un-granting permission " + perm
                                     + " from package " + pkg.getPackageName()
                                     + " (protectionLevel=" + bp.getProtectionLevel()
-                                    + " flags=0x" + Integer.toHexString(pkg.getFlags())
+                                    + " flags=0x"
+                                    + Integer.toHexString(PackageInfoUtils.appInfoFlags(pkg, ps))
                                     + ")");
                         }
                     } else if (bp.isAppOp()) {
@@ -2776,7 +2780,8 @@
                             Slog.i(TAG, "Not granting permission " + perm
                                     + " to package " + pkg.getPackageName()
                                     + " (protectionLevel=" + bp.getProtectionLevel()
-                                    + " flags=0x" + Integer.toHexString(pkg.getFlags())
+                                    + " flags=0x"
+                                    + Integer.toHexString(PackageInfoUtils.appInfoFlags(pkg, ps))
                                     + ")");
                         }
                     }
@@ -2784,7 +2789,7 @@
             }
 
             if ((changedInstallPermission || replace) && !ps.areInstallPermissionsFixed() &&
-                    !ps.isSystem() || ps.isUpdatedSystem()) {
+                    !ps.isSystem() || !ps.getPkgState().isUpdatedSystemApp()) {
                 // This is the first that we have heard about this package, so the
                 // permissions we have now selected are fixed until explicitly
                 // changed.
@@ -2934,7 +2939,7 @@
      */
     private @NonNull int[] checkIfLegacyStorageOpsNeedToBeUpdated(
             @NonNull AndroidPackage pkg, boolean replace, @NonNull int[] updatedUserIds) {
-        if (replace && pkg.hasRequestedLegacyExternalStorage() && (
+        if (replace && pkg.isRequestLegacyExternalStorage() && (
                 pkg.getRequestedPermissions().contains(READ_EXTERNAL_STORAGE)
                         || pkg.getRequestedPermissions().contains(WRITE_EXTERNAL_STORAGE))) {
             return UserManagerService.getInstance().getUserIds();
@@ -3127,7 +3132,7 @@
     }
 
     private boolean grantSignaturePermission(String perm, AndroidPackage pkg,
-            BasePermission bp, PermissionsState origPermissions) {
+            PackageSetting pkgSetting, BasePermission bp, PermissionsState origPermissions) {
         boolean oemPermission = bp.isOEM();
         boolean vendorPrivilegedPermission = bp.isVendorPrivileged();
         boolean privilegedPermission = bp.isPrivileged() || bp.isVendorPrivileged();
@@ -3139,7 +3144,7 @@
                 && !platformPackage && platformPermission) {
             if (!hasPrivappWhitelistEntry(perm, pkg)) {
                 // Only report violations for apps on system image
-                if (!mSystemReady && !pkg.isUpdatedSystemApp()) {
+                if (!mSystemReady && !pkgSetting.getPkgState().isUpdatedSystemApp()) {
                     // it's only a reportable violation if the permission isn't explicitly denied
                     ArraySet<String> deniedPermissions = null;
                     if (pkg.isVendor()) {
@@ -3205,8 +3210,8 @@
             if (pkg.isSystem()) {
                 // For updated system applications, a privileged/oem permission
                 // is granted only if it had been defined by the original application.
-                if (pkg.isUpdatedSystemApp()) {
-                    final PackageSetting disabledPs = (PackageSetting) mPackageManagerInt
+                if (pkgSetting.getPkgState().isUpdatedSystemApp()) {
+                    final PackageSetting disabledPs = mPackageManagerInt
                             .getDisabledSystemPackage(pkg.getPackageName());
                     final AndroidPackage disabledPkg = disabledPs == null ? null : disabledPs.pkg;
                     if (disabledPs != null
@@ -3612,7 +3617,7 @@
             return EmptyArray.INT;
         }
         for (AndroidPackage pkg : pkgList) {
-            if (pkg.getRequestedPermissions() == null) {
+            if (pkg.getRequestedPermissions().isEmpty()) {
                 continue;
             }
             final int requestedPermCount = pkg.getRequestedPermissions().size();
@@ -3720,9 +3725,9 @@
                 // Only system declares background permissions, hence mapping does never change.
                 mBackgroundPermissions = new ArrayMap<>();
                 for (BasePermission bp : mSettings.getAllPermissionsLocked()) {
-                    if (bp.perm != null && bp.perm.backgroundPermission != null) {
+                    if (bp.perm != null && bp.perm.getBackgroundPermission() != null) {
                         String fgPerm = bp.name;
-                        String bgPerm = bp.perm.backgroundPermission;
+                        String bgPerm = bp.perm.getBackgroundPermission();
 
                         List<String> fgPerms = mBackgroundPermissions.get(bgPerm);
                         if (fgPerms == null) {
@@ -4234,7 +4239,7 @@
         if (pkg == null) {
             return StorageManager.UUID_PRIVATE_INTERNAL;
         }
-        if (pkg.isExternal()) {
+        if (pkg.isExternalStorage()) {
             if (TextUtils.isEmpty(pkg.getVolumeUuid())) {
                 return StorageManager.UUID_PRIMARY_PHYSICAL;
             } else {
@@ -4246,7 +4251,7 @@
     }
 
     private static boolean hasPermission(AndroidPackage pkg, String permName) {
-        if (pkg.getPermissions() == null) {
+        if (pkg.getPermissions().isEmpty()) {
             return false;
         }
 
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
index 58a9f42..048e487 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
@@ -22,9 +22,10 @@
 import android.annotation.UserIdInt;
 import android.content.pm.PackageManager;
 import android.content.pm.PermissionInfo;
-import android.content.pm.parsing.AndroidPackage;
 import android.permission.PermissionManagerInternal;
 
+import com.android.server.pm.parsing.pkg.AndroidPackage;
+
 import java.util.ArrayList;
 import java.util.List;
 import java.util.function.Consumer;
diff --git a/services/core/java/com/android/server/pm/permission/PermissionSettings.java b/services/core/java/com/android/server/pm/permission/PermissionSettings.java
index 254b720..355e243 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionSettings.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionSettings.java
@@ -18,7 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.content.pm.parsing.ComponentParseUtils;
+import android.content.pm.parsing.component.ParsedPermissionGroup;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.Log;
@@ -65,7 +65,7 @@
      * name to permission group object.
      */
     @GuardedBy("mLock")
-    final ArrayMap<String, ComponentParseUtils.ParsedPermissionGroup> mPermissionGroups =
+    final ArrayMap<String, ParsedPermissionGroup> mPermissionGroups =
             new ArrayMap<>();
 
     /**
diff --git a/services/core/java/com/android/server/pm/pkg/PackageStateUnserialized.java b/services/core/java/com/android/server/pm/pkg/PackageStateUnserialized.java
new file mode 100644
index 0000000..c008d93
--- /dev/null
+++ b/services/core/java/com/android/server/pm/pkg/PackageStateUnserialized.java
@@ -0,0 +1,196 @@
+/*
+ * 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.pkg;
+
+import static java.util.Collections.emptyList;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageParser;
+import android.content.pm.SharedLibraryInfo;
+
+import com.android.internal.util.DataClass;
+import com.android.server.pm.PackageSetting;
+
+import java.util.List;
+
+/**
+ * For use by {@link PackageSetting} to maintain functionality that used to exist in
+ * {@link PackageParser.Package}.
+ *
+ * It is assumed that anything inside the package was not cached or written to disk, so none of
+ * these fields are either. They must be set on every boot from other state on the device.
+ */
+@DataClass(genSetters = true, genConstructor = false, genBuilder = false)
+public class PackageStateUnserialized {
+
+    private boolean hiddenUntilInstalled;
+
+    @NonNull
+    private List<SharedLibraryInfo> usesLibraryInfos = emptyList();
+
+    @NonNull
+    private List<String> usesLibraryFiles = emptyList();
+
+    private boolean updatedSystemApp;
+
+    @NonNull
+    private volatile long[] lastPackageUsageTimeInMills;
+
+    @Nullable
+    private String overrideSeInfo;
+
+    private long[] lazyInitLastPackageUsageTimeInMills() {
+        return new long[PackageManager.NOTIFY_PACKAGE_USE_REASONS_COUNT];
+    }
+
+    public PackageStateUnserialized setLastPackageUsageTimeInMills(int reason, long time) {
+        getLastPackageUsageTimeInMills()[reason] = time;
+        return this;
+    }
+
+    public long getLatestPackageUseTimeInMills() {
+        long latestUse = 0L;
+        for (long use : getLastPackageUsageTimeInMills()) {
+            latestUse = Math.max(latestUse, use);
+        }
+        return latestUse;
+    }
+
+    public long getLatestForegroundPackageUseTimeInMills() {
+        int[] foregroundReasons = {
+                PackageManager.NOTIFY_PACKAGE_USE_ACTIVITY,
+                PackageManager.NOTIFY_PACKAGE_USE_FOREGROUND_SERVICE
+        };
+
+        long latestUse = 0L;
+        for (int reason : foregroundReasons) {
+            latestUse = Math.max(latestUse, getLastPackageUsageTimeInMills()[reason]);
+        }
+        return latestUse;
+    }
+
+
+
+    // Code below generated by codegen v1.0.14.
+    //
+    // DO NOT MODIFY!
+    // CHECKSTYLE:OFF Generated code
+    //
+    // To regenerate run:
+    // $ codegen $ANDROID_BUILD_TOP/frameworks/base/services/core/java/com/android/server/pm/pkg/PackageStateUnserialized.java
+    //
+    // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+    //   Settings > Editor > Code Style > Formatter Control
+    //@formatter:off
+
+
+    @DataClass.Generated.Member
+    public boolean isHiddenUntilInstalled() {
+        return hiddenUntilInstalled;
+    }
+
+    @DataClass.Generated.Member
+    public @NonNull List<SharedLibraryInfo> getUsesLibraryInfos() {
+        return usesLibraryInfos;
+    }
+
+    @DataClass.Generated.Member
+    public @NonNull List<String> getUsesLibraryFiles() {
+        return usesLibraryFiles;
+    }
+
+    @DataClass.Generated.Member
+    public boolean isUpdatedSystemApp() {
+        return updatedSystemApp;
+    }
+
+    @DataClass.Generated.Member
+    public @NonNull long[] getLastPackageUsageTimeInMills() {
+        long[] _lastPackageUsageTimeInMills = lastPackageUsageTimeInMills;
+        if (_lastPackageUsageTimeInMills == null) {
+            synchronized(this) {
+                _lastPackageUsageTimeInMills = lastPackageUsageTimeInMills;
+                if (_lastPackageUsageTimeInMills == null) {
+                    _lastPackageUsageTimeInMills = lastPackageUsageTimeInMills = lazyInitLastPackageUsageTimeInMills();
+                }
+            }
+        }
+        return _lastPackageUsageTimeInMills;
+    }
+
+    @DataClass.Generated.Member
+    public @Nullable String getOverrideSeInfo() {
+        return overrideSeInfo;
+    }
+
+    @DataClass.Generated.Member
+    public PackageStateUnserialized setHiddenUntilInstalled(boolean value) {
+        hiddenUntilInstalled = value;
+        return this;
+    }
+
+    @DataClass.Generated.Member
+    public PackageStateUnserialized setUsesLibraryInfos(@NonNull List<SharedLibraryInfo> value) {
+        usesLibraryInfos = value;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, usesLibraryInfos);
+        return this;
+    }
+
+    @DataClass.Generated.Member
+    public PackageStateUnserialized setUsesLibraryFiles(@NonNull List<String> value) {
+        usesLibraryFiles = value;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, usesLibraryFiles);
+        return this;
+    }
+
+    @DataClass.Generated.Member
+    public PackageStateUnserialized setUpdatedSystemApp(boolean value) {
+        updatedSystemApp = value;
+        return this;
+    }
+
+    @DataClass.Generated.Member
+    public PackageStateUnserialized setLastPackageUsageTimeInMills(@NonNull long... value) {
+        lastPackageUsageTimeInMills = value;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, lastPackageUsageTimeInMills);
+        return this;
+    }
+
+    @DataClass.Generated.Member
+    public PackageStateUnserialized setOverrideSeInfo(@Nullable String value) {
+        overrideSeInfo = value;
+        return this;
+    }
+
+    @DataClass.Generated(
+            time = 1580422870209L,
+            codegenVersion = "1.0.14",
+            sourceFile = "frameworks/base/services/core/java/com/android/server/pm/pkg/PackageStateUnserialized.java",
+            inputSignatures = "private  boolean hiddenUntilInstalled\nprivate @android.annotation.NonNull java.util.List<android.content.pm.SharedLibraryInfo> usesLibraryInfos\nprivate @android.annotation.NonNull java.util.List<java.lang.String> usesLibraryFiles\nprivate  boolean updatedSystemApp\nprivate volatile @android.annotation.NonNull long[] lastPackageUsageTimeInMills\n @android.annotation.Nullable java.lang.String overrideSeInfo\nprivate  long[] lazyInitLastPackageUsageTimeInMills()\npublic  com.android.server.pm.pkg.PackageStateUnserialized setLastPackageUsageTimeInMills(int,long)\npublic  long getLatestPackageUseTimeInMills()\npublic  long getLatestForegroundPackageUseTimeInMills()\nclass PackageStateUnserialized extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genSetters=true, genConstructor=false, genBuilder=false)")
+    @Deprecated
+    private void __metadata() {}
+
+
+    //@formatter:on
+    // End of generated code
+
+}
diff --git a/services/core/java/com/android/server/policy/PermissionPolicyService.java b/services/core/java/com/android/server/policy/PermissionPolicyService.java
index ec8e1a0..139c844 100644
--- a/services/core/java/com/android/server/policy/PermissionPolicyService.java
+++ b/services/core/java/com/android/server/policy/PermissionPolicyService.java
@@ -39,7 +39,6 @@
 import android.content.pm.PackageManagerInternal;
 import android.content.pm.PackageManagerInternal.PackageListObserver;
 import android.content.pm.PermissionInfo;
-import android.content.pm.parsing.AndroidPackage;
 import android.os.Build;
 import android.os.Process;
 import android.os.RemoteException;
@@ -65,6 +64,7 @@
 import com.android.server.FgThread;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.permission.PermissionManagerServiceInternal;
 import com.android.server.policy.PermissionPolicyInternal.OnInitializedCallback;
 
@@ -163,7 +163,7 @@
                 if (perm.isSoftRestricted()) {
                     SoftRestrictedPermissionPolicy policy =
                             SoftRestrictedPermissionPolicy.forPermission(null, null, null,
-                                    perm.name);
+                                    null, perm.name);
                     int extraAppOp = policy.getExtraAppOpCode();
                     if (extraAppOp != OP_NONE) {
                         appOpsService.startWatchingMode(extraAppOp, null, mAppOpsCallback);
@@ -506,17 +506,18 @@
         /**
          * Note: Called with the package lock held. Do <u>not</u> call into app-op manager.
          */
-        private void addAppOps(@NonNull PackageInfo packageInfo, @NonNull String permissionName) {
+        private void addAppOps(@NonNull PackageInfo packageInfo, @NonNull AndroidPackage pkg,
+                @NonNull String permissionName) {
             PermissionInfo permissionInfo = mRuntimePermissionInfos.get(permissionName);
             if (permissionInfo == null) {
                 return;
             }
-            addPermissionAppOp(packageInfo, permissionInfo);
-            addExtraAppOp(packageInfo, permissionInfo);
+            addPermissionAppOp(packageInfo, pkg, permissionInfo);
+            addExtraAppOp(packageInfo, pkg, permissionInfo);
         }
 
         private void addPermissionAppOp(@NonNull PackageInfo packageInfo,
-                @NonNull PermissionInfo permissionInfo) {
+                @NonNull AndroidPackage pkg, @NonNull PermissionInfo permissionInfo) {
             if (!permissionInfo.isRuntime()) {
                 return;
             }
@@ -539,13 +540,13 @@
             }
 
             int appOpMode;
-            boolean shouldGrantAppOp = shouldGrantAppOp(packageInfo, permissionInfo);
+            boolean shouldGrantAppOp = shouldGrantAppOp(packageInfo, pkg, permissionInfo);
             if (shouldGrantAppOp) {
                 if (permissionInfo.backgroundPermission != null) {
                     PermissionInfo backgroundPermissionInfo = mRuntimePermissionInfos.get(
                             permissionInfo.backgroundPermission);
                     boolean shouldGrantBackgroundAppOp = backgroundPermissionInfo != null
-                            && shouldGrantAppOp(packageInfo, backgroundPermissionInfo);
+                            && shouldGrantAppOp(packageInfo, pkg, backgroundPermissionInfo);
                     appOpMode = shouldGrantBackgroundAppOp ? MODE_ALLOWED : MODE_FOREGROUND;
                 } else {
                     appOpMode = MODE_ALLOWED;
@@ -570,7 +571,7 @@
         }
 
         private boolean shouldGrantAppOp(@NonNull PackageInfo packageInfo,
-                @NonNull PermissionInfo permissionInfo) {
+                @NonNull AndroidPackage pkg, @NonNull PermissionInfo permissionInfo) {
             String permissionName = permissionInfo.name;
             String packageName = packageInfo.packageName;
             boolean isGranted = mPackageManager.checkPermission(permissionName, packageName)
@@ -595,14 +596,15 @@
             } else if (permissionInfo.isSoftRestricted()) {
                 SoftRestrictedPermissionPolicy policy =
                         SoftRestrictedPermissionPolicy.forPermission(mContext,
-                                packageInfo.applicationInfo, mContext.getUser(), permissionName);
+                                packageInfo.applicationInfo, pkg, mContext.getUser(),
+                                permissionName);
                 return policy.mayGrantPermission();
             } else {
                 return true;
             }
         }
 
-        private void addExtraAppOp(@NonNull PackageInfo packageInfo,
+        private void addExtraAppOp(@NonNull PackageInfo packageInfo, @NonNull AndroidPackage pkg,
                 @NonNull PermissionInfo permissionInfo) {
             if (!permissionInfo.isSoftRestricted()) {
                 return;
@@ -611,7 +613,7 @@
             String permissionName = permissionInfo.name;
             SoftRestrictedPermissionPolicy policy =
                     SoftRestrictedPermissionPolicy.forPermission(mContext,
-                            packageInfo.applicationInfo, mContext.getUser(), permissionName);
+                            packageInfo.applicationInfo, pkg, mContext.getUser(), permissionName);
             int extraOpCode = policy.getExtraAppOpCode();
             if (extraOpCode == OP_NONE) {
                 return;
@@ -639,19 +641,23 @@
          * @param pkgName The package to add for later processing.
          */
         void addPackage(@NonNull String pkgName) {
-            final PackageInfo pkg;
+            PackageManagerInternal pmInternal =
+                    LocalServices.getService(PackageManagerInternal.class);
+            final PackageInfo pkgInfo;
+            final AndroidPackage pkg;
             try {
-                pkg = mPackageManager.getPackageInfo(pkgName, GET_PERMISSIONS);
+                pkgInfo = mPackageManager.getPackageInfo(pkgName, GET_PERMISSIONS);
+                pkg = pmInternal.getPackage(pkgName);
             } catch (NameNotFoundException e) {
                 return;
             }
 
-            if (pkg.requestedPermissions == null) {
+            if (pkgInfo == null || pkg == null || pkgInfo.requestedPermissions == null) {
                 return;
             }
 
-            for (String permission : pkg.requestedPermissions) {
-                addAppOps(pkg, permission);
+            for (String permission : pkgInfo.requestedPermissions) {
+                addAppOps(pkgInfo, pkg, permission);
             }
         }
 
diff --git a/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java b/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java
index 740472e..90babcd 100644
--- a/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java
+++ b/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java
@@ -35,7 +35,6 @@
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
-import android.content.pm.PackageManagerInternal;
 import android.os.Binder;
 import android.os.IBinder;
 import android.os.RemoteException;
@@ -46,6 +45,7 @@
 
 import com.android.internal.compat.IPlatformCompat;
 import com.android.server.LocalServices;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
 
 /**
  * The behavior of soft restricted permissions is different for each permission. This class collects
@@ -100,8 +100,8 @@
      * @return The policy for this permission
      */
     public static @NonNull SoftRestrictedPermissionPolicy forPermission(@NonNull Context context,
-            @Nullable ApplicationInfo appInfo, @Nullable UserHandle user,
-            @NonNull String permission) {
+            @Nullable ApplicationInfo appInfo, @Nullable AndroidPackage pkg,
+            @Nullable UserHandle user, @NonNull String permission) {
         switch (permission) {
             // Storage uses a special app op to decide the mount state and supports soft restriction
             // where the restricted state allows the permission but only for accessing the medial
@@ -116,8 +116,6 @@
 
                 if (appInfo != null) {
                     PackageManager pm = context.getPackageManager();
-                    PackageManagerInternal pmInternal =
-                            LocalServices.getService(PackageManagerInternal.class);
                     StorageManagerInternal smInternal =
                             LocalServices.getService(StorageManagerInternal.class);
                     int flags = pm.getPermissionFlags(permission, appInfo.packageName, user);
@@ -131,8 +129,7 @@
                     isScopedStorageEnabled =
                             isChangeEnabledForUid(context, appInfo, user, ENABLE_SCOPED_STORAGE)
                             || isScopedStorageRequired;
-                    shouldPreserveLegacyExternalStorage = pmInternal.getPackage(
-                            appInfo.packageName).hasPreserveLegacyExternalStorage()
+                    shouldPreserveLegacyExternalStorage = pkg.hasPreserveLegacyExternalStorage()
                             && smInternal.hasLegacyExternalStorage(appInfo.uid);
                     shouldApplyRestriction = (flags & FLAG_PERMISSION_APPLY_RESTRICTION) != 0
                             || (isScopedStorageRequired && !shouldPreserveLegacyExternalStorage);
diff --git a/services/core/java/com/android/server/role/RoleUserState.java b/services/core/java/com/android/server/role/RoleUserState.java
index 9f4ca3c..97ce6bd 100644
--- a/services/core/java/com/android/server/role/RoleUserState.java
+++ b/services/core/java/com/android/server/role/RoleUserState.java
@@ -364,12 +364,12 @@
                     (Map<String, Set<String>>) (Map<String, ?>) snapshotRolesLocked());
         }
 
-        mPersistence.write(roles, UserHandle.of(mUserId));
+        mPersistence.writeAsUser(roles, UserHandle.of(mUserId));
     }
 
     private void readFile() {
         synchronized (mLock) {
-            RolesState roles = mPersistence.read(UserHandle.of(mUserId));
+            RolesState roles = mPersistence.readAsUser(UserHandle.of(mUserId));
             if (roles == null) {
                 readLegacyFileLocked();
                 scheduleWriteFileLocked();
@@ -545,7 +545,7 @@
                 throw new IllegalStateException("This RoleUserState has already been destroyed");
             }
             mWriteHandler.removeCallbacksAndMessages(null);
-            mPersistence.delete(UserHandle.of(mUserId));
+            mPersistence.deleteAsUser(UserHandle.of(mUserId));
             mDestroyed = true;
         }
     }
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Enforcer.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Enforcer.java
new file mode 100644
index 0000000..870d909
--- /dev/null
+++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Enforcer.java
@@ -0,0 +1,169 @@
+/*
+ * 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.soundtrigger_middleware;
+
+import android.hardware.soundtrigger.V2_1.ISoundTriggerHw;
+import android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback;
+import android.hardware.soundtrigger.V2_3.ModelParameterRange;
+import android.hardware.soundtrigger.V2_3.Properties;
+import android.hardware.soundtrigger.V2_3.RecognitionConfig;
+import android.os.IHwBinder;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * A decorator around a HAL, which adds some checks that the HAL is behaving as expected.
+ * This is not necessarily a strict enforcement for the HAL contract, but a place to add checks for
+ * common HAL malfunctions, to help track them and assist in debugging.
+ *
+ * The class is not thread-safe.
+ */
+public class SoundTriggerHw2Enforcer implements ISoundTriggerHw2 {
+    static final String TAG = "SoundTriggerHw2Enforcer";
+
+    final ISoundTriggerHw2 mUnderlying;
+    Map<Integer, Boolean> mModelStates = new HashMap<>();
+
+    public SoundTriggerHw2Enforcer(
+            ISoundTriggerHw2 underlying) {
+        mUnderlying = underlying;
+    }
+
+    @Override
+    public Properties getProperties() {
+        return mUnderlying.getProperties();
+    }
+
+    @Override
+    public int loadSoundModel(ISoundTriggerHw.SoundModel soundModel, Callback callback,
+            int cookie) {
+        int handle = mUnderlying.loadSoundModel(soundModel, new CallbackEnforcer(callback), cookie);
+        mModelStates.put(handle, false);
+        return handle;
+    }
+
+    @Override
+    public int loadPhraseSoundModel(ISoundTriggerHw.PhraseSoundModel soundModel, Callback callback,
+            int cookie) {
+        int handle = mUnderlying.loadPhraseSoundModel(soundModel, new CallbackEnforcer(callback),
+                cookie);
+        mModelStates.put(handle, false);
+        return handle;
+    }
+
+    @Override
+    public void unloadSoundModel(int modelHandle) {
+        mUnderlying.unloadSoundModel(modelHandle);
+        mModelStates.remove(modelHandle);
+    }
+
+    @Override
+    public void stopRecognition(int modelHandle) {
+        mUnderlying.stopRecognition(modelHandle);
+        mModelStates.replace(modelHandle, false);
+    }
+
+    @Override
+    public void stopAllRecognitions() {
+        mUnderlying.stopAllRecognitions();
+        for (Map.Entry<Integer, Boolean> entry : mModelStates.entrySet()) {
+            entry.setValue(false);
+        }
+    }
+
+    @Override
+    public void startRecognition(int modelHandle, RecognitionConfig config, Callback callback,
+            int cookie) {
+        mUnderlying.startRecognition(modelHandle, config, new CallbackEnforcer(callback), cookie);
+        mModelStates.replace(modelHandle, true);
+    }
+
+    @Override
+    public void getModelState(int modelHandle) {
+        mUnderlying.getModelState(modelHandle);
+    }
+
+    @Override
+    public int getModelParameter(int modelHandle, int param) {
+        return mUnderlying.getModelParameter(modelHandle, param);
+    }
+
+    @Override
+    public void setModelParameter(int modelHandle, int param, int value) {
+        mUnderlying.setModelParameter(modelHandle, param, value);
+    }
+
+    @Override
+    public ModelParameterRange queryParameter(int modelHandle, int param) {
+        return mUnderlying.queryParameter(modelHandle, param);
+    }
+
+    @Override
+    public boolean linkToDeath(IHwBinder.DeathRecipient recipient, long cookie) {
+        return mUnderlying.linkToDeath(recipient, cookie);
+    }
+
+    @Override
+    public boolean unlinkToDeath(IHwBinder.DeathRecipient recipient) {
+        return mUnderlying.unlinkToDeath(recipient);
+    }
+
+    @Override
+    public String interfaceDescriptor() throws RemoteException {
+        return mUnderlying.interfaceDescriptor();
+    }
+
+    private class CallbackEnforcer implements Callback {
+        private final Callback mUnderlying;
+
+        private CallbackEnforcer(
+                Callback underlying) {
+            mUnderlying = underlying;
+        }
+
+        @Override
+        public void recognitionCallback(ISoundTriggerHwCallback.RecognitionEvent event,
+                int cookie) {
+            int model = event.header.model;
+            if (!mModelStates.getOrDefault(model, false)) {
+                Log.wtfStack(TAG, "Unexpected recognition event for model: " + model);
+            }
+            if (event.header.status
+                    != android.media.soundtrigger_middleware.RecognitionStatus.FORCED) {
+                mModelStates.replace(model, false);
+            }
+            mUnderlying.recognitionCallback(event, cookie);
+        }
+
+        @Override
+        public void phraseRecognitionCallback(ISoundTriggerHwCallback.PhraseRecognitionEvent event,
+                int cookie) {
+            int model = event.common.header.model;
+            if (!mModelStates.getOrDefault(model, false)) {
+                Log.wtfStack(TAG, "Unexpected recognition event for model: " + model);
+            }
+            if (event.common.header.status
+                    != android.media.soundtrigger_middleware.RecognitionStatus.FORCED) {
+                mModelStates.replace(model, false);
+            }
+            mUnderlying.phraseRecognitionCallback(event, cookie);
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java
index cd5e360..aa1558e 100644
--- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java
+++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java
@@ -191,7 +191,7 @@
      * Attached to the HAL service via factory.
      */
     private void attachToHal() {
-        mHalService = new SoundTriggerHw2Compat(mHalFactory.create());
+        mHalService = new SoundTriggerHw2Enforcer(new SoundTriggerHw2Compat(mHalFactory.create()));
         mHalService.linkToDeath(this, 0);
     }
 
diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
index 2b111f7..df6784e 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -41,6 +41,7 @@
 import android.app.AppOpsManager.HistoricalUidOps;
 import android.app.INotificationManager;
 import android.app.ProcessMemoryState;
+import android.app.RuntimeAppOpAccessMessage;
 import android.app.StatsManager;
 import android.app.StatsManager.PullAtomMetadata;
 import android.bluetooth.BluetoothActivityEnergyInfo;
@@ -377,6 +378,8 @@
                     return pullFaceSettings(atomTag, data);
                 case FrameworkStatsLog.APP_OPS:
                     return pullAppOps(atomTag, data);
+                case FrameworkStatsLog.RUNTIME_APP_OP_ACCESS:
+                    return pullRuntimeAppOpAccessMessage(atomTag, data);
                 case FrameworkStatsLog.NOTIFICATION_REMOTE_VIEWS:
                     return pullNotificationRemoteViews(atomTag, data);
                 case FrameworkStatsLog.DANGEROUS_PERMISSION_STATE_SAMPLED:
@@ -539,6 +542,7 @@
         registerAppsOnExternalStorageInfo();
         registerFaceSettings();
         registerAppOps();
+        registerRuntimeAppOpAccessMessage();
         registerNotificationRemoteViews();
         registerDangerousPermissionState();
         registerDangerousPermissionStateSampled();
@@ -2834,6 +2838,17 @@
 
     }
 
+    private void registerRuntimeAppOpAccessMessage() {
+        int tagId = FrameworkStatsLog.RUNTIME_APP_OP_ACCESS;
+        mStatsManager.registerPullAtomCallback(
+                tagId,
+                null, // use default PullAtomMetadata values
+                BackgroundThread.getExecutor(),
+                mStatsCallbackImpl
+        );
+
+    }
+
     int pullAppOps(int atomTag, List<StatsEvent> pulledData) {
         final long token = Binder.clearCallingIdentity();
         try {
@@ -2894,6 +2909,41 @@
         return StatsManager.PULL_SUCCESS;
     }
 
+    int pullRuntimeAppOpAccessMessage(int atomTag, List<StatsEvent> pulledData) {
+        final long token = Binder.clearCallingIdentity();
+        try {
+            AppOpsManager appOps = mContext.getSystemService(AppOpsManager.class);
+
+            RuntimeAppOpAccessMessage message = appOps.collectRuntimeAppOpAccessMessage();
+            if (message == null) {
+                Slog.i(TAG, "No runtime appop access message collected");
+                return StatsManager.PULL_SUCCESS;
+            }
+
+            StatsEvent.Builder e = StatsEvent.newBuilder();
+            e.setAtomId(atomTag);
+            e.writeInt(message.getUid());
+            e.writeString(message.getPackageName());
+            e.writeString(message.getOp());
+            if (message.getFeatureId() == null) {
+                e.writeString("");
+            } else {
+                e.writeString(message.getFeatureId());
+            }
+            e.writeString(message.getMessage());
+            e.writeInt(message.getSamplingStrategy());
+
+            pulledData.add(e.build());
+        } catch (Throwable t) {
+            // TODO: catch exceptions at a more granular level
+            Slog.e(TAG, "Could not read runtime appop access message", t);
+            return StatsManager.PULL_SKIP;
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+        return StatsManager.PULL_SUCCESS;
+    }
+
     static void unpackStreamedData(int atomTag, List<StatsEvent> pulledData,
             List<ParcelFileDescriptor> statsFiles) throws IOException {
         InputStream stream = new ParcelFileDescriptor.AutoCloseInputStream(statsFiles.get(0));
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 4cc4851..04fae97 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -1163,8 +1163,12 @@
         // An activity is considered to be in multi-window mode if its task isn't fullscreen.
         final boolean inMultiWindowMode = inMultiWindowMode();
         if (inMultiWindowMode != mLastReportedMultiWindowMode) {
-            mLastReportedMultiWindowMode = inMultiWindowMode;
-            scheduleMultiWindowModeChanged(getConfiguration());
+            if (!inMultiWindowMode && mLastReportedPictureInPictureMode) {
+                updatePictureInPictureMode(null, false);
+            } else {
+                mLastReportedMultiWindowMode = inMultiWindowMode;
+                scheduleMultiWindowModeChanged(getConfiguration());
+            }
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index 688f474..2f1cc05 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -658,8 +658,8 @@
     }
 
     @Override
-    public void resolveOverrideConfiguration(Configuration newParentConfig) {
-        super.resolveOverrideConfiguration(newParentConfig);
+    public void resolveTileOverrideConfiguration(Configuration newParentConfig) {
+        super.resolveTileOverrideConfiguration(newParentConfig);
         if (mTile != null) {
             // If this is a virtual child of a tile, simulate the parent-child relationship
             mTile.updateResolvedConfig(getResolvedOverrideConfiguration());
@@ -742,8 +742,8 @@
                 setBounds(newBounds);
             } else if (overrideWindowingMode != WINDOWING_MODE_PINNED) {
                 // For pinned stack, resize is now part of the {@link WindowContainerTransaction}
-                resize(new Rect(newBounds), null /* tempTaskBounds */,
-                        null /* tempTaskInsetBounds */, PRESERVE_WINDOWS, true /* deferResume */);
+                resize(new Rect(newBounds), null /* configBounds */,
+                        PRESERVE_WINDOWS, true /* deferResume */);
             }
         }
         if (prevIsAlwaysOnTop != isAlwaysOnTop()) {
@@ -952,8 +952,8 @@
             }
 
             if (!Objects.equals(getRequestedOverrideBounds(), mTmpRect2)) {
-                resize(mTmpRect2, null /* tempTaskBounds */, null /* tempTaskInsetBounds */,
-                        false /* preserveWindows */, true /* deferResume */);
+                resize(mTmpRect2, null /*configBounds*/,
+                        false /*preserveWindows*/, true /*deferResume*/);
             }
         } finally {
             if (showRecents && !alreadyInSplitScreenMode && isOnHomeDisplay()
@@ -1118,20 +1118,15 @@
         return r.getTask().mTaskId != taskId && r.appToken != notTop && r.canBeTopRunning();
     }
 
-    ActivityRecord isInStackLocked(IBinder token) {
-        final ActivityRecord r = ActivityRecord.forTokenLocked(token);
-        return isInStackLocked(r);
-    }
-
     ActivityRecord isInStackLocked(ActivityRecord r) {
         if (r == null) {
             return null;
         }
-        final Task task = r.getTask();
-        final ActivityStack stack = r.getRootTask();
-        if (stack != null && task.mChildren.contains(r) && mChildren.contains(task)) {
-            if (stack != this) Slog.w(TAG,
-                    "Illegal state! task does not point to stack it is in.");
+        final Task task = r.getRootTask();
+        if (task != null && r.isDescendantOf(task)) {
+            if (task != this) Slog.w(TAG, "Illegal state! task does not point to stack it is in. "
+                    + "stack=" + this + " task=" + task + " r=" + r
+                    + " callers=" + Debug.getCallers(15, "\n"));
             return r;
         }
         return null;
@@ -1207,7 +1202,7 @@
         }
 
         getDisplay().positionStackAtBottom(this, reason);
-        if (task != null) {
+        if (task != null && task != this) {
             positionChildAtBottom(task);
         }
 
@@ -1251,12 +1246,12 @@
         mCurrentUser = userId;
 
         super.switchUser(userId);
-        forAllTasks((t) -> {
-            if (t.showToCurrentUser()) {
+        forAllLeafTasks((t) -> {
+            if (t.showToCurrentUser() && t != this) {
                 mChildren.remove(t);
                 mChildren.add(t);
             }
-        }, true /* traverseTopToBottom */, this);
+        }, true /* traverseTopToBottom */);
     }
 
     void minimalResumeActivityLocked(ActivityRecord r) {
@@ -2450,16 +2445,16 @@
             boolean newTask, boolean keepCurTransition, ActivityOptions options) {
         Task rTask = r.getTask();
         final boolean allowMoveToFront = options == null || !options.getAvoidMoveToFront();
-        final boolean hasTask = hasChild(rTask);
+        final boolean isOrhasTask = rTask == this || hasChild(rTask);
         // mLaunchTaskBehind tasks get placed at the back of the task stack.
-        if (!r.mLaunchTaskBehind && allowMoveToFront && (!hasTask || newTask)) {
+        if (!r.mLaunchTaskBehind && allowMoveToFront && (!isOrhasTask || newTask)) {
             // Last activity in task had been removed or ActivityManagerService is reusing task.
             // Insert or replace.
             // Might not even be in.
             positionChildAtTop(rTask);
         }
         Task task = null;
-        if (!newTask && hasTask) {
+        if (!newTask && isOrhasTask) {
             final ActivityRecord occludingActivity = getActivity(
                     (ar) -> !ar.finishing && ar.occludesParent(), true, rTask);
             if (occludingActivity != null) {
@@ -2717,7 +2712,7 @@
     void finishVoiceTask(IVoiceInteractionSession session) {
         final PooledConsumer c = PooledLambda.obtainConsumer(ActivityStack::finishIfVoiceTask,
                 PooledLambda.__(Task.class), session.asBinder());
-        forAllTasks(c, true /* traverseTopToBottom */, this);
+        forAllLeafTasks(c, true /* traverseTopToBottom */);
         c.recycle();
     }
 
@@ -2818,8 +2813,7 @@
             return false;
         }
         final Task task = srec.getTask();
-
-        if (!mChildren.contains(task) || !task.hasChild(srec)) {
+        if (!srec.isDescendantOf(this)) {
             return false;
         }
 
@@ -2932,20 +2926,20 @@
         getDisplay().mDisplayContent.prepareAppTransition(transit, false);
     }
 
-    final void moveTaskToFrontLocked(Task tr, boolean noAnimation, ActivityOptions options,
+    final void moveTaskToFront(Task tr, boolean noAnimation, ActivityOptions options,
             AppTimeTracker timeTracker, String reason) {
-        moveTaskToFrontLocked(tr, noAnimation, options, timeTracker, !DEFER_RESUME, reason);
+        moveTaskToFront(tr, noAnimation, options, timeTracker, !DEFER_RESUME, reason);
     }
 
-    final void moveTaskToFrontLocked(Task tr, boolean noAnimation, ActivityOptions options,
+    final void moveTaskToFront(Task tr, boolean noAnimation, ActivityOptions options,
             AppTimeTracker timeTracker, boolean deferResume, String reason) {
         if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "moveTaskToFront: " + tr);
 
         final ActivityStack topStack = getDisplay().getTopStack();
-        final ActivityRecord topActivity = topStack != null ? topStack.getTopNonFinishingActivity() : null;
-        final int numTasks = getChildCount();
-        final int index = mChildren.indexOf(tr);
-        if (numTasks == 0 || index < 0)  {
+        final ActivityRecord topActivity = topStack != null
+                ? topStack.getTopNonFinishingActivity() : null;
+
+        if (tr != this && !tr.isDescendantOf(this)) {
             // nothing to do!
             if (noAnimation) {
                 ActivityOptions.abort(options);
@@ -3099,24 +3093,30 @@
 
     // TODO: Can only be called from special methods in ActivityStackSupervisor.
     // Need to consolidate those calls points into this resize method so anyone can call directly.
-    void resize(Rect bounds, Rect tempTaskBounds, Rect tempTaskInsetBounds,
-            boolean preserveWindows, boolean deferResume) {
-        if (!updateBoundsAllowed(bounds)) {
+    void resize(Rect displayedBounds, Rect configBounds, boolean preserveWindows,
+            boolean deferResume) {
+        if (!updateBoundsAllowed(displayedBounds)) {
             return;
         }
 
         Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "stack.resize_" + getRootTaskId());
         mAtmService.deferWindowLayout();
         try {
+            // TODO: Why not just set this on the stack directly vs. on each tasks?
             // Update override configurations of all tasks in the stack.
-            final Rect taskBounds = tempTaskBounds != null ? tempTaskBounds : bounds;
             final PooledConsumer c = PooledLambda.obtainConsumer(
                     ActivityStack::processTaskResizeBounds, PooledLambda.__(Task.class),
-                    taskBounds, tempTaskInsetBounds);
-            forAllTasks(c, true /* traverseTopToBottom */, this);
+                    displayedBounds, configBounds);
+            forAllTasks(c, true /* traverseTopToBottom */);
             c.recycle();
 
-            setBounds(bounds);
+            if (mBoundsAnimating) {
+                // Force to update task surface bounds and relayout windows, since configBounds
+                // remains unchanged during bounds animation.
+                updateSurfaceBounds();
+                getDisplay().setLayoutNeeded();
+                mWmService.requestTraversal();
+            }
 
             if (!deferResume) {
                 ensureVisibleActivitiesConfiguration(topRunningActivity(), preserveWindows);
@@ -3127,15 +3127,16 @@
         }
     }
 
-    private static void processTaskResizeBounds(Task task, Rect bounds, Rect insetBounds) {
+    private static void processTaskResizeBounds(
+            Task task, Rect displayedBounds, Rect configBounds) {
         if (!task.isResizeable()) return;
 
-        if (insetBounds != null && !insetBounds.isEmpty()) {
-            task.setOverrideDisplayedBounds(bounds);
-            task.setBounds(insetBounds);
+        if (configBounds != null && !configBounds.isEmpty()) {
+            task.setOverrideDisplayedBounds(displayedBounds);
+            task.setBounds(configBounds);
         } else {
             task.setOverrideDisplayedBounds(null);
-            task.setBounds(bounds);
+            task.setBounds(displayedBounds);
         }
     }
 
@@ -3150,7 +3151,7 @@
 
         final PooledConsumer c = PooledLambda.obtainConsumer(ActivityStack::setTaskBounds,
                 PooledLambda.__(Task.class), bounds);
-        forAllTasks(c, true /* traverseTopToBottom */, this);
+        forAllLeafTasks(c, true /* traverseTopToBottom */);
         c.recycle();
     }
 
@@ -3166,7 +3167,7 @@
 
         final PooledConsumer c = PooledLambda.obtainConsumer(ActivityStack::setTaskDisplayedBounds,
                 PooledLambda.__(Task.class), bounds);
-        forAllTasks(c, true /* traverseTopToBottom */, this);
+        forAllLeafTasks(c, true /* traverseTopToBottom */);
         c.recycle();
     }
 
@@ -3262,7 +3263,7 @@
             return false;
         }
         final String prefix = "    ";
-        forAllTasks((task) -> {
+        forAllLeafTasks((task) -> {
             if (needSep) {
                 pw.println("");
             }
@@ -3280,7 +3281,7 @@
                     false /* traverseTopToBottom */);
             dumpHistoryList(fd, pw, activities, prefix, "Hist", true, !dumpAll, dumpClient,
                     dumpPackage, false, null, task);
-        }, true /* traverseTopToBottom */, this);
+        }, true /* traverseTopToBottom */);
         return true;
     }
 
@@ -3331,19 +3332,33 @@
         }
     }
 
-    Task createTask(int taskId, ActivityInfo info, Intent intent, boolean toTop) {
-        return createTask(taskId, info, intent, null /*voiceSession*/, null /*voiceInteractor*/,
+    Task reuseOrCreateTask(ActivityInfo info, Intent intent, boolean toTop) {
+        return reuseOrCreateTask(info, intent, null /*voiceSession*/, null /*voiceInteractor*/,
                 toTop, null /*activity*/, null /*source*/, null /*options*/);
     }
+    // TODO: Can be removed once we change callpoints creating stacks to be creating tasks.
+    /** Either returns this current task to be re-used or creates a new child task. */
+    Task reuseOrCreateTask(ActivityInfo info, Intent intent, IVoiceInteractionSession voiceSession,
+            IVoiceInteractor voiceInteractor, boolean toTop, ActivityRecord activity,
+            ActivityRecord source, ActivityOptions options) {
 
-    Task createTask(int taskId, ActivityInfo info, Intent intent,
-            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
-            boolean toTop, ActivityRecord activity, ActivityRecord source,
-            ActivityOptions options) {
-        final Task task = Task.create(
-                mAtmService, taskId, info, intent, voiceSession, voiceInteractor, this);
-        // add the task to stack first, mTaskPositioner might need the stack association
-        addChild(task, toTop, (info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0);
+        Task task;
+        if (DisplayContent.alwaysCreateStack(getWindowingMode(), getActivityType())) {
+            // This stack will only contain one task, so just return itself since all stacks ara now
+            // tasks and all tasks are now stacks.
+            task = reuseAsLeafTask(voiceSession, voiceInteractor, info, activity);
+        } else {
+            // Create child task since this stack can contain multiple tasks.
+            final int taskId = activity != null
+                    ? mStackSupervisor.getNextTaskIdForUser(activity.mUserId)
+                    : mStackSupervisor.getNextTaskIdForUser();
+            task = Task.create(
+                    mAtmService, taskId, info, intent, voiceSession, voiceInteractor, this);
+
+            // add the task to stack first, mTaskPositioner might need the stack association
+            addChild(task, toTop, (info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0);
+        }
+
         int displayId = getDisplayId();
         if (displayId == INVALID_DISPLAY) displayId = DEFAULT_DISPLAY;
         final boolean isLockscreenShown = mAtmService.mStackSupervisor.getKeyguardController()
@@ -3353,6 +3368,7 @@
                 && !matchParentBounds() && task.isResizeable() && !isLockscreenShown) {
             task.setBounds(getRequestedOverrideBounds());
         }
+
         return task;
     }
 
@@ -3559,10 +3575,6 @@
                     "Can't exit pinned mode if it's not pinned already.");
         }
 
-        if (mChildren.size() != 1) {
-            throw new RuntimeException("There should be only one task in a pinned stack.");
-        }
-
         // give pinned stack a chance to save current bounds, this should happen before reparent.
         final ActivityRecord top = topRunningNonOverlayTaskActivity();
         if (top != null && top.isVisible()) {
@@ -3592,12 +3604,12 @@
         final PooledConsumer c = PooledLambda.obtainConsumer(
                 ActivityStackSupervisor::updatePictureInPictureMode, mStackSupervisor,
                 PooledLambda.__(Task.class), targetStackBounds, forceUpdate);
-        forAllTasks(c, true /* traverseTopToBottom */, this);
+        forAllLeafTasks(c, true /* traverseTopToBottom */);
         c.recycle();
     }
 
     void prepareFreezingTaskBounds() {
-        forAllTasks(Task::prepareFreezingBounds, true /* traverseTopToBottom */, this);
+        forAllLeafTasks(Task::prepareFreezingBounds, true /* traverseTopToBottom */);
     }
 
     /**
@@ -3629,7 +3641,7 @@
             final PooledConsumer c = PooledLambda.obtainConsumer(Task::alignToAdjustedBounds,
                     PooledLambda.__(Task.class), adjusted ? mAdjustedBounds : getRawBounds(),
                     insetBounds, alignBottom);
-            forAllTasks(c, true /* traverseTopToBottom */, this);
+            forAllLeafTasks(c, true /* traverseTopToBottom */);
             c.recycle();
         }
 
@@ -3902,6 +3914,12 @@
             return;
         }
 
+        if (child == this) {
+            // TODO: Fix call-points
+            moveToFront("positionChildAtTop");
+            return;
+        }
+
         positionChildAt(POSITION_TOP, child, true /* includingParents */);
         child.updateTaskMovement(true);
 
@@ -4316,19 +4334,19 @@
      * to the list of to be drawn windows the service is waiting for.
      */
     void beginImeAdjustAnimation() {
-        forAllTasks((t) -> {
+        forAllLeafTasks((t) -> {
             if (t.hasContentToDisplay()) {
                 t.setDragResizing(true, DRAG_RESIZE_MODE_DOCKED_DIVIDER);
                 t.setWaitingForDrawnIfResizingChanged();
             }
-        }, true /* traverseTopToBottom */, this);
+        }, true /* traverseTopToBottom */);
     }
 
     /** Resets the resizing state of all windows. */
     void endImeAdjustAnimation() {
-        forAllTasks((t) -> {
+        forAllLeafTasks((t) -> {
             t.setDragResizing(false, DRAG_RESIZE_MODE_DOCKED_DIVIDER);
-        }, true /* traverseTopToBottom */, this);
+        }, true /* traverseTopToBottom */);
     }
 
     private int getMinTopStackBottom(final Rect displayContentRect, int originalStackBottom) {
@@ -4572,19 +4590,15 @@
         return task != null;
     }
 
-    public boolean setPinnedStackSize(Rect stackBounds, Rect tempTaskBounds) {
+    public boolean setPinnedStackSize(Rect displayedBounds, Rect configBounds) {
         // Hold the lock since this is called from the BoundsAnimator running on the UiThread
         synchronized (mWmService.mGlobalLock) {
             if (mCancelCurrentBoundsAnimation) {
                 return false;
             }
+            mStackSupervisor.resizePinnedStack(displayedBounds, configBounds);
         }
 
-        try {
-            mWmService.mActivityTaskManager.resizePinnedStack(stackBounds, tempTaskBounds);
-        } catch (RemoteException e) {
-            // I don't believe you.
-        }
         return true;
     }
 
@@ -4730,7 +4744,7 @@
     /** Called immediately prior to resizing the tasks at the end of the pinned stack animation. */
     void onPipAnimationEndResize() {
         mBoundsAnimating = false;
-        forAllTasks(Task::clearPreserveNonFloatingState, false /* traverseTopToBottom */, this);
+        forAllLeafTasks(Task::clearPreserveNonFloatingState, false /* traverseTopToBottom */);
         mWmService.requestTraversal();
     }
 
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index 70cd01b..97b6388 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -419,14 +419,29 @@
             mTopTask = fromStack.getTopMostTask();
 
             final PooledConsumer c = PooledLambda.obtainConsumer(
-                    MoveTaskToFullscreenHelper::processTask, this, PooledLambda.__(Task.class));
-            fromStack.forAllTasks(c, false /* traverseTopToBottom */, fromStack);
+                    MoveTaskToFullscreenHelper::processLeafTask, this, PooledLambda.__(Task.class));
+            fromStack.forAllLeafTasks(c, false /* traverseTopToBottom */);
             c.recycle();
             mToDisplay = null;
             mTopTask = null;
         }
 
-        private void processTask(Task task) {
+        private void processLeafTask(Task task) {
+            // This is a one level task that we don't need to create stack for reparenting to.
+            if (task.isRootTask() && DisplayContent.alwaysCreateStack(WINDOWING_MODE_FULLSCREEN,
+                    task.getActivityType())) {
+                final ActivityStack stack = (ActivityStack) task;
+                stack.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+                if (mToDisplay.getDisplayId() != stack.getDisplayId()) {
+                    mToDisplay.moveStackToDisplay(stack, mOnTop);
+                } else if (mOnTop) {
+                    mToDisplay.positionStackAtTop(stack, false /* includingParents */);
+                } else {
+                    mToDisplay.positionStackAtBottom(stack);
+                }
+                return;
+            }
+
             final ActivityStack toStack = mToDisplay.getOrCreateStack(
                     null, mTmpOptions, task, task.getActivityType(), mOnTop);
 
@@ -1428,8 +1443,7 @@
                 // still need moveTaskToFrontLocked() below for any transition settings.
             }
             if (stack.shouldResizeStackWithLaunchBounds()) {
-                stack.resize(bounds, null /* tempTaskBounds */, null /* tempTaskInsetBounds */,
-                        !PRESERVE_WINDOWS, !DEFER_RESUME);
+                stack.resize(bounds, null /* configBounds */, !PRESERVE_WINDOWS, !DEFER_RESUME);
             } else {
                 // WM resizeTask must be done after the task is moved to the correct stack,
                 // because Task's setBounds() also updates dim layer's bounds, but that has
@@ -1443,7 +1457,7 @@
         }
 
         final ActivityRecord r = task.getTopNonFinishingActivity();
-        currentStack.moveTaskToFrontLocked(task, false /* noAnimation */, options,
+        currentStack.moveTaskToFront(task, false /* noAnimation */, options,
                 r == null ? null : r.appTimeTracker, reason);
 
         if (DEBUG_STACK) Slog.d(TAG_STACK,
@@ -1589,7 +1603,7 @@
                 false /* deferResume */);
     }
 
-    void resizeDockedStackLocked(Rect dockedBounds, Rect tempDockedTaskBounds,
+    void resizeDockedStackLocked(Rect displayedBounds, Rect tempDockedTaskBounds,
             Rect tempDockedTaskInsetBounds, Rect tempOtherTaskBounds, Rect tempOtherTaskInsetBounds,
             boolean preserveWindows, boolean deferResume) {
 
@@ -1607,7 +1621,7 @@
 
         if (mDockedStackResizing) {
             mHasPendingDockedBounds = true;
-            mPendingDockedBounds = copyOrNull(dockedBounds);
+            mPendingDockedBounds = copyOrNull(displayedBounds);
             mPendingTempDockedTaskBounds = copyOrNull(tempDockedTaskBounds);
             mPendingTempDockedTaskInsetBounds = copyOrNull(tempDockedTaskInsetBounds);
             mPendingTempOtherTaskBounds = copyOrNull(tempOtherTaskBounds);
@@ -1620,13 +1634,13 @@
             // Don't allow re-entry while resizing. E.g. due to docked stack detaching.
             mAllowDockedStackResize = false;
             ActivityRecord r = stack.topRunningActivity();
-            stack.resize(dockedBounds, tempDockedTaskBounds, tempDockedTaskInsetBounds,
+            stack.resize(displayedBounds, tempDockedTaskBounds,
                     !PRESERVE_WINDOWS, DEFER_RESUME);
 
             // TODO: Checking for isAttached might not be needed as if the user passes in null
             // dockedBounds then they want the docked stack to be dismissed.
             if (stack.getWindowingMode() == WINDOWING_MODE_FULLSCREEN
-                    || (dockedBounds == null && !stack.isAttached())) {
+                    || (displayedBounds == null && !stack.isAttached())) {
                 // The dock stack either was dismissed or went fullscreen, which is kinda the same.
                 // In this case we make all other static stacks fullscreen and move all
                 // docked stack tasks to the fullscreen stack.
@@ -1654,7 +1668,7 @@
                         // interaction.
                         continue;
                     }
-                    current.getStackDockedModeBounds(dockedBounds,
+                    current.getStackDockedModeBounds(displayedBounds,
                             tempOtherTaskBounds /* currentTempTaskBounds */,
                             tempRect /* outStackBounds */,
                             otherTaskRect /* outTempTaskBounds */);
@@ -1669,9 +1683,7 @@
                                 + " non-fullscreen stack");
                     }
 
-                    current.resize(tempRect,
-                            !otherTaskRect.isEmpty() ? otherTaskRect : tempOtherTaskBounds,
-                            tempOtherTaskInsetBounds, preserveWindows, deferResume);
+                    current.resize(tempRect, tempOtherTaskBounds, preserveWindows, deferResume);
                 }
             }
             if (!deferResume) {
@@ -1684,7 +1696,7 @@
         }
     }
 
-    void resizePinnedStackLocked(Rect pinnedBounds, Rect tempPinnedTaskBounds) {
+    void resizePinnedStack(Rect displayedBounds, Rect inConfigBounds) {
         // TODO(multi-display): The display containing the stack should be passed in.
         final ActivityStack stack =
                 mRootWindowContainer.getDefaultDisplay().getRootPinnedTask();
@@ -1696,23 +1708,22 @@
         Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "resizePinnedStack");
         mService.deferWindowLayout();
         try {
-            Rect insetBounds = null;
-            if (tempPinnedTaskBounds != null && stack.isAnimatingBoundsToFullscreen()) {
+            Rect configBounds = null;
+            if (inConfigBounds != null) {
                 // Use 0,0 as the position for the inset rect because we are headed for fullscreen.
-                insetBounds = tempRect;
-                insetBounds.top = 0;
-                insetBounds.left = 0;
-                insetBounds.right = tempPinnedTaskBounds.width();
-                insetBounds.bottom = tempPinnedTaskBounds.height();
+                configBounds = tempRect;
+                configBounds.top = 0;
+                configBounds.left = 0;
+                configBounds.right = inConfigBounds.width();
+                configBounds.bottom = inConfigBounds.height();
             }
-            if (pinnedBounds != null && tempPinnedTaskBounds == null) {
+            if (displayedBounds != null && inConfigBounds == null) {
                 // We have finished the animation into PiP, and are resizing the tasks to match the
                 // stack bounds, while layouts are deferred, update any task state as a part of
                 // transitioning it from fullscreen into a floating state.
                 stack.onPipAnimationEndResize();
             }
-            stack.resize(pinnedBounds, tempPinnedTaskBounds, insetBounds, !PRESERVE_WINDOWS,
-                    !DEFER_RESUME);
+            stack.resize(displayedBounds, configBounds, !PRESERVE_WINDOWS, !DEFER_RESUME);
         } finally {
             mService.continueWindowLayout();
             Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
@@ -1742,7 +1753,7 @@
         } else {
             final PooledConsumer c = PooledLambda.obtainConsumer(
                     ActivityStackSupervisor::processRemoveTask, this, PooledLambda.__(Task.class));
-            stack.forAllTasks(c, true /* traverseTopToBottom */, stack);
+            stack.forAllLeafTasks(c, true /* traverseTopToBottom */);
             c.recycle();
         }
     }
@@ -2755,6 +2766,10 @@
                 deferUpdateRecentsHomeStackBounds();
                 // TODO(multi-display): currently recents animation only support default display.
                 mWindowManager.prepareAppTransition(TRANSIT_DOCK_TASK_FROM_RECENTS, false);
+                // TODO(task-hierarchy): Remove when tiles are in hierarchy.
+                // Unset launching windowing mode to prevent creating split-screen-primary stack
+                // in RWC#anyTaskForId() below.
+                activityOptions.setLaunchWindowingMode(WINDOWING_MODE_UNDEFINED);
             }
 
             task = mRootWindowContainer.anyTaskForId(taskId,
@@ -2764,6 +2779,9 @@
                 mWindowManager.executeAppTransition();
                 throw new IllegalArgumentException(
                         "startActivityFromRecents: Task " + taskId + " not found.");
+            } else if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
+                    && task.getWindowingMode() != windowingMode) {
+                mService.moveTaskToSplitScreenPrimaryTile(task, true /* toTop */);
             }
 
             if (windowingMode != WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 2a2ab4b..600a125 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -2366,7 +2366,7 @@
                     // task on top there.
                     // Defer resuming the top activity while moving task to top, since the
                     // current task-top activity may not be the activity that should be resumed.
-                    mTargetStack.moveTaskToFrontLocked(intentTask, mNoAnimation, mOptions,
+                    mTargetStack.moveTaskToFront(intentTask, mNoAnimation, mOptions,
                             mStartActivity.appTimeTracker, DEFER_RESUME,
                             "bringingFoundTaskToFront");
                     mMovedToFront = !isSplitScreenTopStack;
@@ -2396,8 +2396,7 @@
 
     private void setNewTask(Task taskToAffiliate) {
         final boolean toTop = !mLaunchTaskBehind && !mAvoidMoveToFront;
-        final Task task = mTargetStack.createTask(
-                mSupervisor.getNextTaskIdForUser(mStartActivity.mUserId),
+        final Task task = mTargetStack.reuseOrCreateTask(
                 mNewTaskInfo != null ? mNewTaskInfo : mStartActivity.info,
                 mNewTaskIntent != null ? mNewTaskIntent : mIntent, mVoiceSession,
                 mVoiceInteractor, toTop, mStartActivity, mSourceRecord, mOptions);
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 882d5c7..344d4a5 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -2760,9 +2760,17 @@
             throw new IllegalArgumentException("setTaskWindowingMode: Attempt to move"
                     + " non-standard task " + taskId + " to split-screen windowing mode");
         }
+        if (!task.supportsSplitScreenWindowingMode()) {
+            return false;
+        }
 
         final int prevMode = task.getWindowingMode();
-        final ActivityStack stack = task.getStack();
+        moveTaskToSplitScreenPrimaryTile(task, toTop);
+        return prevMode != task.getWindowingMode();
+    }
+
+    void moveTaskToSplitScreenPrimaryTile(Task task, boolean toTop) {
+        ActivityStack stack = task.getStack();
         TaskTile tile = null;
         for (int i = stack.getDisplay().getStackCount() - 1; i >= 0; --i) {
             tile = stack.getDisplay().getStackAt(i).asTile();
@@ -2776,7 +2784,6 @@
         WindowContainerTransaction wct = new WindowContainerTransaction();
         wct.reparent(stack.mRemoteToken, tile.mRemoteToken, toTop);
         mTaskOrganizerController.applyContainerTransaction(wct, null);
-        return prevMode != task.getWindowingMode();
     }
 
     /**
@@ -3247,8 +3254,9 @@
                 }
 
                 final ActivityStack stack = r.getRootTask();
-                final Task task = stack.createTask(
-                        mStackSupervisor.getNextTaskIdForUser(r.mUserId), ainfo, intent, !ON_TOP);
+                final Task task = stack.getDisplay().createStack(stack.getWindowingMode(),
+                        stack.getActivityType(), !ON_TOP, ainfo, intent);
+
                 if (!mRecentTasks.addToBottom(task)) {
                     // The app has too many tasks already and we can't add any more
                     stack.removeChild(task, "addAppTask");
@@ -4426,12 +4434,12 @@
     }
 
     @Override
-    public void resizePinnedStack(Rect pinnedBounds, Rect tempPinnedTaskBounds) {
+    public void resizePinnedStack(Rect displayedBounds, Rect configBounds) {
         enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "resizePinnedStack()");
         final long ident = Binder.clearCallingIdentity();
         try {
             synchronized (mGlobalLock) {
-                mStackSupervisor.resizePinnedStackLocked(pinnedBounds, tempPinnedTaskBounds);
+                mStackSupervisor.resizePinnedStack(displayedBounds, configBounds);
             }
         } finally {
             Binder.restoreCallingIdentity(ident);
diff --git a/services/core/java/com/android/server/wm/BoundsAnimationTarget.java b/services/core/java/com/android/server/wm/BoundsAnimationTarget.java
index 9f54e49e0..b1d5359 100644
--- a/services/core/java/com/android/server/wm/BoundsAnimationTarget.java
+++ b/services/core/java/com/android/server/wm/BoundsAnimationTarget.java
@@ -52,7 +52,7 @@
      * animation is now invalid and not required. In such a case, the cancel will trigger the
      * animation end callback as well, but will not send any further size changes.
      */
-    boolean setPinnedStackSize(Rect stackBounds, Rect taskBounds);
+    boolean setPinnedStackSize(Rect displayedBounds, Rect configBounds);
 
     /** Sets the alpha of the animation target */
     boolean setPinnedStackAlpha(float alpha);
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index e60ab3f..0029dc8 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -4415,7 +4415,7 @@
         ArrayList<Task> getVisibleTasks() {
             final ArrayList<Task> visibleTasks = new ArrayList<>();
             forAllTasks(task -> {
-                if (!task.isRootTask() && task.isVisible()) {
+                if (task.isLeafTask() && task.isVisible()) {
                     visibleTasks.add(task);
                 }
             });
@@ -4537,6 +4537,8 @@
                         true /* includingParents */);
             }
 
+            child.updateTaskMovement(moveToTop);
+
             setLayoutNeeded();
         }
 
@@ -5790,7 +5792,7 @@
         return null;
     }
 
-    boolean alwaysCreateStack(int windowingMode, int activityType) {
+    static boolean alwaysCreateStack(int windowingMode, int activityType) {
         // Always create a stack for fullscreen, freeform, and split-screen-secondary windowing
         // modes so that we can manage visual ordering and return types correctly.
         return activityType == ACTIVITY_TYPE_STANDARD
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index e443fe4..f02a9dd 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -131,7 +131,6 @@
 import android.graphics.Region;
 import android.hardware.input.InputManager;
 import android.hardware.power.V1_0.PowerHint;
-import android.os.Binder;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
@@ -304,6 +303,8 @@
 
     private boolean mIsFreeformWindowOverlappingWithNavBar;
 
+    private boolean mLastImmersiveMode;
+
     private final StatusBarController mStatusBarController;
 
     private final BarController mNavigationBarController;
@@ -3182,8 +3183,8 @@
                     if (nb) mNavigationBarController.showTransient();
                     updateSystemUiVisibilityLw();
                 }
-                mImmersiveModeConfirmation.confirmCurrentPrompt();
             }
+            mImmersiveModeConfirmation.confirmCurrentPrompt();
         }
     }
 
@@ -3210,7 +3211,7 @@
         updateSystemUiVisibilityLw();
     }
 
-    private int updateSystemUiVisibilityLw() {
+    int updateSystemUiVisibilityLw() {
         // If there is no window focused, there will be nobody to handle the events
         // anyway, so just hang on in whatever state we're in until things settle down.
         WindowState winCandidate = mFocusedWindow != null ? mFocusedWindow
@@ -3566,9 +3567,11 @@
         vis = mStatusBarController.updateVisibilityLw(transientStatusBarAllowed, oldVis, vis);
 
         // update navigation bar
-        boolean oldImmersiveMode = isImmersiveMode(oldVis);
-        boolean newImmersiveMode = isImmersiveMode(vis);
+        boolean newInsetsMode = ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_FULL;
+        boolean oldImmersiveMode = newInsetsMode ? mLastImmersiveMode : isImmersiveMode(oldVis);
+        boolean newImmersiveMode = newInsetsMode ? isImmersiveMode(win) : isImmersiveMode(vis);
         if (oldImmersiveMode != newImmersiveMode) {
+            mLastImmersiveMode = newImmersiveMode;
             final String pkg = win.getOwningPackage();
             mImmersiveModeConfirmation.immersiveModeChangedLw(pkg, newImmersiveMode,
                     mService.mPolicy.isUserSetupComplete(),
@@ -3673,6 +3676,7 @@
         }
     }
 
+    // TODO(b/118118435): Remove this after migration
     private boolean isImmersiveMode(int vis) {
         final int flags = View.SYSTEM_UI_FLAG_IMMERSIVE | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
         return mNavigationBar != null
@@ -3681,6 +3685,16 @@
                 && canHideNavigationBar();
     }
 
+    private boolean isImmersiveMode(WindowState win) {
+        final int behavior = win.mAttrs.insetsFlags.behavior;
+        return mNavigationBar != null
+                && canHideNavigationBar()
+                && (behavior == BEHAVIOR_SHOW_BARS_BY_SWIPE
+                        || behavior == BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE)
+                && getInsetsPolicy().isHidden(ITYPE_NAVIGATION_BAR)
+                && win != getNotificationShade();
+    }
+
     /**
      * @return whether the navigation bar can be hidden, e.g. the device has a navigation bar
      */
diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java
index 64c5faa..57babb0 100644
--- a/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -558,16 +558,14 @@
 
     @VisibleForTesting
     boolean shouldRotateSeamlessly(int oldRotation, int newRotation, boolean forceUpdate) {
-        final WindowState w = mDisplayPolicy.getTopFullscreenOpaqueWindow();
-        if (w == null) {
-            return false;
-        }
         // Display doesn't need to be frozen because application has been started in correct
         // rotation already, so the rest of the windows can use seamless rotation.
-        if (w.mToken.hasFixedRotationTransform()) {
+        if (mDisplayContent.mFixedRotationLaunchingApp != null) {
             return true;
         }
-        if (w != mDisplayContent.mCurrentFocus) {
+
+        final WindowState w = mDisplayPolicy.getTopFullscreenOpaqueWindow();
+        if (w == null || w != mDisplayContent.mCurrentFocus) {
             return false;
         }
         // We only enable seamless rotation if the top window has requested it and is in the
diff --git a/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java b/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java
index 9d985d7..c92de2b 100644
--- a/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java
+++ b/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java
@@ -76,7 +76,7 @@
         // to be visible (such as performing Recents animation).
         final boolean resumeTopActivity = mTop != null && !mTop.mLaunchTaskBehind
                 && mContiner.isTopActivityFocusable()
-                && mContiner.isInStackLocked(starting) == null;
+                && (starting == null || !starting.isDescendantOf(mContiner));
 
         final PooledConsumer f = PooledLambda.obtainConsumer(
                 EnsureActivitiesVisibleHelper::setActivityVisibilityState, this,
diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java
index a8fe349..b3890cd 100644
--- a/services/core/java/com/android/server/wm/InsetsStateController.java
+++ b/services/core/java/com/android/server/wm/InsetsStateController.java
@@ -182,6 +182,7 @@
         }
         if (changed) {
             notifyInsetsChanged();
+            mDisplayContent.getDisplayPolicy().updateSystemUiVisibilityLw();
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java
index b0492be..e92bbaa 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimation.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimation.java
@@ -334,7 +334,7 @@
                         if (sendUserLeaveHint) {
                             // Setting this allows the previous app to PiP.
                             mStackSupervisor.mUserLeaving = true;
-                            targetStack.moveTaskToFrontLocked(targetActivity.getTask(),
+                            targetStack.moveTaskToFront(targetActivity.getTask(),
                                     true /* noAnimation */, null /* activityOptions */,
                                     targetActivity.appTimeTracker,
                                     "RecentsAnimation.onAnimationFinished()");
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index e923e64..57c877f 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -376,7 +376,7 @@
             final PooledConsumer c = PooledLambda.obtainConsumer((t, outList) ->
 	            { if (!outList.contains(t)) outList.add(t); }, PooledLambda.__(Task.class),
                     visibleTasks);
-            targetStack.forAllTasks(c, true /* traverseTopToBottom */, targetStack);
+            targetStack.forAllLeafTasks(c, true /* traverseTopToBottom */);
             c.recycle();
         }
 
diff --git a/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java b/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java
index 63346b9..45f8a15 100644
--- a/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java
+++ b/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java
@@ -67,7 +67,7 @@
 
         final PooledConsumer c = PooledLambda.obtainConsumer(
                 ResetTargetTaskHelper::processTask, this, PooledLambda.__(Task.class));
-        targetTask.mWmService.mRoot.forAllTasks(c, true /*traverseTopToBottom*/, mTargetStack);
+        targetTask.mWmService.mRoot.forAllLeafTasks(c, true /*traverseTopToBottom*/);
         c.recycle();
 
         processPendingReparentActivities();
@@ -245,9 +245,8 @@
                 if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Start pushing activity "
                         + r + " out to bottom task " + targetTask);
             } else {
-                targetTask = mTargetStack.createTask(
-                        atmService.mStackSupervisor.getNextTaskIdForUser(r.mUserId), r.info,
-                        null /* intent */, false /* toTop */);
+                targetTask = mTargetStack.reuseOrCreateTask(
+                        r.info, null /*intent*/, false /*toTop*/);
                 targetTask.affinityIntent = r.intent;
                 createdTasks.add(targetTask);
                 if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Start pushing activity "
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 2596452..aa6bdfd 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -2137,10 +2137,7 @@
                         r.getActivityType(), ON_TOP, r.info, r.intent);
                 // There are multiple activities in the task and moving the top activity should
                 // reveal/leave the other activities in their original task.
-
-                Task newTask = stack.createTask(mStackSupervisor.getNextTaskIdForUser(r.mUserId),
-                        r.info, r.intent, true);
-                r.reparent(newTask, MAX_VALUE, "moveActivityToStack");
+                r.reparent(stack, MAX_VALUE, "moveActivityToStack");
             }
 
             stack.setWindowingMode(WINDOWING_MODE_PINNED);
@@ -2407,7 +2404,7 @@
         final PooledConsumer c = PooledLambda.obtainConsumer(
                 RootWindowContainer::processTaskForStackInfo, PooledLambda.__(Task.class), info,
                 currentIndex);
-        stack.forAllTasks(c, false /* traverseTopToBottom */, stack);
+        stack.forAllLeafTasks(c, false /* traverseTopToBottom */);
         c.recycle();
 
         final ActivityRecord top = stack.topRunningActivity();
@@ -3302,7 +3299,7 @@
             final PooledConsumer c = PooledLambda.obtainConsumer(
                     RootWindowContainer::taskTopActivityIsUser, this, PooledLambda.__(Task.class),
                     userId);
-            forAllTasks(c);
+            forAllLeafTasks(c, true /* traverseTopToBottom */);
             c.recycle();
         } finally {
             mService.continueWindowLayout();
@@ -3321,14 +3318,6 @@
      * @return {@code true} if the top activity looks like it belongs to {@param userId}.
      */
     private void taskTopActivityIsUser(Task task, @UserIdInt int userId) {
-        // TODO(b/80414790): having utilities to loop for all leaf tasks from caller vs. checking
-        //  leaf tasks here.
-        if (!task.isLeafTask()) {
-            // No op if not a leaf task since we don't want to report root tasks to
-            // TaskStackListeners.
-            return;
-        }
-
         // To handle the case that work app is in the task but just is not the top one.
         final ActivityRecord activityRecord = task.getTopNonFinishingActivity();
         final ActivityRecord resultTo = (activityRecord != null ? activityRecord.resultTo : null);
@@ -3430,18 +3419,8 @@
     }
 
     ActivityRecord isInAnyStack(IBinder token) {
-        int numDisplays = getChildCount();
-        for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
-            final DisplayContent display = getChildAt(displayNdx);
-            for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) {
-                final ActivityStack stack = display.getStackAt(stackNdx);
-                final ActivityRecord r = stack.isInStackLocked(token);
-                if (r != null) {
-                    return r;
-                }
-            }
-        }
-        return null;
+        final ActivityRecord r = ActivityRecord.forTokenLocked(token);
+        return (r != null && r.isDescendantOf(this)) ? r : null;
     }
 
     @VisibleForTesting
diff --git a/services/core/java/com/android/server/wm/RunningTasks.java b/services/core/java/com/android/server/wm/RunningTasks.java
index 6ebbf77..9593ea0 100644
--- a/services/core/java/com/android/server/wm/RunningTasks.java
+++ b/services/core/java/com/android/server/wm/RunningTasks.java
@@ -76,7 +76,7 @@
 
         final PooledConsumer c = PooledLambda.obtainConsumer(RunningTasks::processTask, this,
                 PooledLambda.__(Task.class));
-        root.forAllTasks(c, false);
+        root.forAllLeafTasks(c, false);
         c.recycle();
 
         // Take the first {@param maxNum} tasks and create running task infos for them
@@ -93,9 +93,6 @@
     }
 
     private void processTask(Task task) {
-        if (task.isRootTask()) {
-            return;
-        }
         if (task.getTopNonFinishingActivity() == null) {
             // Skip if there are no activities in the task
             return;
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index c7f2cc7..f93e392 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -225,8 +225,8 @@
 
     String affinity;        // The affinity name for this task, or null; may change identity.
     String rootAffinity;    // Initial base affinity, or null; does not change from initial root.
-    final IVoiceInteractionSession voiceSession;    // Voice interaction session driving task
-    final IVoiceInteractor voiceInteractor;         // Associated interactor to provide to app
+    IVoiceInteractionSession voiceSession;    // Voice interaction session driving task
+    IVoiceInteractor voiceInteractor;         // Associated interactor to provide to app
     Intent intent;          // The original intent that started the task. Note that this value can
                             // be null.
     Intent affinityIntent;  // Intent of affinity-moved activity that started this task.
@@ -422,6 +422,8 @@
     /** When set, will force the task to report as invisible. */
     boolean mForceHidden = false;
 
+    SurfaceControl.Transaction mMainWindowSizeChangeTransaction;
+
     private final FindRootHelper mFindRootHelper = new FindRootHelper();
     private class FindRootHelper {
         private ActivityRecord mRoot;
@@ -571,6 +573,15 @@
         mAtmService.getTaskChangeNotificationController().notifyTaskCreated(_taskId, realActivity);
     }
 
+    Task reuseAsLeafTask(IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor,
+            ActivityInfo info, ActivityRecord activity) {
+        voiceSession = _voiceSession;
+        voiceInteractor = _voiceInteractor;
+        setIntent(activity);
+        setMinDimensions(info);
+        return this;
+    }
+
     private void cleanUpResourcesForDestroy(ConfigurationContainer oldParent) {
         if (hasChild()) {
             return;
@@ -1004,7 +1015,7 @@
     }
 
     /** Sets the original minimal width and height. */
-    private void setMinDimensions(ActivityInfo info) {
+    void setMinDimensions(ActivityInfo info) {
         if (info != null && info.windowLayout != null) {
             mMinWidth = info.windowLayout.minWidth;
             mMinHeight = info.windowLayout.minHeight;
@@ -2176,16 +2187,20 @@
         return Configuration.reduceScreenLayout(sourceScreenLayout, longSize, shortSize);
     }
 
+    void resolveTileOverrideConfiguration(Configuration newParentConfig) {
+        super.resolveOverrideConfiguration(newParentConfig);
+    }
+
     @Override
     void resolveOverrideConfiguration(Configuration newParentConfig) {
-        if (isRootTask()) {
-            super.resolveOverrideConfiguration(newParentConfig);
+        if (!isLeafTask()) {
+            resolveTileOverrideConfiguration(newParentConfig);
             return;
         }
         mTmpBounds.set(getResolvedOverrideConfiguration().windowConfiguration.getBounds());
-        super.resolveOverrideConfiguration(newParentConfig);
+        resolveTileOverrideConfiguration(newParentConfig);
         int windowingMode =
-                getRequestedOverrideConfiguration().windowConfiguration.getWindowingMode();
+                getResolvedOverrideConfiguration().windowConfiguration.getWindowingMode();
         if (windowingMode == WINDOWING_MODE_UNDEFINED) {
             windowingMode = newParentConfig.windowConfiguration.getWindowingMode();
         }
@@ -2392,7 +2407,7 @@
         final int[] currentCount = {0};
         final PooledConsumer c = PooledLambda.obtainConsumer((t, count) -> { count[0]++; },
                 PooledLambda.__(Task.class), currentCount);
-        forAllTasks(c, false /* traverseTopToBottom */, this);
+        forAllLeafTasks(c, false /* traverseTopToBottom */);
         c.recycle();
         return currentCount[0];
     }
@@ -2614,6 +2629,7 @@
      */
     void setOverrideDisplayedBounds(Rect overrideDisplayedBounds) {
         if (overrideDisplayedBounds != null) {
+            adjustForMinimalTaskDimensions(overrideDisplayedBounds, mOverrideDisplayedBounds);
             mOverrideDisplayedBounds.set(overrideDisplayedBounds);
         } else {
             mOverrideDisplayedBounds.setEmpty();
@@ -3074,16 +3090,33 @@
     }
 
     @Override
-    void forAllTasks(Consumer<Task> callback, boolean traverseTopToBottom, Task excludedTask) {
-        super.forAllTasks(callback, traverseTopToBottom, excludedTask);
-        if (excludedTask != this) {
-            callback.accept(this);
+    void forAllLeafTasks(Consumer<Task> callback, boolean traverseTopToBottom) {
+        final int count = mChildren.size();
+        boolean isLeafTask = true;
+        if (traverseTopToBottom) {
+            for (int i = count - 1; i >= 0; --i) {
+                final Task child = mChildren.get(i).asTask();
+                if (child != null) {
+                    isLeafTask = false;
+                    child.forAllLeafTasks(callback, traverseTopToBottom);
+                }
+            }
+        } else {
+            for (int i = 0; i < count; i++) {
+                final Task child = mChildren.get(i).asTask();
+                if (child != null) {
+                    isLeafTask = false;
+                    child.forAllLeafTasks(callback, traverseTopToBottom);
+                }
+            }
         }
+        if (isLeafTask) callback.accept(this);
     }
 
     @Override
     void forAllTasks(Consumer<Task> callback, boolean traverseTopToBottom) {
-        forAllTasks(callback, traverseTopToBottom, null /* excludedTask */);
+        super.forAllTasks(callback, traverseTopToBottom);
+        callback.accept(this);
     }
 
     @Override
@@ -3265,7 +3298,7 @@
         pw.print(" effectiveUid="); UserHandle.formatUid(pw, effectiveUid);
         pw.print(" mCallingUid="); UserHandle.formatUid(pw, mCallingUid);
         pw.print(" mUserSetupComplete="); pw.print(mUserSetupComplete);
-        pw.print(" mCallingPackage="); pw.println(mCallingPackage);
+        pw.print(" mCallingPackage="); pw.print(mCallingPackage);
         pw.print(" mCallingFeatureId="); pw.println(mCallingFeatureId);
         if (affinity != null || rootAffinity != null) {
             pw.print(prefix); pw.print("affinity="); pw.print(affinity);
@@ -3979,4 +4012,17 @@
         mAtmService.mTaskOrganizerController.dispatchTaskInfoChanged(
                 this, true /* force */);
     }
+
+    /**
+     * See {@link WindowContainerTransaction#setBoundsChangeTransaction}. In short this
+     * transaction will be consumed by the next BASE_APPLICATION window within our hierarchy
+     * to resize, and it will defer the transaction until that resize frame completes.
+     */
+    void setMainWindowSizeChangeTransaction(SurfaceControl.Transaction t) {
+        mMainWindowSizeChangeTransaction = t;
+    }
+
+    SurfaceControl.Transaction getMainWindowSizeChangeTransaction() {
+        return mMainWindowSizeChangeTransaction;
+    }
 }
diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java
index 4d5621c..6caa27c 100644
--- a/services/core/java/com/android/server/wm/TaskOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java
@@ -547,8 +547,7 @@
             final ActivityStack stack = (ActivityStack) container;
             if (stack.inPinnedWindowingMode()) {
                 stack.resize(config.windowConfiguration.getBounds(),
-                        null /* tempTaskBounds */, null /* tempTaskInsetBounds */,
-                        PRESERVE_WINDOWS, true /* deferResume */);
+                        null /* configBounds */, PRESERVE_WINDOWS, true /* deferResume */);
             }
         }
     }
@@ -557,6 +556,12 @@
             WindowContainerTransaction.Change c) {
         int effects = sanitizeAndApplyChange(wc, c);
 
+        final SurfaceControl.Transaction t = c.getBoundsChangeTransaction();
+        if (t != null) {
+            Task tr = (Task) wc;
+            tr.setMainWindowSizeChangeTransaction(t);
+        }
+
         Rect enterPipBounds = c.getEnterPipBounds();
         if (enterPipBounds != null) {
             Task tr = (Task) wc;
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index da996dc..7a4d0b0 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -615,7 +615,7 @@
     void positionChildAt(int position, E child, boolean includingParents) {
 
         if (child.getParent() != this) {
-            throw new IllegalArgumentException("removeChild: container=" + child.getName()
+            throw new IllegalArgumentException("positionChildAt: container=" + child.getName()
                     + " is not a child of container=" + getName()
                     + " current parent=" + child.getParent());
         }
@@ -1459,15 +1459,15 @@
         }
     }
 
-    void forAllTasks(Consumer<Task> callback, boolean traverseTopToBottom, Task excludedTask) {
+    void forAllLeafTasks(Consumer<Task> callback, boolean traverseTopToBottom) {
         final int count = mChildren.size();
         if (traverseTopToBottom) {
             for (int i = count - 1; i >= 0; --i) {
-                mChildren.get(i).forAllTasks(callback, traverseTopToBottom, excludedTask);
+                mChildren.get(i).forAllLeafTasks(callback, traverseTopToBottom);
             }
         } else {
             for (int i = 0; i < count; i++) {
-                mChildren.get(i).forAllTasks(callback, traverseTopToBottom, excludedTask);
+                mChildren.get(i).forAllLeafTasks(callback, traverseTopToBottom);
             }
         }
     }
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 9552df7..a1a9af6 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -873,6 +873,14 @@
             clipRect = mTmpClipRect;
         }
 
+        if (mSurfaceResized && (mAttrType == TYPE_BASE_APPLICATION) &&
+            (task != null) && (task.getMainWindowSizeChangeTransaction() != null)) {
+            mSurfaceController.deferTransactionUntil(mWin.getDeferTransactionBarrier(),
+                    mWin.getFrameNumber());
+            SurfaceControl.mergeToGlobalTransaction(task.getMainWindowSizeChangeTransaction());
+            task.setMainWindowSizeChangeTransaction(null);
+        }
+
         float surfaceWidth = mSurfaceController.getWidth();
         float surfaceHeight = mSurfaceController.getHeight();
 
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index 36ed9a5..336934e 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -166,7 +166,10 @@
 using MeasurementCorrections_V1_0 = android::hardware::gnss::measurement_corrections::V1_0::MeasurementCorrections;
 using MeasurementCorrections_V1_1 = android::hardware::gnss::measurement_corrections::V1_1::MeasurementCorrections;
 
-using android::hardware::gnss::measurement_corrections::V1_0::SingleSatCorrection;
+using SingleSatCorrection_V1_0 =
+        android::hardware::gnss::measurement_corrections::V1_0::SingleSatCorrection;
+using SingleSatCorrection_V1_1 =
+        android::hardware::gnss::measurement_corrections::V1_1::SingleSatCorrection;
 using android::hardware::gnss::measurement_corrections::V1_0::ReflectingPlane;
 
 using android::hidl::base::V1_0::IBase;
@@ -3124,6 +3127,91 @@
     return JNI_FALSE;
 }
 
+static SingleSatCorrection_V1_0 getSingleSatCorrection_1_0_withoutConstellation(
+        JNIEnv* env, jobject singleSatCorrectionObj) {
+    jint correctionFlags = env->CallIntMethod(singleSatCorrectionObj, method_correctionSatFlags);
+    jint satId = env->CallIntMethod(singleSatCorrectionObj, method_correctionSatId);
+    jfloat carrierFreqHz =
+            env->CallFloatMethod(singleSatCorrectionObj, method_correctionSatCarrierFreq);
+    jfloat probSatIsLos =
+            env->CallFloatMethod(singleSatCorrectionObj, method_correctionSatIsLosProb);
+    jfloat eplMeters = env->CallFloatMethod(singleSatCorrectionObj, method_correctionSatEpl);
+    jfloat eplUncMeters = env->CallFloatMethod(singleSatCorrectionObj, method_correctionSatEplUnc);
+    uint16_t corrFlags = static_cast<uint16_t>(correctionFlags);
+    jobject reflectingPlaneObj;
+    bool has_ref_plane = (corrFlags & GnssSingleSatCorrectionFlags::HAS_REFLECTING_PLANE) != 0;
+    if (has_ref_plane) {
+        reflectingPlaneObj =
+                env->CallObjectMethod(singleSatCorrectionObj, method_correctionSatRefPlane);
+    }
+
+    ReflectingPlane reflectingPlane;
+    if (has_ref_plane) {
+        jdouble latitudeDegreesRefPlane =
+                env->CallDoubleMethod(reflectingPlaneObj, method_correctionPlaneLatDeg);
+        jdouble longitudeDegreesRefPlane =
+                env->CallDoubleMethod(reflectingPlaneObj, method_correctionPlaneLngDeg);
+        jdouble altitudeDegreesRefPlane =
+                env->CallDoubleMethod(reflectingPlaneObj, method_correctionPlaneAltDeg);
+        jdouble azimuthDegreeRefPlane =
+                env->CallDoubleMethod(reflectingPlaneObj, method_correctionPlaneAzimDeg);
+        reflectingPlane = {
+                .latitudeDegrees = latitudeDegreesRefPlane,
+                .longitudeDegrees = longitudeDegreesRefPlane,
+                .altitudeMeters = altitudeDegreesRefPlane,
+                .azimuthDegrees = azimuthDegreeRefPlane,
+        };
+    }
+
+    SingleSatCorrection_V1_0 singleSatCorrection = {
+            .singleSatCorrectionFlags = corrFlags,
+            .svid = static_cast<uint16_t>(satId),
+            .carrierFrequencyHz = carrierFreqHz,
+            .probSatIsLos = probSatIsLos,
+            .excessPathLengthMeters = eplMeters,
+            .excessPathLengthUncertaintyMeters = eplUncMeters,
+            .reflectingPlane = reflectingPlane,
+    };
+
+    return singleSatCorrection;
+}
+
+static void getSingleSatCorrectionList_1_1(JNIEnv* env, jobject singleSatCorrectionList,
+                                           hidl_vec<SingleSatCorrection_V1_1>& list) {
+    for (uint16_t i = 0; i < list.size(); ++i) {
+        jobject singleSatCorrectionObj =
+                env->CallObjectMethod(singleSatCorrectionList, method_correctionListGet, i);
+
+        SingleSatCorrection_V1_0 singleSatCorrection_1_0 =
+                getSingleSatCorrection_1_0_withoutConstellation(env, singleSatCorrectionObj);
+
+        jint constType = env->CallIntMethod(singleSatCorrectionObj, method_correctionSatConstType);
+
+        SingleSatCorrection_V1_1 singleSatCorrection_1_1 = {
+                .v1_0 = singleSatCorrection_1_0,
+                .constellation = static_cast<GnssConstellationType_V2_0>(constType),
+        };
+
+        list[i] = singleSatCorrection_1_1;
+    }
+}
+
+static void getSingleSatCorrectionList_1_0(JNIEnv* env, jobject singleSatCorrectionList,
+                                           hidl_vec<SingleSatCorrection_V1_0>& list) {
+    for (uint16_t i = 0; i < list.size(); ++i) {
+        jobject singleSatCorrectionObj =
+                env->CallObjectMethod(singleSatCorrectionList, method_correctionListGet, i);
+
+        SingleSatCorrection_V1_0 singleSatCorrection =
+                getSingleSatCorrection_1_0_withoutConstellation(env, singleSatCorrectionObj);
+
+        jint constType = env->CallIntMethod(singleSatCorrectionObj, method_correctionSatConstType);
+
+        singleSatCorrection.constellation = static_cast<GnssConstellationType_V1_0>(constType),
+
+        list[i] = singleSatCorrection;
+    }
+}
 static jboolean
     android_location_GnssMeasurementCorrectionsProvider_inject_gnss_measurement_corrections(
         JNIEnv* env,
@@ -3146,64 +3234,6 @@
         ALOGI("Empty correction list injected....Returning with no HAL injection");
         return JNI_TRUE;
     }
-    hidl_vec<SingleSatCorrection> list(len);
-
-    for (uint16_t i = 0; i < len; ++i) {
-        jobject singleSatCorrectionObj = env->CallObjectMethod(
-            singleSatCorrectionList, method_correctionListGet, i);
-
-        jint correctionFlags =
-            env->CallIntMethod(singleSatCorrectionObj, method_correctionSatFlags);
-        jint constType = env->CallIntMethod(singleSatCorrectionObj,
-            method_correctionSatConstType);
-        jint satId =
-            env->CallIntMethod(singleSatCorrectionObj, method_correctionSatId);
-        jfloat carrierFreqHz = env->CallFloatMethod(
-            singleSatCorrectionObj, method_correctionSatCarrierFreq);
-        jfloat probSatIsLos = env->CallFloatMethod(singleSatCorrectionObj,
-            method_correctionSatIsLosProb);
-        jfloat eplMeters =
-            env->CallFloatMethod(singleSatCorrectionObj, method_correctionSatEpl);
-        jfloat eplUncMeters = env->CallFloatMethod(singleSatCorrectionObj,
-            method_correctionSatEplUnc);
-        uint16_t corrFlags = static_cast<uint16_t>(correctionFlags);
-        jobject reflectingPlaneObj;
-        bool has_ref_plane = (corrFlags & GnssSingleSatCorrectionFlags::HAS_REFLECTING_PLANE) != 0;
-        if (has_ref_plane) {
-            reflectingPlaneObj = env->CallObjectMethod(
-                singleSatCorrectionObj, method_correctionSatRefPlane);
-        }
-
-        ReflectingPlane reflectingPlane;
-        if (has_ref_plane) {
-            jdouble latitudeDegreesRefPlane = env->CallDoubleMethod(
-                reflectingPlaneObj, method_correctionPlaneLatDeg);
-            jdouble longitudeDegreesRefPlane = env->CallDoubleMethod(
-                reflectingPlaneObj, method_correctionPlaneLngDeg);
-            jdouble altitudeDegreesRefPlane = env->CallDoubleMethod(
-                reflectingPlaneObj, method_correctionPlaneAltDeg);
-            jdouble azimuthDegreeRefPlane = env->CallDoubleMethod(
-                reflectingPlaneObj, method_correctionPlaneAzimDeg);
-            reflectingPlane = {
-                .latitudeDegrees = latitudeDegreesRefPlane,
-                .longitudeDegrees = longitudeDegreesRefPlane,
-                .altitudeMeters = altitudeDegreesRefPlane,
-                .azimuthDegrees = azimuthDegreeRefPlane,
-            };
-        }
-
-        SingleSatCorrection singleSatCorrection = {
-            .singleSatCorrectionFlags = corrFlags,
-            .constellation = static_cast<GnssConstellationType_V1_0>(constType),
-            .svid = static_cast<uint16_t>(satId),
-            .carrierFrequencyHz = carrierFreqHz,
-            .probSatIsLos = probSatIsLos,
-            .excessPathLengthMeters = eplMeters,
-            .excessPathLengthUncertaintyMeters = eplUncMeters,
-            .reflectingPlane = reflectingPlane,
-        };
-        list[i] = singleSatCorrection;
-    }
 
     jdouble latitudeDegreesCorr = env->CallDoubleMethod(
         correctionsObj, method_correctionsGetLatitudeDegrees);
@@ -3225,7 +3255,6 @@
         .horizontalPositionUncertaintyMeters = horizontalPositionUncertaintyMeters,
         .verticalPositionUncertaintyMeters = verticalPositionUncertaintyMeters,
         .toaGpsNanosecondsOfWeek = static_cast<uint64_t>(toaGpsNanosOfWeek),
-        .satCorrections = list,
     };
 
     if (gnssCorrectionsIface_V1_1 != nullptr) {
@@ -3237,17 +3266,25 @@
         jfloat environmentBearingUncertaintyDegreesCorr = env->CallFloatMethod(
             correctionsObj, method_correctionsGetEnvironmentBearingUncertaintyDegrees);
 
+        hidl_vec<SingleSatCorrection_V1_1> list(len);
+        getSingleSatCorrectionList_1_1(env, singleSatCorrectionList, list);
+
         MeasurementCorrections_V1_1 measurementCorrections_1_1 = {
-            .v1_0 = measurementCorrections_1_0,
-            .hasEnvironmentBearing = static_cast<bool>(hasEnvironmentBearingCorr),
-            .environmentBearingDegrees = environmentBearingDegreesCorr,
-            .environmentBearingUncertaintyDegrees = environmentBearingUncertaintyDegreesCorr,
+                .v1_0 = measurementCorrections_1_0,
+                .hasEnvironmentBearing = static_cast<bool>(hasEnvironmentBearingCorr),
+                .environmentBearingDegrees = environmentBearingDegreesCorr,
+                .environmentBearingUncertaintyDegrees = environmentBearingUncertaintyDegreesCorr,
+                .satCorrections = list,
         };
 
         auto result = gnssCorrectionsIface_V1_1->setCorrections_1_1(measurementCorrections_1_1);
         return checkHidlReturn(result, "IMeasurementCorrections 1.1 setCorrections() failed.");
     }
 
+    hidl_vec<SingleSatCorrection_V1_0> list(len);
+    getSingleSatCorrectionList_1_0(env, singleSatCorrectionList, list);
+    measurementCorrections_1_0.satCorrections = list;
+
     auto result = gnssCorrectionsIface_V1_0->setCorrections(measurementCorrections_1_0);
     return checkHidlReturn(result, "IMeasurementCorrections 1.0 setCorrections() failed.");
 }
diff --git a/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp b/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp
index 70a9c09..f445aa8 100644
--- a/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp
+++ b/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp
@@ -190,6 +190,7 @@
 }
 
 static inline int32_t skipIdSigHeaders(borrowed_fd fd) {
+    readBEInt32(fd);        // version
     readBytes(fd);          // verityRootHash
     readBytes(fd);          // v3Digest
     readBytes(fd);          // pkcs7SignatureBlock
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index b239b684..46d8800 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -180,14 +180,12 @@
 import android.content.pm.ServiceInfo;
 import android.content.pm.StringParceledListSlice;
 import android.content.pm.UserInfo;
-import android.content.pm.parsing.AndroidPackage;
 import android.content.res.Resources;
 import android.database.ContentObserver;
 import android.database.Cursor;
 import android.graphics.Bitmap;
 import android.graphics.Color;
 import android.location.LocationManager;
-import android.location.LocationManagerInternal;
 import android.media.AudioManager;
 import android.media.IAudioService;
 import android.net.ConnectivityManager;
@@ -290,6 +288,7 @@
 import com.android.server.inputmethod.InputMethodManagerInternal;
 import com.android.server.net.NetworkPolicyManagerInternal;
 import com.android.server.pm.UserRestrictionsUtils;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.storage.DeviceStorageMonitorInternal;
 import com.android.server.uri.UriGrantsManagerInternal;
 import com.android.server.wm.ActivityTaskManagerInternal;
@@ -445,10 +444,13 @@
     });
 
     /**
-     *  System property whose value is either "true" or "false", indicating whether
-     *  device owner is present.
+     * System property whose value indicates whether the device is fully owned by an organization:
+     * it can be either a device owner device, or a device with an organization-owned managed
+     * profile.
+     *
+     * <p>The state is stored as a Boolean string.
      */
-    private static final String PROPERTY_DEVICE_OWNER_PRESENT = "ro.device_owner";
+    private static final String PROPERTY_ORGANIZATION_OWNED = "ro.organization_owned";
 
     private static final int STATUS_BAR_DISABLE_MASK =
             StatusBarManager.DISABLE_EXPAND |
@@ -481,6 +483,7 @@
 
         GLOBAL_SETTINGS_WHITELIST = new ArraySet<>();
         GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.ADB_ENABLED);
+        GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.ADB_WIFI_ENABLED);
         GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.AUTO_TIME);
         GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.AUTO_TIME_ZONE);
         GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.DATA_ROAMING);
@@ -1073,7 +1076,8 @@
         private static final String TAG_SUSPEND_PERSONAL_APPS = "suspend-personal-apps";
         private static final String TAG_PROFILE_MAXIMUM_TIME_OFF = "profile-max-time-off";
         private static final String TAG_PROFILE_OFF_DEADLINE = "profile-off-deadline";
-
+        private static final String TAG_ALWAYS_ON_VPN_PACKAGE = "vpn-package";
+        private static final String TAG_ALWAYS_ON_VPN_LOCKDOWN = "vpn-lockdown";
         DeviceAdminInfo info;
 
 
@@ -1202,6 +1206,9 @@
         // Time by which the profile should be turned on according to System.currentTimeMillis().
         long mProfileOffDeadline = 0;
 
+        public String mAlwaysOnVpnPackage;
+        public boolean mAlwaysOnVpnLockdown;
+
 
         ActiveAdmin(DeviceAdminInfo _info, boolean parent) {
             info = _info;
@@ -1442,6 +1449,12 @@
             if (mProfileMaximumTimeOff != 0) {
                 writeAttributeValueToXml(out, TAG_PROFILE_OFF_DEADLINE, mProfileOffDeadline);
             }
+            if (!TextUtils.isEmpty(mAlwaysOnVpnPackage)) {
+                writeAttributeValueToXml(out, TAG_ALWAYS_ON_VPN_PACKAGE, mAlwaysOnVpnPackage);
+            }
+            if (mAlwaysOnVpnLockdown) {
+                writeAttributeValueToXml(out, TAG_ALWAYS_ON_VPN_LOCKDOWN, mAlwaysOnVpnLockdown);
+            }
         }
 
         void writeTextToXml(XmlSerializer out, String tag, String text) throws IOException {
@@ -1687,6 +1700,11 @@
                 } else if (TAG_PROFILE_OFF_DEADLINE.equals(tag)) {
                     mProfileOffDeadline =
                             Long.parseLong(parser.getAttributeValue(null, ATTR_VALUE));
+                } else if (TAG_ALWAYS_ON_VPN_PACKAGE.equals(tag)) {
+                    mAlwaysOnVpnPackage = parser.getAttributeValue(null, ATTR_VALUE);
+                } else if (TAG_ALWAYS_ON_VPN_LOCKDOWN.equals(tag)) {
+                    mAlwaysOnVpnLockdown = Boolean.parseBoolean(
+                            parser.getAttributeValue(null, ATTR_VALUE));
                 } else {
                     Slog.w(LOG_TAG, "Unknown admin tag: " + tag);
                     XmlUtils.skipCurrentTag(parser);
@@ -1919,6 +1937,10 @@
                 pw.println(mProfileMaximumTimeOff);
             pw.print("mProfileOffDeadline=");
                 pw.println(mProfileOffDeadline);
+            pw.print("mAlwaysOnVpnPackage=");
+            pw.println(mAlwaysOnVpnPackage);
+            pw.print("mAlwaysOnVpnLockdown=");
+            pw.println(mAlwaysOnVpnLockdown);
         }
     }
 
@@ -2112,10 +2134,6 @@
             return mContext.getSystemService(LocationManager.class);
         }
 
-        LocationManagerInternal getLocationManagerInternal() {
-            return LocalServices.getService(LocationManagerInternal.class);
-        }
-
         IWindowManager getIWindowManager() {
             return IWindowManager.Stub
                     .asInterface(ServiceManager.getService(Context.WINDOW_SERVICE));
@@ -2536,7 +2554,7 @@
     void loadOwners() {
         synchronized (getLockObject()) {
             mOwners.load();
-            setDeviceOwnerSystemPropertyLocked();
+            setDeviceOwnershipSystemPropertyLocked();
             findOwnerComponentIfNecessaryLocked();
             migrateUserRestrictionsIfNecessaryLocked();
 
@@ -2738,34 +2756,36 @@
         }
     }
 
-    private void setDeviceOwnerSystemPropertyLocked() {
-        final boolean deviceProvisioned =
-                mInjector.settingsGlobalGetInt(Settings.Global.DEVICE_PROVISIONED, 0) != 0;
-        final boolean hasDeviceOwner = mOwners.hasDeviceOwner();
-        // If the device is not provisioned and there is currently no device owner, do not set the
-        // read-only system property yet, since Device owner may still be provisioned.
-        if (!hasDeviceOwner && !deviceProvisioned) {
-            return;
-        }
-        // Still at the first stage of CryptKeeper double bounce, mOwners.hasDeviceOwner is
-        // always false at this point.
+    private void setDeviceOwnershipSystemPropertyLocked() {
+        // Still at the first stage of CryptKeeper double bounce, nothing can be learnt about
+        // the real system at this point.
         if (StorageManager.inCryptKeeperBounce()) {
             return;
         }
-
-        if (!mInjector.systemPropertiesGet(PROPERTY_DEVICE_OWNER_PRESENT, "").isEmpty()) {
-            Slog.w(LOG_TAG, "Trying to set ro.device_owner, but it has already been set?");
-        } else {
-            final String value = Boolean.toString(hasDeviceOwner);
-            mInjector.systemPropertiesSet(PROPERTY_DEVICE_OWNER_PRESENT, value);
-            Slog.i(LOG_TAG, "Set ro.device_owner property to " + value);
+        final boolean deviceProvisioned =
+                mInjector.settingsGlobalGetInt(Settings.Global.DEVICE_PROVISIONED, 0) != 0;
+        final boolean hasDeviceOwner = mOwners.hasDeviceOwner();
+        final boolean hasOrgOwnedProfile = isOrganizationOwnedDeviceWithManagedProfile();
+        // If the device is not provisioned and there is currently no management, do not set the
+        // read-only system property yet, since device owner / org-owned profile may still be
+        // provisioned.
+        if (!hasDeviceOwner && !hasOrgOwnedProfile && !deviceProvisioned) {
+            return;
+        }
+        final String value = Boolean.toString(hasDeviceOwner || hasOrgOwnedProfile);
+        final String currentVal = mInjector.systemPropertiesGet(PROPERTY_ORGANIZATION_OWNED, null);
+        if (TextUtils.isEmpty(currentVal)) {
+            Slog.i(LOG_TAG, "Set ro.organization_owned property to " + value);
+            mInjector.systemPropertiesSet(PROPERTY_ORGANIZATION_OWNED, value);
+        } else if (!value.equals(currentVal)) {
+            Slog.w(LOG_TAG, "Cannot change existing ro.organization_owned to " + value);
         }
     }
 
     private void maybeStartSecurityLogMonitorOnActivityManagerReady() {
         synchronized (getLockObject()) {
             if (mInjector.securityLogIsLoggingEnabled()) {
-                mSecurityLogMonitor.start();
+                mSecurityLogMonitor.start(getSecurityLoggingEnabledUser());
                 mInjector.runCryptoSelfTest();
                 maybePauseDeviceWideLoggingLocked();
             }
@@ -6781,10 +6801,10 @@
      * @throws UnsupportedOperationException if the package does not support being set as always-on.
      */
     @Override
-    public boolean setAlwaysOnVpnPackage(ComponentName admin, String vpnPackage, boolean lockdown,
+    public boolean setAlwaysOnVpnPackage(ComponentName who, String vpnPackage, boolean lockdown,
             List<String> lockdownWhitelist)
             throws SecurityException {
-        enforceProfileOrDeviceOwner(admin);
+        enforceProfileOrDeviceOwner(who);
 
         final int userId = mInjector.userHandleGetCallingUserId();
         mInjector.binderWithCleanCallingIdentity(() -> {
@@ -6810,12 +6830,22 @@
             }
             DevicePolicyEventLogger
                     .createEvent(DevicePolicyEnums.SET_ALWAYS_ON_VPN_PACKAGE)
-                    .setAdmin(admin)
+                    .setAdmin(who)
                     .setStrings(vpnPackage)
                     .setBoolean(lockdown)
                     .setInt(lockdownWhitelist != null ? lockdownWhitelist.size() : 0)
                     .write();
         });
+        synchronized (getLockObject()) {
+            ActiveAdmin admin = getActiveAdminForCallerLocked(who,
+                    DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+            if (!TextUtils.equals(vpnPackage, admin.mAlwaysOnVpnPackage)
+                    || lockdown != admin.mAlwaysOnVpnLockdown) {
+                admin.mAlwaysOnVpnPackage = vpnPackage;
+                admin.mAlwaysOnVpnLockdown = lockdown;
+                saveSettingsLocked(userId);
+            }
+        }
         return true;
     }
 
@@ -6829,6 +6859,15 @@
     }
 
     @Override
+    public String getAlwaysOnVpnPackageForUser(int userHandle) {
+        enforceSystemCaller("getAlwaysOnVpnPackageForUser");
+        synchronized (getLockObject()) {
+            ActiveAdmin admin = getDeviceOrProfileOwnerAdminLocked(userHandle);
+            return admin != null ? admin.mAlwaysOnVpnPackage : null;
+        }
+    }
+
+    @Override
     public boolean isAlwaysOnVpnLockdownEnabled(ComponentName admin) throws SecurityException {
         enforceProfileOrDeviceOwner(admin);
 
@@ -6838,6 +6877,15 @@
     }
 
     @Override
+    public boolean isAlwaysOnVpnLockdownEnabledForUser(int userHandle) {
+        enforceSystemCaller("isAlwaysOnVpnLockdownEnabledForUser");
+        synchronized (getLockObject()) {
+            ActiveAdmin admin = getDeviceOrProfileOwnerAdminLocked(userHandle);
+            return admin != null ? admin.mAlwaysOnVpnLockdown : null;
+        }
+    }
+
+    @Override
     public List<String> getAlwaysOnVpnLockdownWhitelist(ComponentName admin)
             throws SecurityException {
         enforceProfileOrDeviceOwner(admin);
@@ -8349,7 +8397,7 @@
             mOwners.setDeviceOwner(admin, ownerName, userId);
             mOwners.writeDeviceOwner();
             updateDeviceOwnerLocked();
-            setDeviceOwnerSystemPropertyLocked();
+            setDeviceOwnershipSystemPropertyLocked();
 
             mInjector.binderWithCleanCallingIdentity(() -> {
                 // Restrict adding a managed profile when a device owner is set on the device.
@@ -8987,6 +9035,19 @@
         return null;
     }
 
+    /**
+     * Returns the ActiveAdmin associated wit the PO or DO on the given user.
+     * @param userHandle
+     * @return
+     */
+    private @Nullable ActiveAdmin getDeviceOrProfileOwnerAdminLocked(int userHandle) {
+        ActiveAdmin admin = getProfileOwnerAdminLocked(userHandle);
+        if (admin == null && getDeviceOwnerUserId() == userHandle) {
+            admin = getDeviceOwnerAdminLocked();
+        }
+        return admin;
+    }
+
     @GuardedBy("getLockObject()")
     ActiveAdmin getProfileOwnerOfOrganizationOwnedDeviceLocked(int userHandle) {
         return mInjector.binderWithCleanCallingIdentity(() -> {
@@ -9016,21 +9077,21 @@
         return getApplicationLabel(profileOwner.getPackageName(), userHandle);
     }
 
+    private @UserIdInt int getOrganizationOwnedProfileUserId() {
+        for (UserInfo ui : mUserManagerInternal.getUserInfos()) {
+            if (ui.isManagedProfile() && isProfileOwnerOfOrganizationOwnedDevice(ui.id)) {
+                return ui.id;
+            }
+        }
+        return UserHandle.USER_NULL;
+    }
+
     @Override
     public boolean isOrganizationOwnedDeviceWithManagedProfile() {
         if (!mHasFeature) {
             return false;
         }
-
-        return mInjector.binderWithCleanCallingIdentity(() -> {
-            for (UserInfo ui : mUserManager.getUsers()) {
-                if (ui.isManagedProfile() && isProfileOwnerOfOrganizationOwnedDevice(ui.id)) {
-                    return true;
-                }
-            }
-
-            return false;
-        });
+        return getOrganizationOwnedProfileUserId() != UserHandle.USER_NULL;
     }
 
     @Override
@@ -11643,17 +11704,6 @@
     }
 
     @Override
-    public void requestSetLocationProviderAllowed(ComponentName who, String provider,
-            boolean providerAllowed) {
-        Objects.requireNonNull(who, "ComponentName is null");
-        enforceDeviceOwner(who);
-
-        mInjector.binderWithCleanCallingIdentity(
-                () -> mInjector.getLocationManagerInternal().requestSetProviderAllowed(provider,
-                        providerAllowed));
-    }
-
-    @Override
     public boolean setTime(ComponentName who, long millis) {
         Objects.requireNonNull(who, "ComponentName is null in setTime");
         enforceDeviceOwnerOrProfileOwnerOnOrganizationOwnedDevice(who);
@@ -12002,7 +12052,7 @@
                 synchronized (getLockObject()) {
                     // Set PROPERTY_DEVICE_OWNER_PRESENT, for the SUW case where setting the property
                     // is delayed until device is marked as provisioned.
-                    setDeviceOwnerSystemPropertyLocked();
+                    setDeviceOwnershipSystemPropertyLocked();
                 }
             } else if (mDefaultImeChanged.equals(uri)) {
                 synchronized (getLockObject()) {
@@ -13627,6 +13677,22 @@
         });
     }
 
+    private boolean canStartSecurityLogging() {
+        synchronized (getLockObject()) {
+            return isOrganizationOwnedDeviceWithManagedProfile()
+                    || areAllUsersAffiliatedWithDeviceLocked();
+        }
+    }
+
+    private @UserIdInt int getSecurityLoggingEnabledUser() {
+        synchronized (getLockObject()) {
+            if (mOwners.hasDeviceOwner()) {
+                return UserHandle.USER_ALL;
+            }
+        }
+        return getOrganizationOwnedProfileUserId();
+    }
+
     @Override
     public void setSecurityLoggingEnabled(ComponentName admin, boolean enabled) {
         if (!mHasFeature) {
@@ -13635,13 +13701,14 @@
         Objects.requireNonNull(admin);
 
         synchronized (getLockObject()) {
-            getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
+            getActiveAdminForCallerLocked(admin,
+                    DeviceAdminInfo.USES_POLICY_ORGANIZATION_OWNED_PROFILE_OWNER);
             if (enabled == mInjector.securityLogGetLoggingEnabledProperty()) {
                 return;
             }
             mInjector.securityLogSetLoggingEnabledProperty(enabled);
             if (enabled) {
-                mSecurityLogMonitor.start();
+                mSecurityLogMonitor.start(getSecurityLoggingEnabledUser());
                 maybePauseDeviceWideLoggingLocked();
             } else {
                 mSecurityLogMonitor.stop();
@@ -13663,7 +13730,8 @@
         synchronized (getLockObject()) {
             if (!isCallerWithSystemUid()) {
                 Objects.requireNonNull(admin);
-                getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
+                getActiveAdminForCallerLocked(admin,
+                        DeviceAdminInfo.USES_POLICY_ORGANIZATION_OWNED_PROFILE_OWNER);
             }
             return mInjector.securityLogGetLoggingEnabledProperty();
         }
@@ -13687,7 +13755,10 @@
         }
 
         Objects.requireNonNull(admin);
-        ensureDeviceOwnerAndAllUsersAffiliated(admin);
+        enforceDeviceOwnerOrProfileOwnerOnOrganizationOwnedDevice(admin);
+        if (!isOrganizationOwnedDeviceWithManagedProfile()) {
+            ensureAllUsersAffiliated();
+        }
 
         DevicePolicyEventLogger
                 .createEvent(DevicePolicyEnums.RETRIEVE_PRE_REBOOT_SECURITY_LOGS)
@@ -13703,6 +13774,10 @@
         ArrayList<SecurityEvent> output = new ArrayList<SecurityEvent>();
         try {
             SecurityLog.readPreviousEvents(output);
+            int enabledUser = getSecurityLoggingEnabledUser();
+            if (enabledUser != UserHandle.USER_ALL) {
+                SecurityLog.redactEvents(output, enabledUser);
+            }
             return new ParceledListSlice<SecurityEvent>(output);
         } catch (IOException e) {
             Slog.w(LOG_TAG, "Fail to read previous events" , e);
@@ -13717,7 +13792,10 @@
         }
 
         Objects.requireNonNull(admin);
-        ensureDeviceOwnerAndAllUsersAffiliated(admin);
+        enforceDeviceOwnerOrProfileOwnerOnOrganizationOwnedDevice(admin);
+        if (!isOrganizationOwnedDeviceWithManagedProfile()) {
+            ensureAllUsersAffiliated();
+        }
 
         if (!mInjector.securityLogGetLoggingEnabledProperty()) {
             return null;
@@ -14243,26 +14321,34 @@
     @GuardedBy("getLockObject()")
     private void maybePauseDeviceWideLoggingLocked() {
         if (!areAllUsersAffiliatedWithDeviceLocked()) {
-            Slog.i(LOG_TAG, "There are unaffiliated users, security and network logging will be "
+            Slog.i(LOG_TAG, "There are unaffiliated users, network logging will be "
                     + "paused if enabled.");
-            mSecurityLogMonitor.pause();
             if (mNetworkLogger != null) {
                 mNetworkLogger.pause();
             }
+            if (!isOrganizationOwnedDeviceWithManagedProfile()) {
+                Slog.i(LOG_TAG, "Not org-owned managed profile device, security logging will be "
+                        + "paused if enabled.");
+                mSecurityLogMonitor.pause();
+            }
         }
     }
 
     /** Resumes security and network logging (if they are enabled) if all users are affiliated */
     @GuardedBy("getLockObject()")
     private void maybeResumeDeviceWideLoggingLocked() {
-        if (areAllUsersAffiliatedWithDeviceLocked()) {
-            mInjector.binderWithCleanCallingIdentity(() -> {
+        boolean allUsersAffiliated = areAllUsersAffiliatedWithDeviceLocked();
+        boolean orgOwnedProfileDevice = isOrganizationOwnedDeviceWithManagedProfile();
+        mInjector.binderWithCleanCallingIdentity(() -> {
+            if (allUsersAffiliated || orgOwnedProfileDevice) {
                 mSecurityLogMonitor.resume();
+            }
+            if (allUsersAffiliated) {
                 if (mNetworkLogger != null) {
                     mNetworkLogger.resume();
                 }
-            });
-        }
+            }
+        });
     }
 
     /** Deletes any security and network logs that might have been collected so far */
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/SecurityLogMonitor.java b/services/devicepolicy/java/com/android/server/devicepolicy/SecurityLogMonitor.java
index 1ab3b98..3c445ca 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/SecurityLogMonitor.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/SecurityLogMonitor.java
@@ -51,15 +51,17 @@
 
     private final Lock mLock = new ReentrantLock();
 
+    private int mEnabledUser;
+
     SecurityLogMonitor(DevicePolicyManagerService service) {
         this(service, 0 /* id */);
     }
 
     @VisibleForTesting
     SecurityLogMonitor(DevicePolicyManagerService service, long id) {
-        this.mService = service;
-        this.mId = id;
-        this.mLastForceNanos = System.nanoTime();
+        mService = service;
+        mId = id;
+        mLastForceNanos = System.nanoTime();
     }
 
     private static final boolean DEBUG = false;  // STOPSHIP if true.
@@ -136,8 +138,15 @@
     @GuardedBy("mForceSemaphore")
     private long mLastForceNanos = 0;
 
-    void start() {
-        Slog.i(TAG, "Starting security logging.");
+    /**
+     * Start security logging.
+     *
+     * @param enabledUser which user logging is enabled on, or USER_ALL to enable logging for all
+     *     users on the device.
+     */
+    void start(int enabledUser) {
+        Slog.i(TAG, "Starting security logging for user " + enabledUser);
+        mEnabledUser = enabledUser;
         SecurityLog.writeEvent(SecurityLog.TAG_LOGGING_STARTED);
         mLock.lock();
         try {
@@ -286,7 +295,7 @@
                 break;
             }
         }
-
+        SecurityLog.redactEvents(newLogs, mEnabledUser);
         if (DEBUG) Slog.d(TAG, "Got " + newLogs.size() + " new events.");
     }
 
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 569986c..b5d3d18 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -44,7 +44,6 @@
 import android.graphics.GraphicsStatsService;
 import android.hardware.display.DisplayManagerInternal;
 import android.net.ConnectivityModuleConnector;
-import android.net.ITetheringConnector;
 import android.net.NetworkStackClient;
 import android.os.BaseBundle;
 import android.os.Binder;
@@ -298,6 +297,9 @@
             "com.android.server.blob.BlobStoreManagerService";
     private static final String APP_SEARCH_MANAGER_SERVICE_CLASS =
             "com.android.server.appsearch.AppSearchManagerService";
+
+    private static final String TETHERING_CONNECTOR_CLASS = "android.net.ITetheringConnector";
+
     private static final String PERSISTENT_DATA_BLOCK_PROP = "ro.frp.pst";
 
     private static final String UNCRYPT_PACKAGE_FILE = "/cache/recovery/uncrypt_file";
@@ -2331,7 +2333,7 @@
             try {
                 // TODO: hide implementation details, b/146312721.
                 ConnectivityModuleConnector.getInstance().startModuleService(
-                        ITetheringConnector.class.getName(),
+                        TETHERING_CONNECTOR_CLASS,
                         PERMISSION_MAINLINE_NETWORK_STACK, service -> {
                             ServiceManager.addService(Context.TETHERING_SERVICE, service,
                                     false /* allowIsolated */,
diff --git a/services/people/java/com/android/server/people/data/AbstractProtoDiskReadWriter.java b/services/people/java/com/android/server/people/data/AbstractProtoDiskReadWriter.java
index 203e980..7672cd0 100644
--- a/services/people/java/com/android/server/people/data/AbstractProtoDiskReadWriter.java
+++ b/services/people/java/com/android/server/people/data/AbstractProtoDiskReadWriter.java
@@ -51,15 +51,18 @@
 abstract class AbstractProtoDiskReadWriter<T> {
 
     private static final String TAG = AbstractProtoDiskReadWriter.class.getSimpleName();
+
+    // Common disk write delay that will be appropriate for most scenarios.
+    private static final long DEFAULT_DISK_WRITE_DELAY = 2L * DateUtils.MINUTE_IN_MILLIS;
     private static final long SHUTDOWN_DISK_WRITE_TIMEOUT = 5L * DateUtils.SECOND_IN_MILLIS;
 
     private final File mRootDir;
     private final ScheduledExecutorService mScheduledExecutorService;
-    private final long mWriteDelayMs;
 
     @GuardedBy("this")
     private ScheduledFuture<?> mScheduledFuture;
 
+    // File name -> data class
     @GuardedBy("this")
     private Map<String, T> mScheduledFileDataMap = new ArrayMap<>();
 
@@ -75,15 +78,15 @@
      */
     abstract ProtoStreamReader<T> protoStreamReader();
 
-    AbstractProtoDiskReadWriter(@NonNull File rootDir, long writeDelayMs,
+    AbstractProtoDiskReadWriter(@NonNull File rootDir,
             @NonNull ScheduledExecutorService scheduledExecutorService) {
         mRootDir = rootDir;
-        mWriteDelayMs = writeDelayMs;
         mScheduledExecutorService = scheduledExecutorService;
     }
 
     @WorkerThread
-    void delete(@NonNull String fileName) {
+    synchronized void delete(@NonNull String fileName) {
+        mScheduledFileDataMap.remove(fileName);
         final File file = getFile(fileName);
         if (!file.exists()) {
             return;
@@ -174,7 +177,7 @@
         }
 
         mScheduledFuture = mScheduledExecutorService.schedule(this::flushScheduledData,
-                mWriteDelayMs, TimeUnit.MILLISECONDS);
+                DEFAULT_DISK_WRITE_DELAY, TimeUnit.MILLISECONDS);
     }
 
     /**
@@ -183,7 +186,13 @@
      */
     @MainThread
     synchronized void saveImmediately(@NonNull String fileName, @NonNull T data) {
-        if (mScheduledExecutorService.isShutdown()) {
+        mScheduledFileDataMap.put(fileName, data);
+        triggerScheduledFlushEarly();
+    }
+
+    @MainThread
+    private synchronized void triggerScheduledFlushEarly() {
+        if (mScheduledFileDataMap.isEmpty() || mScheduledExecutorService.isShutdown()) {
             return;
         }
         // Cancel existing future.
@@ -194,7 +203,6 @@
             mScheduledFuture.cancel(true);
         }
 
-        mScheduledFileDataMap.put(fileName, data);
         // Submit flush and blocks until it completes. Blocking will prevent the device from
         // shutting down before flushing completes.
         Future<?> future = mScheduledExecutorService.submit(this::flushScheduledData);
@@ -212,9 +220,10 @@
             return;
         }
         for (String fileName : mScheduledFileDataMap.keySet()) {
-            T data = mScheduledFileDataMap.remove(fileName);
+            T data = mScheduledFileDataMap.get(fileName);
             writeTo(fileName, data);
         }
+        mScheduledFileDataMap.clear();
         mScheduledFuture = null;
     }
 
diff --git a/services/people/java/com/android/server/people/data/ConversationInfo.java b/services/people/java/com/android/server/people/data/ConversationInfo.java
index 859cdf2..41bc361 100644
--- a/services/people/java/com/android/server/people/data/ConversationInfo.java
+++ b/services/people/java/com/android/server/people/data/ConversationInfo.java
@@ -274,6 +274,10 @@
         }
         protoOutputStream.write(ConversationInfoProto.SHORTCUT_FLAGS, mShortcutFlags);
         protoOutputStream.write(ConversationInfoProto.CONVERSATION_FLAGS, mConversationFlags);
+        if (mContactPhoneNumber != null) {
+            protoOutputStream.write(ConversationInfoProto.CONTACT_PHONE_NUMBER,
+                    mContactPhoneNumber);
+        }
     }
 
     /** Reads from {@link ProtoInputStream} and constructs a {@link ConversationInfo}. */
@@ -315,6 +319,10 @@
                     builder.setConversationFlags(protoInputStream.readInt(
                             ConversationInfoProto.CONVERSATION_FLAGS));
                     break;
+                case (int) ConversationInfoProto.CONTACT_PHONE_NUMBER:
+                    builder.setContactPhoneNumber(protoInputStream.readString(
+                            ConversationInfoProto.CONTACT_PHONE_NUMBER));
+                    break;
                 default:
                     Slog.w(TAG, "Could not read undefined field: "
                             + protoInputStream.getFieldNumber());
diff --git a/services/people/java/com/android/server/people/data/ConversationStore.java b/services/people/java/com/android/server/people/data/ConversationStore.java
index 3afb209..89c4972 100644
--- a/services/people/java/com/android/server/people/data/ConversationStore.java
+++ b/services/people/java/com/android/server/people/data/ConversationStore.java
@@ -22,8 +22,6 @@
 import android.annotation.WorkerThread;
 import android.content.LocusId;
 import android.net.Uri;
-import android.text.TextUtils;
-import android.text.format.DateUtils;
 import android.util.ArrayMap;
 import android.util.Slog;
 import android.util.proto.ProtoInputStream;
@@ -50,8 +48,6 @@
 
     private static final String CONVERSATIONS_FILE_NAME = "conversations";
 
-    private static final long DISK_WRITE_DELAY = 2L * DateUtils.MINUTE_IN_MILLIS;
-
     // Shortcut ID -> Conversation Info
     @GuardedBy("this")
     private final Map<String, ConversationInfo> mConversationInfoMap = new ArrayMap<>();
@@ -74,16 +70,13 @@
 
     private final ScheduledExecutorService mScheduledExecutorService;
     private final File mPackageDir;
-    private final ContactsQueryHelper mHelper;
 
     private ConversationInfosProtoDiskReadWriter mConversationInfosProtoDiskReadWriter;
 
     ConversationStore(@NonNull File packageDir,
-            @NonNull ScheduledExecutorService scheduledExecutorService,
-            @NonNull ContactsQueryHelper helper) {
+            @NonNull ScheduledExecutorService scheduledExecutorService) {
         mScheduledExecutorService = scheduledExecutorService;
         mPackageDir = packageDir;
-        mHelper = helper;
     }
 
     /**
@@ -92,7 +85,7 @@
      */
     @MainThread
     void loadConversationsFromDisk() {
-        mScheduledExecutorService.submit(() -> {
+        mScheduledExecutorService.execute(() -> {
             synchronized (this) {
                 ConversationInfosProtoDiskReadWriter conversationInfosProtoDiskReadWriter =
                         getConversationInfosProtoDiskReadWriter();
@@ -105,7 +98,6 @@
                     return;
                 }
                 for (ConversationInfo conversationInfo : conversationsOnDisk) {
-                    conversationInfo = restoreConversationPhoneNumber(conversationInfo);
                     updateConversationsInMemory(conversationInfo);
                 }
             }
@@ -194,6 +186,15 @@
         return getConversation(mNotifChannelIdToShortcutIdMap.get(notifChannelId));
     }
 
+    synchronized void onDestroy() {
+        mConversationInfoMap.clear();
+        mContactUriToShortcutIdMap.clear();
+        mLocusIdToShortcutIdMap.clear();
+        mNotifChannelIdToShortcutIdMap.clear();
+        mPhoneNumberToShortcutIdMap.clear();
+        mConversationInfosProtoDiskReadWriter.deleteConversationsFile();
+    }
+
     @MainThread
     private synchronized void updateConversationsInMemory(
             @NonNull ConversationInfo conversationInfo) {
@@ -239,41 +240,21 @@
         }
         if (mConversationInfosProtoDiskReadWriter == null) {
             mConversationInfosProtoDiskReadWriter = new ConversationInfosProtoDiskReadWriter(
-                    mPackageDir, CONVERSATIONS_FILE_NAME, DISK_WRITE_DELAY,
-                    mScheduledExecutorService);
+                    mPackageDir, CONVERSATIONS_FILE_NAME, mScheduledExecutorService);
         }
         return mConversationInfosProtoDiskReadWriter;
     }
 
-    /**
-     * Conversation's phone number is not saved on disk, so it has to be fetched.
-     */
-    @WorkerThread
-    private ConversationInfo restoreConversationPhoneNumber(
-            @NonNull ConversationInfo conversationInfo) {
-        if (conversationInfo.getContactUri() != null) {
-            if (mHelper.query(conversationInfo.getContactUri().toString())) {
-                String phoneNumber = mHelper.getPhoneNumber();
-                if (!TextUtils.isEmpty(phoneNumber)) {
-                    conversationInfo = new ConversationInfo.Builder(
-                            conversationInfo).setContactPhoneNumber(
-                            phoneNumber).build();
-                }
-            }
-        }
-        return conversationInfo;
-    }
-
-    /** Reads and writes {@link ConversationInfo} on disk. */
-    static class ConversationInfosProtoDiskReadWriter extends
+    /** Reads and writes {@link ConversationInfo}s on disk. */
+    private static class ConversationInfosProtoDiskReadWriter extends
             AbstractProtoDiskReadWriter<List<ConversationInfo>> {
 
         private final String mConversationInfoFileName;
 
-        ConversationInfosProtoDiskReadWriter(@NonNull File baseDir,
+        ConversationInfosProtoDiskReadWriter(@NonNull File rootDir,
                 @NonNull String conversationInfoFileName,
-                long writeDelayMs, @NonNull ScheduledExecutorService scheduledExecutorService) {
-            super(baseDir, writeDelayMs, scheduledExecutorService);
+                @NonNull ScheduledExecutorService scheduledExecutorService) {
+            super(rootDir, scheduledExecutorService);
             mConversationInfoFileName = conversationInfoFileName;
         }
 
@@ -328,5 +309,10 @@
         void saveConversationsImmediately(@NonNull List<ConversationInfo> conversationInfos) {
             saveImmediately(mConversationInfoFileName, conversationInfos);
         }
+
+        @WorkerThread
+        void deleteConversationsFile() {
+            delete(mConversationInfoFileName);
+        }
     }
 }
diff --git a/services/people/java/com/android/server/people/data/DataManager.java b/services/people/java/com/android/server/people/data/DataManager.java
index 6b97c98..3a34c6a 100644
--- a/services/people/java/com/android/server/people/data/DataManager.java
+++ b/services/people/java/com/android/server/people/data/DataManager.java
@@ -31,7 +31,9 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.LauncherApps;
 import android.content.pm.LauncherApps.ShortcutQuery;
+import android.content.pm.PackageManager;
 import android.content.pm.PackageManagerInternal;
 import android.content.pm.ShortcutInfo;
 import android.content.pm.ShortcutManager.ShareShortcutInfo;
@@ -51,9 +53,9 @@
 import android.service.notification.NotificationListenerService;
 import android.service.notification.StatusBarNotification;
 import android.telecom.TelecomManager;
-import android.text.TextUtils;
 import android.text.format.DateUtils;
 import android.util.ArraySet;
+import android.util.Slog;
 import android.util.SparseArray;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -62,11 +64,13 @@
 import com.android.internal.os.BackgroundThread;
 import com.android.internal.telephony.SmsApplication;
 import com.android.server.LocalServices;
+import com.android.server.notification.NotificationManagerInternal;
 
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 import java.util.Set;
+import java.util.concurrent.Executor;
 import java.util.concurrent.Executors;
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.ScheduledFuture;
@@ -81,8 +85,8 @@
  */
 public class DataManager {
 
-    private static final int MY_UID = Process.myUid();
-    private static final int MY_PID = Process.myPid();
+    private static final String TAG = "DataManager";
+
     private static final long QUERY_EVENTS_MAX_AGE_MS = DateUtils.DAY_IN_MILLIS;
     private static final long USAGE_STATS_QUERY_INTERVAL_SEC = 120L;
 
@@ -103,6 +107,7 @@
 
     private ShortcutServiceInternal mShortcutServiceInternal;
     private PackageManagerInternal mPackageManagerInternal;
+    private NotificationManagerInternal mNotificationManagerInternal;
     private UserManager mUserManager;
 
     public DataManager(Context context) {
@@ -121,9 +126,10 @@
     public void initialize() {
         mShortcutServiceInternal = LocalServices.getService(ShortcutServiceInternal.class);
         mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
+        mNotificationManagerInternal = LocalServices.getService(NotificationManagerInternal.class);
         mUserManager = mContext.getSystemService(UserManager.class);
 
-        mShortcutServiceInternal.addListener(new ShortcutServiceListener());
+        mShortcutServiceInternal.addShortcutChangeCallback(new ShortcutServiceCallback());
 
         IntentFilter shutdownIntentFilter = new IntentFilter(Intent.ACTION_SHUTDOWN);
         BroadcastReceiver shutdownBroadcastReceiver = new ShutdownBroadcastReceiver();
@@ -134,8 +140,7 @@
     public void onUserUnlocked(int userId) {
         UserData userData = mUserDataArray.get(userId);
         if (userData == null) {
-            userData = new UserData(userId, mDiskReadWriterExecutor,
-                    mInjector.createContactsQueryHelper(mContext));
+            userData = new UserData(userId, mDiskReadWriterExecutor);
             mUserDataArray.put(userId, userData);
         }
         userData.setUserUnlocked();
@@ -275,40 +280,35 @@
                 mContext.getPackageName(), intentFilter, callingUserId);
     }
 
-    /** Reports the {@link AppTargetEvent} from App Prediction Manager. */
-    public void reportAppTargetEvent(@NonNull AppTargetEvent event,
+    /** Reports the sharing related {@link AppTargetEvent} from App Prediction Manager. */
+    public void reportShareTargetEvent(@NonNull AppTargetEvent event,
             @Nullable IntentFilter intentFilter) {
         AppTarget appTarget = event.getTarget();
-        ShortcutInfo shortcutInfo = appTarget != null ? appTarget.getShortcutInfo() : null;
-        if (shortcutInfo == null || event.getAction() != AppTargetEvent.ACTION_LAUNCH) {
+        if (appTarget == null || event.getAction() != AppTargetEvent.ACTION_LAUNCH) {
             return;
         }
-        PackageData packageData = getPackage(appTarget.getPackageName(),
-                appTarget.getUser().getIdentifier());
-        if (packageData == null) {
-            return;
-        }
+        UserData userData = getUnlockedUserData(appTarget.getUser().getIdentifier());
+        PackageData packageData = userData.getOrCreatePackageData(appTarget.getPackageName());
+        String mimeType = intentFilter != null ? intentFilter.getDataType(0) : null;
+        @Event.EventType int eventType = mimeTypeToShareEventType(mimeType);
+        EventHistoryImpl eventHistory;
         if (ChooserActivity.LAUNCH_LOCATON_DIRECT_SHARE.equals(event.getLaunchLocation())) {
-            String mimeType = intentFilter != null ? intentFilter.getDataType(0) : null;
-            String shortcutId = shortcutInfo.getId();
-            if (packageData.getConversationStore().getConversation(shortcutId) == null
-                    || TextUtils.isEmpty(mimeType)) {
+            // Direct share event
+            if (appTarget.getShortcutInfo() == null) {
                 return;
             }
-            EventHistoryImpl eventHistory = packageData.getEventStore().getOrCreateEventHistory(
-                    EventStore.CATEGORY_SHORTCUT_BASED, shortcutInfo.getId());
-            @Event.EventType int eventType;
-            if (mimeType.startsWith("text/")) {
-                eventType = Event.TYPE_SHARE_TEXT;
-            } else if (mimeType.startsWith("image/")) {
-                eventType = Event.TYPE_SHARE_IMAGE;
-            } else if (mimeType.startsWith("video/")) {
-                eventType = Event.TYPE_SHARE_VIDEO;
-            } else {
-                eventType = Event.TYPE_SHARE_OTHER;
+            String shortcutId = appTarget.getShortcutInfo().getId();
+            if (packageData.getConversationStore().getConversation(shortcutId) == null) {
+                addOrUpdateConversationInfo(appTarget.getShortcutInfo());
             }
-            eventHistory.addEvent(new Event(System.currentTimeMillis(), eventType));
+            eventHistory = packageData.getEventStore().getOrCreateEventHistory(
+                    EventStore.CATEGORY_SHORTCUT_BASED, shortcutId);
+        } else {
+            // App share event
+            eventHistory = packageData.getEventStore().getOrCreateEventHistory(
+                    EventStore.CATEGORY_CLASS_BASED, appTarget.getClassName());
         }
+        eventHistory.addEvent(new Event(System.currentTimeMillis(), eventType));
     }
 
     /** Prunes the data for the specified user. */
@@ -319,12 +319,11 @@
         }
         pruneUninstalledPackageData(userData);
 
-        long currentTimeMillis = System.currentTimeMillis();
         userData.forAllPackages(packageData -> {
             if (signal.isCanceled()) {
                 return;
             }
-            packageData.getEventStore().pruneOldEvents(currentTimeMillis);
+            packageData.getEventStore().pruneOldEvents();
             if (!packageData.isDefaultDialer()) {
                 packageData.getEventStore().deleteEventHistories(EventStore.CATEGORY_CALL);
             }
@@ -335,6 +334,17 @@
         });
     }
 
+    private int mimeTypeToShareEventType(String mimeType) {
+        if (mimeType.startsWith("text/")) {
+            return Event.TYPE_SHARE_TEXT;
+        } else if (mimeType.startsWith("image/")) {
+            return Event.TYPE_SHARE_IMAGE;
+        } else if (mimeType.startsWith("video/")) {
+            return Event.TYPE_SHARE_VIDEO;
+        }
+        return Event.TYPE_SHARE_OTHER;
+    }
+
     private void pruneUninstalledPackageData(@NonNull UserData userData) {
         Set<String> installApps = new ArraySet<>();
         mPackageManagerInternal.forEachInstalledPackage(
@@ -359,7 +369,7 @@
         return mShortcutServiceInternal.getShortcuts(
                 UserHandle.USER_SYSTEM, mContext.getPackageName(),
                 /*changedSince=*/ 0, packageName, shortcutIds, /*locusIds=*/ null,
-                /*componentName=*/ null, queryFlags, userId, MY_PID, MY_UID);
+                /*componentName=*/ null, queryFlags, userId, Process.myPid(), Process.myUid());
     }
 
     private void forAllUnlockedUsers(Consumer<UserData> consumer) {
@@ -410,12 +420,13 @@
                 EventStore.CATEGORY_SHORTCUT_BASED, shortcutId);
     }
 
+    private boolean isPersonShortcut(@NonNull ShortcutInfo shortcutInfo) {
+        return shortcutInfo.getPersons() != null && shortcutInfo.getPersons().length != 0;
+    }
+
     @VisibleForTesting
     @WorkerThread
-    void onShortcutAddedOrUpdated(@NonNull ShortcutInfo shortcutInfo) {
-        if (shortcutInfo.getPersons() == null || shortcutInfo.getPersons().length == 0) {
-            return;
-        }
+    void addOrUpdateConversationInfo(@NonNull ShortcutInfo shortcutInfo) {
         UserData userData = getUnlockedUserData(shortcutInfo.getUserId());
         if (userData == null) {
             return;
@@ -431,24 +442,24 @@
         builder.setShortcutId(shortcutInfo.getId());
         builder.setLocusId(shortcutInfo.getLocusId());
         builder.setShortcutFlags(shortcutInfo.getFlags());
+        builder.setContactUri(null);
+        builder.setContactPhoneNumber(null);
+        builder.setContactStarred(false);
 
-        Person person = shortcutInfo.getPersons()[0];
-        builder.setPersonImportant(person.isImportant());
-        builder.setPersonBot(person.isBot());
-        String contactUri = person.getUri();
-        if (contactUri != null) {
-            ContactsQueryHelper helper = mInjector.createContactsQueryHelper(mContext);
-            if (helper.query(contactUri)) {
-                builder.setContactUri(helper.getContactUri());
-                builder.setContactStarred(helper.isStarred());
-                builder.setContactPhoneNumber(helper.getPhoneNumber());
+        if (shortcutInfo.getPersons() != null && shortcutInfo.getPersons().length != 0) {
+            Person person = shortcutInfo.getPersons()[0];
+            builder.setPersonImportant(person.isImportant());
+            builder.setPersonBot(person.isBot());
+            String contactUri = person.getUri();
+            if (contactUri != null) {
+                ContactsQueryHelper helper = mInjector.createContactsQueryHelper(mContext);
+                if (helper.query(contactUri)) {
+                    builder.setContactUri(helper.getContactUri());
+                    builder.setContactStarred(helper.isStarred());
+                    builder.setContactPhoneNumber(helper.getPhoneNumber());
+                }
             }
-        } else {
-            builder.setContactUri(null);
-            builder.setContactPhoneNumber(null);
-            builder.setContactStarred(false);
         }
-
         conversationStore.addOrUpdate(builder.build());
     }
 
@@ -617,16 +628,40 @@
     }
 
     /** Listener for the shortcut data changes. */
-    private class ShortcutServiceListener implements
-            ShortcutServiceInternal.ShortcutChangeListener {
+    private class ShortcutServiceCallback implements LauncherApps.ShortcutChangeCallback {
 
         @Override
-        public void onShortcutChanged(@NonNull String packageName, int userId) {
-            BackgroundThread.getExecutor().execute(() -> {
-                List<ShortcutInfo> shortcuts = getShortcuts(packageName, userId,
-                        /*shortcutIds=*/ null);
+        public void onShortcutsAddedOrUpdated(@NonNull String packageName,
+                @NonNull List<ShortcutInfo> shortcuts, @NonNull UserHandle user) {
+            mInjector.getBackgroundExecutor().execute(() -> {
                 for (ShortcutInfo shortcut : shortcuts) {
-                    onShortcutAddedOrUpdated(shortcut);
+                    if (isPersonShortcut(shortcut)) {
+                        addOrUpdateConversationInfo(shortcut);
+                    }
+                }
+            });
+        }
+
+        @Override
+        public void onShortcutsRemoved(@NonNull String packageName,
+                @NonNull List<ShortcutInfo> shortcuts, @NonNull UserHandle user) {
+            mInjector.getBackgroundExecutor().execute(() -> {
+                int uid = Process.INVALID_UID;
+                try {
+                    uid = mContext.getPackageManager().getPackageUidAsUser(
+                            packageName, user.getIdentifier());
+                } catch (PackageManager.NameNotFoundException e) {
+                    Slog.e(TAG, "Package not found: " + packageName, e);
+                }
+                PackageData packageData = getPackage(packageName, user.getIdentifier());
+                for (ShortcutInfo shortcutInfo : shortcuts) {
+                    if (packageData != null) {
+                        packageData.deleteDataForConversation(shortcutInfo.getId());
+                    }
+                    if (uid != Process.INVALID_UID) {
+                        mNotificationManagerInternal.onConversationRemoved(
+                                shortcutInfo.getPackage(), uid, shortcutInfo.getId());
+                    }
                 }
             });
         }
@@ -782,6 +817,10 @@
             return Executors.newSingleThreadScheduledExecutor();
         }
 
+        Executor getBackgroundExecutor() {
+            return BackgroundThread.getExecutor();
+        }
+
         ContactsQueryHelper createContactsQueryHelper(Context context) {
             return new ContactsQueryHelper(context);
         }
diff --git a/services/people/java/com/android/server/people/data/Event.java b/services/people/java/com/android/server/people/data/Event.java
index 81411c0..a929f6f 100644
--- a/services/people/java/com/android/server/people/data/Event.java
+++ b/services/people/java/com/android/server/people/data/Event.java
@@ -20,7 +20,13 @@
 import android.annotation.NonNull;
 import android.text.format.DateFormat;
 import android.util.ArraySet;
+import android.util.Slog;
+import android.util.proto.ProtoInputStream;
+import android.util.proto.ProtoOutputStream;
 
+import com.android.server.people.PeopleEventProto;
+
+import java.io.IOException;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.Objects;
@@ -29,6 +35,8 @@
 /** An event representing the interaction with a specific conversation or app. */
 public class Event {
 
+    private static final String TAG = Event.class.getSimpleName();
+
     public static final int TYPE_SHORTCUT_INVOCATION = 1;
 
     public static final int TYPE_NOTIFICATION_POSTED = 2;
@@ -142,6 +150,36 @@
         return mDurationSeconds;
     }
 
+    /** Writes field members to {@link ProtoOutputStream}. */
+    void writeToProto(@NonNull ProtoOutputStream protoOutputStream) {
+        protoOutputStream.write(PeopleEventProto.EVENT_TYPE, mType);
+        protoOutputStream.write(PeopleEventProto.TIME, mTimestamp);
+        protoOutputStream.write(PeopleEventProto.DURATION, mDurationSeconds);
+    }
+
+    /** Reads from {@link ProtoInputStream} and constructs {@link Event}. */
+    @NonNull
+    static Event readFromProto(@NonNull ProtoInputStream protoInputStream) throws IOException {
+        Event.Builder builder = new Event.Builder();
+        while (protoInputStream.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (protoInputStream.getFieldNumber()) {
+                case (int) PeopleEventProto.EVENT_TYPE:
+                    builder.setType(protoInputStream.readInt(PeopleEventProto.EVENT_TYPE));
+                    break;
+                case (int) PeopleEventProto.TIME:
+                    builder.setTimestamp(protoInputStream.readLong(PeopleEventProto.TIME));
+                    break;
+                case (int) PeopleEventProto.DURATION:
+                    builder.setDurationSeconds(protoInputStream.readInt(PeopleEventProto.DURATION));
+                    break;
+                default:
+                    Slog.w(TAG, "Could not read undefined field: "
+                            + protoInputStream.getFieldNumber());
+            }
+        }
+        return builder.build();
+    }
+
     @Override
     public boolean equals(Object obj) {
         if (this == obj) {
@@ -177,12 +215,14 @@
     /** Builder class for {@link Event} objects. */
     static class Builder {
 
-        private final long mTimestamp;
+        private long mTimestamp;
 
-        private final int mType;
+        private int mType;
 
         private int mDurationSeconds;
 
+        private Builder() {}
+
         Builder(long timestamp, @EventType int type) {
             mTimestamp = timestamp;
             mType = type;
@@ -193,6 +233,16 @@
             return this;
         }
 
+        private Builder setTimestamp(long timestamp) {
+            mTimestamp = timestamp;
+            return this;
+        }
+
+        private Builder setType(int type) {
+            mType = type;
+            return this;
+        }
+
         Event build() {
             return new Event(this);
         }
diff --git a/services/people/java/com/android/server/people/data/EventHistoryImpl.java b/services/people/java/com/android/server/people/data/EventHistoryImpl.java
index 6bef1db..85661c6 100644
--- a/services/people/java/com/android/server/people/data/EventHistoryImpl.java
+++ b/services/people/java/com/android/server/people/data/EventHistoryImpl.java
@@ -16,42 +16,149 @@
 
 package com.android.server.people.data;
 
+import android.annotation.MainThread;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.WorkerThread;
+import android.net.Uri;
+import android.text.format.DateUtils;
+import android.util.ArrayMap;
+import android.util.Slog;
 import android.util.SparseArray;
+import android.util.proto.ProtoInputStream;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.people.PeopleEventIndexesProto;
+import com.android.server.people.PeopleEventsProto;
+import com.android.server.people.TypedPeopleEventIndexProto;
 
+import com.google.android.collect.Lists;
+
+import java.io.File;
+import java.io.IOException;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.ScheduledExecutorService;
+
 
 class EventHistoryImpl implements EventHistory {
 
+    private static final long MAX_EVENTS_AGE = 4L * DateUtils.HOUR_IN_MILLIS;
+    private static final long PRUNE_OLD_EVENTS_DELAY = 15L * DateUtils.MINUTE_IN_MILLIS;
+
+    private static final String EVENTS_DIR = "events";
+    private static final String INDEXES_DIR = "indexes";
+
     private final Injector mInjector;
+    private final ScheduledExecutorService mScheduledExecutorService;
+    private final EventsProtoDiskReadWriter mEventsProtoDiskReadWriter;
+    private final EventIndexesProtoDiskReadWriter mEventIndexesProtoDiskReadWriter;
 
     // Event Type -> Event Index
+    @GuardedBy("this")
     private final SparseArray<EventIndex> mEventIndexArray = new SparseArray<>();
 
+    @GuardedBy("this")
     private final EventList mRecentEvents = new EventList();
 
-    EventHistoryImpl() {
-        mInjector = new Injector();
+    private long mLastPruneTime;
+
+    EventHistoryImpl(@NonNull File rootDir,
+            @NonNull ScheduledExecutorService scheduledExecutorService) {
+        this(new Injector(), rootDir, scheduledExecutorService);
     }
 
     @VisibleForTesting
-    EventHistoryImpl(Injector injector) {
+    EventHistoryImpl(@NonNull Injector injector, @NonNull File rootDir,
+            @NonNull ScheduledExecutorService scheduledExecutorService) {
         mInjector = injector;
+        mScheduledExecutorService = scheduledExecutorService;
+        mLastPruneTime = injector.currentTimeMillis();
+
+        File eventsDir = new File(rootDir, EVENTS_DIR);
+        mEventsProtoDiskReadWriter = new EventsProtoDiskReadWriter(eventsDir,
+                mScheduledExecutorService);
+        File indexesDir = new File(rootDir, INDEXES_DIR);
+        mEventIndexesProtoDiskReadWriter = new EventIndexesProtoDiskReadWriter(indexesDir,
+                scheduledExecutorService);
+    }
+
+    @WorkerThread
+    @NonNull
+    static Map<String, EventHistoryImpl> eventHistoriesImplFromDisk(File categoryDir,
+            ScheduledExecutorService scheduledExecutorService) {
+        return eventHistoriesImplFromDisk(new Injector(), categoryDir, scheduledExecutorService);
+    }
+
+    @VisibleForTesting
+    @NonNull
+    static Map<String, EventHistoryImpl> eventHistoriesImplFromDisk(Injector injector,
+            File categoryDir, ScheduledExecutorService scheduledExecutorService) {
+        Map<String, EventHistoryImpl> results = new ArrayMap<>();
+        File[] keyDirs = categoryDir.listFiles(File::isDirectory);
+        if (keyDirs == null) {
+            return results;
+        }
+        for (File keyDir : keyDirs) {
+            File[] dirContents = keyDir.listFiles(
+                    (dir, name) -> EVENTS_DIR.equals(name) || INDEXES_DIR.equals(name));
+            if (dirContents != null && dirContents.length == 2) {
+                EventHistoryImpl eventHistory = new EventHistoryImpl(injector, keyDir,
+                        scheduledExecutorService);
+                eventHistory.loadFromDisk();
+                results.put(Uri.decode(keyDir.getName()), eventHistory);
+            }
+        }
+        return results;
+    }
+
+    /**
+     * Loads recent events and indexes from disk to memory in a background thread. This should be
+     * called after the device powers on and the user has been unlocked.
+     */
+    @VisibleForTesting
+    @MainThread
+    synchronized void loadFromDisk() {
+        mScheduledExecutorService.execute(() -> {
+            synchronized (this) {
+                EventList diskEvents = mEventsProtoDiskReadWriter.loadRecentEventsFromDisk();
+                if (diskEvents != null) {
+                    diskEvents.removeOldEvents(mInjector.currentTimeMillis() - MAX_EVENTS_AGE);
+                    mRecentEvents.addAll(diskEvents.getAllEvents());
+                }
+
+                SparseArray<EventIndex> diskIndexes =
+                        mEventIndexesProtoDiskReadWriter.loadIndexesFromDisk();
+                if (diskIndexes != null) {
+                    for (int i = 0; i < diskIndexes.size(); i++) {
+                        mEventIndexArray.put(diskIndexes.keyAt(i), diskIndexes.valueAt(i));
+                    }
+                }
+            }
+        });
+    }
+
+    /**
+     * Flushes events and indexes immediately. This should be called when device is powering off.
+     */
+    @MainThread
+    synchronized void saveToDisk() {
+        mEventsProtoDiskReadWriter.saveEventsImmediately(mRecentEvents);
+        mEventIndexesProtoDiskReadWriter.saveIndexesImmediately(mEventIndexArray);
     }
 
     @Override
     @NonNull
-    public EventIndex getEventIndex(@Event.EventType int eventType) {
+    public synchronized EventIndex getEventIndex(@Event.EventType int eventType) {
         EventIndex eventIndex = mEventIndexArray.get(eventType);
         return eventIndex != null ? new EventIndex(eventIndex) : mInjector.createEventIndex();
     }
 
     @Override
     @NonNull
-    public EventIndex getEventIndex(Set<Integer> eventTypes) {
+    public synchronized EventIndex getEventIndex(Set<Integer> eventTypes) {
         EventIndex combined = mInjector.createEventIndex();
         for (@Event.EventType int eventType : eventTypes) {
             EventIndex eventIndex = mEventIndexArray.get(eventType);
@@ -64,11 +171,35 @@
 
     @Override
     @NonNull
-    public List<Event> queryEvents(Set<Integer> eventTypes, long startTime, long endTime) {
+    public synchronized List<Event> queryEvents(Set<Integer> eventTypes, long startTime,
+            long endTime) {
         return mRecentEvents.queryEvents(eventTypes, startTime, endTime);
     }
 
-    void addEvent(Event event) {
+    synchronized void addEvent(Event event) {
+        pruneOldEvents();
+        addEventInMemory(event);
+        mEventsProtoDiskReadWriter.scheduleEventsSave(mRecentEvents);
+        mEventIndexesProtoDiskReadWriter.scheduleIndexesSave(mEventIndexArray);
+    }
+
+    synchronized void onDestroy() {
+        mEventIndexArray.clear();
+        mRecentEvents.clear();
+        mEventsProtoDiskReadWriter.deleteRecentEventsFile();
+        mEventIndexesProtoDiskReadWriter.deleteIndexesFile();
+    }
+
+    /** Deletes the events data that exceeds the retention period. */
+    synchronized void pruneOldEvents() {
+        long currentTime = mInjector.currentTimeMillis();
+        if (currentTime - mLastPruneTime > PRUNE_OLD_EVENTS_DELAY) {
+            mRecentEvents.removeOldEvents(currentTime - MAX_EVENTS_AGE);
+            mLastPruneTime = currentTime;
+        }
+    }
+
+    private synchronized void addEventInMemory(Event event) {
         EventIndex eventIndex = mEventIndexArray.get(event.getType());
         if (eventIndex == null) {
             eventIndex = mInjector.createEventIndex();
@@ -78,22 +209,180 @@
         mRecentEvents.add(event);
     }
 
-    void onDestroy() {
-        mEventIndexArray.clear();
-        mRecentEvents.clear();
-        // TODO: STOPSHIP: Delete the data files.
-    }
-
-    /** Deletes the events data that exceeds the retention period. */
-    void pruneOldEvents(long currentTimeMillis) {
-        // TODO: STOPSHIP: Delete the old events data files.
-    }
-
     @VisibleForTesting
     static class Injector {
 
         EventIndex createEventIndex() {
             return new EventIndex();
         }
+
+        long currentTimeMillis() {
+            return System.currentTimeMillis();
+        }
+    }
+
+    /** Reads and writes {@link Event}s on disk. */
+    private static class EventsProtoDiskReadWriter extends AbstractProtoDiskReadWriter<EventList> {
+
+        private static final String TAG = EventsProtoDiskReadWriter.class.getSimpleName();
+
+        private static final String RECENT_FILE = "recent";
+
+
+        EventsProtoDiskReadWriter(@NonNull File rootDir,
+                @NonNull ScheduledExecutorService scheduledExecutorService) {
+            super(rootDir, scheduledExecutorService);
+            rootDir.mkdirs();
+        }
+
+        @Override
+        ProtoStreamWriter<EventList> protoStreamWriter() {
+            return (protoOutputStream, data) -> {
+                for (Event event : data.getAllEvents()) {
+                    long token = protoOutputStream.start(PeopleEventsProto.EVENTS);
+                    event.writeToProto(protoOutputStream);
+                    protoOutputStream.end(token);
+                }
+            };
+        }
+
+        @Override
+        ProtoStreamReader<EventList> protoStreamReader() {
+            return protoInputStream -> {
+                List<Event> results = Lists.newArrayList();
+                try {
+                    while (protoInputStream.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+                        if (protoInputStream.getFieldNumber() != (int) PeopleEventsProto.EVENTS) {
+                            continue;
+                        }
+                        long token = protoInputStream.start(PeopleEventsProto.EVENTS);
+                        Event event = Event.readFromProto(protoInputStream);
+                        protoInputStream.end(token);
+                        results.add(event);
+                    }
+                } catch (IOException e) {
+                    Slog.e(TAG, "Failed to read protobuf input stream.", e);
+                }
+                EventList eventList = new EventList();
+                eventList.addAll(results);
+                return eventList;
+            };
+        }
+
+        @MainThread
+        void scheduleEventsSave(EventList recentEvents) {
+            scheduleSave(RECENT_FILE, recentEvents);
+        }
+
+        @MainThread
+        void saveEventsImmediately(EventList recentEvents) {
+            saveImmediately(RECENT_FILE, recentEvents);
+        }
+
+        /**
+         * Loads recent events from disk. This should be called when device is powered on.
+         */
+        @WorkerThread
+        @Nullable
+        EventList loadRecentEventsFromDisk() {
+            return read(RECENT_FILE);
+        }
+
+        @WorkerThread
+        void deleteRecentEventsFile() {
+            delete(RECENT_FILE);
+        }
+    }
+
+    /** Reads and writes {@link EventIndex}s on disk. */
+    private static class EventIndexesProtoDiskReadWriter extends
+            AbstractProtoDiskReadWriter<SparseArray<EventIndex>> {
+
+        private static final String TAG = EventIndexesProtoDiskReadWriter.class.getSimpleName();
+
+        private static final String INDEXES_FILE = "index";
+
+        EventIndexesProtoDiskReadWriter(@NonNull File rootDir,
+                @NonNull ScheduledExecutorService scheduledExecutorService) {
+            super(rootDir, scheduledExecutorService);
+            rootDir.mkdirs();
+        }
+
+        @Override
+        ProtoStreamWriter<SparseArray<EventIndex>> protoStreamWriter() {
+            return (protoOutputStream, data) -> {
+                for (int i = 0; i < data.size(); i++) {
+                    @Event.EventType int eventType = data.keyAt(i);
+                    EventIndex index = data.valueAt(i);
+                    long token = protoOutputStream.start(PeopleEventIndexesProto.TYPED_INDEXES);
+                    protoOutputStream.write(TypedPeopleEventIndexProto.EVENT_TYPE, eventType);
+                    long indexToken = protoOutputStream.start(TypedPeopleEventIndexProto.INDEX);
+                    index.writeToProto(protoOutputStream);
+                    protoOutputStream.end(indexToken);
+                    protoOutputStream.end(token);
+                }
+            };
+        }
+
+        @Override
+        ProtoStreamReader<SparseArray<EventIndex>> protoStreamReader() {
+            return protoInputStream -> {
+                SparseArray<EventIndex> results = new SparseArray<>();
+                try {
+                    while (protoInputStream.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+                        if (protoInputStream.getFieldNumber()
+                                != (int) PeopleEventIndexesProto.TYPED_INDEXES) {
+                            continue;
+                        }
+                        long token = protoInputStream.start(PeopleEventIndexesProto.TYPED_INDEXES);
+                        @Event.EventType int eventType = 0;
+                        EventIndex index = EventIndex.EMPTY;
+                        while (protoInputStream.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+                            switch (protoInputStream.getFieldNumber()) {
+                                case (int) TypedPeopleEventIndexProto.EVENT_TYPE:
+                                    eventType = protoInputStream.readInt(
+                                            TypedPeopleEventIndexProto.EVENT_TYPE);
+                                    break;
+                                case (int) TypedPeopleEventIndexProto.INDEX:
+                                    long indexToken = protoInputStream.start(
+                                            TypedPeopleEventIndexProto.INDEX);
+                                    index = EventIndex.readFromProto(protoInputStream);
+                                    protoInputStream.end(indexToken);
+                                    break;
+                                default:
+                                    Slog.w(TAG, "Could not read undefined field: "
+                                            + protoInputStream.getFieldNumber());
+                            }
+                        }
+                        results.append(eventType, index);
+                        protoInputStream.end(token);
+                    }
+                } catch (IOException e) {
+                    Slog.e(TAG, "Failed to read protobuf input stream.", e);
+                }
+                return results;
+            };
+        }
+
+        @MainThread
+        void scheduleIndexesSave(SparseArray<EventIndex> indexes) {
+            scheduleSave(INDEXES_FILE, indexes);
+        }
+
+        @MainThread
+        void saveIndexesImmediately(SparseArray<EventIndex> indexes) {
+            saveImmediately(INDEXES_FILE, indexes);
+        }
+
+        @WorkerThread
+        @Nullable
+        SparseArray<EventIndex> loadIndexesFromDisk() {
+            return read(INDEXES_FILE);
+        }
+
+        @WorkerThread
+        void deleteIndexesFile() {
+            delete(INDEXES_FILE);
+        }
     }
 }
diff --git a/services/people/java/com/android/server/people/data/EventIndex.java b/services/people/java/com/android/server/people/data/EventIndex.java
index b74a3fa..47b6207 100644
--- a/services/people/java/com/android/server/people/data/EventIndex.java
+++ b/services/people/java/com/android/server/people/data/EventIndex.java
@@ -21,9 +21,14 @@
 import android.annotation.Nullable;
 import android.text.format.DateFormat;
 import android.util.Range;
+import android.util.Slog;
+import android.util.proto.ProtoInputStream;
+import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.people.PeopleEventIndexProto;
 
+import java.io.IOException;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.time.Instant;
@@ -34,6 +39,7 @@
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
+import java.util.Objects;
 import java.util.TimeZone;
 import java.util.function.Function;
 
@@ -60,8 +66,9 @@
  *  </pre>
  */
 public class EventIndex {
+    private static final String TAG = EventIndex.class.getSimpleName();
 
-    private static final int LONG_SIZE_BITS = 64;
+    private static final int RETENTION_DAYS = 63;
 
     private static final int TIME_SLOT_ONE_DAY = 0;
 
@@ -118,22 +125,23 @@
     private final Injector mInjector;
 
     EventIndex() {
-        mInjector = new Injector();
-        mEventBitmaps = new long[]{0L, 0L, 0L, 0L};
-        mLastUpdatedTime = mInjector.currentTimeMillis();
+        this(new Injector());
     }
 
-    EventIndex(EventIndex from) {
-        mInjector = new Injector();
-        mEventBitmaps = Arrays.copyOf(from.mEventBitmaps, TIME_SLOT_TYPES_COUNT);
-        mLastUpdatedTime = from.mLastUpdatedTime;
+    EventIndex(@NonNull EventIndex from) {
+        this(from.mInjector, Arrays.copyOf(from.mEventBitmaps, TIME_SLOT_TYPES_COUNT),
+                from.mLastUpdatedTime);
     }
 
     @VisibleForTesting
-    EventIndex(Injector injector) {
+    EventIndex(@NonNull Injector injector) {
+        this(injector, new long[]{0L, 0L, 0L, 0L}, injector.currentTimeMillis());
+    }
+
+    private EventIndex(@NonNull Injector injector, long[] eventBitmaps, long lastUpdatedTime) {
         mInjector = injector;
-        mEventBitmaps = new long[]{0L, 0L, 0L, 0L};
-        mLastUpdatedTime = mInjector.currentTimeMillis();
+        mEventBitmaps = eventBitmaps;
+        mLastUpdatedTime = lastUpdatedTime;
     }
 
     /**
@@ -202,7 +210,7 @@
             updateEventBitmaps(currentTime);
             for (int slotType = 0; slotType < TIME_SLOT_TYPES_COUNT; slotType++) {
                 int offset = diffTimeSlots(slotType, eventTime, currentTime);
-                if (offset < LONG_SIZE_BITS) {
+                if (offset < Long.SIZE) {
                     mEventBitmaps[slotType] |= (1L << offset);
                 }
             }
@@ -232,19 +240,70 @@
         return sb.toString();
     }
 
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!(obj instanceof EventIndex)) {
+            return false;
+        }
+        EventIndex other = (EventIndex) obj;
+        return mLastUpdatedTime == other.mLastUpdatedTime
+                && Arrays.equals(mEventBitmaps, other.mEventBitmaps);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mLastUpdatedTime, mEventBitmaps);
+    }
+
+    synchronized void writeToProto(@NonNull ProtoOutputStream protoOutputStream) {
+        for (long bitmap : mEventBitmaps) {
+            protoOutputStream.write(PeopleEventIndexProto.EVENT_BITMAPS, bitmap);
+        }
+        protoOutputStream.write(PeopleEventIndexProto.LAST_UPDATED_TIME, mLastUpdatedTime);
+    }
+
     /** Shifts the event bitmaps to make them up-to-date. */
     private void updateEventBitmaps(long currentTimeMillis) {
         for (int slotType = 0; slotType < TIME_SLOT_TYPES_COUNT; slotType++) {
             int offset = diffTimeSlots(slotType, mLastUpdatedTime, currentTimeMillis);
-            if (offset < LONG_SIZE_BITS) {
+            if (offset < Long.SIZE) {
                 mEventBitmaps[slotType] <<= offset;
             } else {
                 mEventBitmaps[slotType] = 0L;
             }
         }
+
+        int bitsToClear = Long.SIZE - RETENTION_DAYS;
+        mEventBitmaps[TIME_SLOT_ONE_DAY] <<= bitsToClear;
+        mEventBitmaps[TIME_SLOT_ONE_DAY] >>>= bitsToClear;
         mLastUpdatedTime = currentTimeMillis;
     }
 
+    static EventIndex readFromProto(@NonNull ProtoInputStream protoInputStream) throws IOException {
+        int bitmapIndex = 0;
+        long[] eventBitmaps = new long[TIME_SLOT_TYPES_COUNT];
+        long lastUpdated = 0L;
+        while (protoInputStream.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (protoInputStream.getFieldNumber()) {
+                case (int) PeopleEventIndexProto.EVENT_BITMAPS:
+                    eventBitmaps[bitmapIndex++] = protoInputStream.readLong(
+                            PeopleEventIndexProto.EVENT_BITMAPS);
+                    break;
+                case (int) PeopleEventIndexProto.LAST_UPDATED_TIME:
+                    lastUpdated = protoInputStream.readLong(
+                            PeopleEventIndexProto.LAST_UPDATED_TIME);
+                    break;
+                default:
+                    Slog.e(TAG, "Could not read undefined field: "
+                            + protoInputStream.getFieldNumber());
+            }
+        }
+        return new EventIndex(new Injector(), eventBitmaps, lastUpdated);
+    }
+
     private static LocalDateTime toLocalDateTime(long epochMilli) {
         return LocalDateTime.ofInstant(
                 Instant.ofEpochMilli(epochMilli), TimeZone.getDefault().toZoneId());
diff --git a/services/people/java/com/android/server/people/data/EventList.java b/services/people/java/com/android/server/people/data/EventList.java
index d770f91..3788d6c 100644
--- a/services/people/java/com/android/server/people/data/EventList.java
+++ b/services/people/java/com/android/server/people/data/EventList.java
@@ -18,6 +18,8 @@
 
 import android.annotation.NonNull;
 
+import com.android.internal.util.CollectionUtils;
+
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Set;
@@ -41,6 +43,16 @@
         mEvents.add(index, event);
     }
 
+
+    /**
+     * Call #add on each event to keep the order.
+     */
+    void addAll(@NonNull List<Event> events) {
+        for (Event event : events) {
+            add(event);
+        }
+    }
+
     /**
      * Returns a {@link List} of {@link Event}s whose timestamps are between the specified {@code
      * fromTimestamp}, inclusive, and {@code toTimestamp} exclusive, and match the specified event
@@ -73,6 +85,44 @@
         mEvents.clear();
     }
 
+    /**
+     * Returns a copy of events.
+     */
+    @NonNull
+    List<Event> getAllEvents() {
+        return CollectionUtils.copyOf(mEvents);
+    }
+
+    /**
+     * Remove events that are older than the specified cut off threshold timestamp.
+     */
+    void removeOldEvents(long cutOffThreshold) {
+
+        // Everything before the cut off is considered old, and should be removed.
+        int cutOffIndex = firstIndexOnOrAfter(cutOffThreshold);
+        if (cutOffIndex == 0) {
+            return;
+        }
+
+        // Clear entire list if the cut off is greater than the last element.
+        int eventsSize = mEvents.size();
+        if (cutOffIndex == eventsSize) {
+            mEvents.clear();
+            return;
+        }
+
+        // Reorder the list starting from the cut off index.
+        int i = 0;
+        for (; cutOffIndex < eventsSize; i++, cutOffIndex++) {
+            mEvents.set(i, mEvents.get(cutOffIndex));
+        }
+
+        // Clear the list after reordering.
+        if (eventsSize > i) {
+            mEvents.subList(i, eventsSize).clear();
+        }
+    }
+
     /** Returns the first index whose timestamp is greater or equal to the provided timestamp. */
     private int firstIndexOnOrAfter(long timestamp) {
         int result = mEvents.size();
diff --git a/services/people/java/com/android/server/people/data/EventStore.java b/services/people/java/com/android/server/people/data/EventStore.java
index c8d44ac..00d4241 100644
--- a/services/people/java/com/android/server/people/data/EventStore.java
+++ b/services/people/java/com/android/server/people/data/EventStore.java
@@ -17,16 +17,22 @@
 package com.android.server.people.data;
 
 import android.annotation.IntDef;
+import android.annotation.MainThread;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.net.Uri;
 import android.util.ArrayMap;
 
+import com.android.internal.annotations.GuardedBy;
+
+import java.io.File;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.ScheduledExecutorService;
 import java.util.function.Predicate;
 
 /** The store that stores and accesses the events data for a package. */
@@ -57,14 +63,58 @@
     @Retention(RetentionPolicy.SOURCE)
     @interface EventCategory {}
 
+    @GuardedBy("this")
     private final List<Map<String, EventHistoryImpl>> mEventHistoryMaps = new ArrayList<>();
+    private final List<File> mEventsCategoryDirs = new ArrayList<>();
+    private final ScheduledExecutorService mScheduledExecutorService;
 
-    EventStore() {
+    EventStore(@NonNull File packageDir,
+            @NonNull ScheduledExecutorService scheduledExecutorService) {
         mEventHistoryMaps.add(CATEGORY_SHORTCUT_BASED, new ArrayMap<>());
         mEventHistoryMaps.add(CATEGORY_LOCUS_ID_BASED, new ArrayMap<>());
         mEventHistoryMaps.add(CATEGORY_CALL, new ArrayMap<>());
         mEventHistoryMaps.add(CATEGORY_SMS, new ArrayMap<>());
         mEventHistoryMaps.add(CATEGORY_CLASS_BASED, new ArrayMap<>());
+
+        File eventDir = new File(packageDir, "event");
+        mEventsCategoryDirs.add(CATEGORY_SHORTCUT_BASED, new File(eventDir, "shortcut"));
+        mEventsCategoryDirs.add(CATEGORY_LOCUS_ID_BASED, new File(eventDir, "locus"));
+        mEventsCategoryDirs.add(CATEGORY_CALL, new File(eventDir, "call"));
+        mEventsCategoryDirs.add(CATEGORY_SMS, new File(eventDir, "sms"));
+        mEventsCategoryDirs.add(CATEGORY_CLASS_BASED, new File(eventDir, "class"));
+
+        mScheduledExecutorService = scheduledExecutorService;
+    }
+
+    /**
+     * Loads existing {@link EventHistoryImpl}s from disk. This should be called when device powers
+     * on and user is unlocked.
+     */
+    @MainThread
+    void loadFromDisk() {
+        mScheduledExecutorService.execute(() -> {
+            synchronized (this) {
+                for (@EventCategory int category = 0; category < mEventsCategoryDirs.size();
+                        category++) {
+                    File categoryDir = mEventsCategoryDirs.get(category);
+                    Map<String, EventHistoryImpl> existingEventHistoriesImpl =
+                            EventHistoryImpl.eventHistoriesImplFromDisk(categoryDir,
+                                    mScheduledExecutorService);
+                    mEventHistoryMaps.get(category).putAll(existingEventHistoriesImpl);
+                }
+            }
+        });
+    }
+
+    /**
+     * Flushes all {@link EventHistoryImpl}s to disk. Should be called when device is shutting down.
+     */
+    synchronized void saveToDisk() {
+        for (Map<String, EventHistoryImpl> map : mEventHistoryMaps) {
+            for (EventHistoryImpl eventHistory : map.values()) {
+                eventHistory.saveToDisk();
+            }
+        }
     }
 
     /**
@@ -74,7 +124,7 @@
      *            name.
      */
     @Nullable
-    EventHistory getEventHistory(@EventCategory int category, String key) {
+    synchronized EventHistory getEventHistory(@EventCategory int category, String key) {
         return mEventHistoryMaps.get(category).get(key);
     }
 
@@ -87,8 +137,11 @@
      *            name.
      */
     @NonNull
-    EventHistoryImpl getOrCreateEventHistory(@EventCategory int category, String key) {
-        return mEventHistoryMaps.get(category).computeIfAbsent(key, k -> new EventHistoryImpl());
+    synchronized EventHistoryImpl getOrCreateEventHistory(@EventCategory int category, String key) {
+        return mEventHistoryMaps.get(category).computeIfAbsent(key,
+                k -> new EventHistoryImpl(
+                        new File(mEventsCategoryDirs.get(category), Uri.encode(key)),
+                        mScheduledExecutorService));
     }
 
     /**
@@ -97,7 +150,7 @@
      * @param key Category-specific key, it can be shortcut ID, locus ID, phone number, or class
      *            name.
      */
-    void deleteEventHistory(@EventCategory int category, String key) {
+    synchronized void deleteEventHistory(@EventCategory int category, String key) {
         EventHistoryImpl eventHistory = mEventHistoryMaps.get(category).remove(key);
         if (eventHistory != null) {
             eventHistory.onDestroy();
@@ -105,16 +158,18 @@
     }
 
     /** Deletes all the events and index data for the specified category from disk. */
-    void deleteEventHistories(@EventCategory int category) {
+    synchronized void deleteEventHistories(@EventCategory int category) {
+        for (EventHistoryImpl eventHistory : mEventHistoryMaps.get(category).values()) {
+            eventHistory.onDestroy();
+        }
         mEventHistoryMaps.get(category).clear();
-        // TODO: Implement this method to delete the data from disk.
     }
 
     /** Deletes the events data that exceeds the retention period. */
-    void pruneOldEvents(long currentTimeMillis) {
+    synchronized void pruneOldEvents() {
         for (Map<String, EventHistoryImpl> map : mEventHistoryMaps) {
             for (EventHistoryImpl eventHistory : map.values()) {
-                eventHistory.pruneOldEvents(currentTimeMillis);
+                eventHistory.pruneOldEvents();
             }
         }
     }
@@ -125,7 +180,8 @@
      *
      * @param keyChecker Check whether there exists a conversation contains this key.
      */
-    void pruneOrphanEventHistories(@EventCategory int category, Predicate<String> keyChecker) {
+    synchronized void pruneOrphanEventHistories(@EventCategory int category,
+            Predicate<String> keyChecker) {
         Set<String> keys = mEventHistoryMaps.get(category).keySet();
         List<String> keysToDelete = new ArrayList<>();
         for (String key : keys) {
@@ -141,4 +197,12 @@
             }
         }
     }
+
+    synchronized void onDestroy() {
+        for (Map<String, EventHistoryImpl> map : mEventHistoryMaps) {
+            for (EventHistoryImpl eventHistory : map.values()) {
+                eventHistory.onDestroy();
+            }
+        }
+    }
 }
diff --git a/services/people/java/com/android/server/people/data/PackageData.java b/services/people/java/com/android/server/people/data/PackageData.java
index c55f972..35d245f 100644
--- a/services/people/java/com/android/server/people/data/PackageData.java
+++ b/services/people/java/com/android/server/people/data/PackageData.java
@@ -27,8 +27,10 @@
 import android.annotation.UserIdInt;
 import android.content.LocusId;
 import android.text.TextUtils;
+import android.util.ArrayMap;
 
 import java.io.File;
+import java.util.Map;
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.function.Consumer;
 import java.util.function.Predicate;
@@ -57,28 +59,53 @@
             @NonNull Predicate<String> isDefaultDialerPredicate,
             @NonNull Predicate<String> isDefaultSmsAppPredicate,
             @NonNull ScheduledExecutorService scheduledExecutorService,
-            @NonNull File perUserPeopleDataDir,
-            @NonNull ContactsQueryHelper helper) {
+            @NonNull File perUserPeopleDataDir) {
         mPackageName = packageName;
         mUserId = userId;
 
         mPackageDataDir = new File(perUserPeopleDataDir, mPackageName);
-        mConversationStore = new ConversationStore(mPackageDataDir, scheduledExecutorService,
-                helper);
-        mEventStore = new EventStore();
+        mPackageDataDir.mkdirs();
+
+        mConversationStore = new ConversationStore(mPackageDataDir, scheduledExecutorService);
+        mEventStore = new EventStore(mPackageDataDir, scheduledExecutorService);
         mIsDefaultDialerPredicate = isDefaultDialerPredicate;
         mIsDefaultSmsAppPredicate = isDefaultSmsAppPredicate;
     }
 
-    /** Called when user is unlocked. */
-    void loadFromDisk() {
-        mPackageDataDir.mkdirs();
+    /**
+     * Returns a map of package directory names as keys and their associated {@link PackageData}.
+     * This should be called when device is powered on and unlocked.
+     */
+    @NonNull
+    static Map<String, PackageData> packagesDataFromDisk(@UserIdInt int userId,
+            @NonNull Predicate<String> isDefaultDialerPredicate,
+            @NonNull Predicate<String> isDefaultSmsAppPredicate,
+            @NonNull ScheduledExecutorService scheduledExecutorService,
+            @NonNull File perUserPeopleDataDir) {
+        Map<String, PackageData> results = new ArrayMap<>();
+        File[] packageDirs = perUserPeopleDataDir.listFiles(File::isDirectory);
+        if (packageDirs == null) {
+            return results;
+        }
+        for (File packageDir : packageDirs) {
+            PackageData packageData = new PackageData(packageDir.getName(), userId,
+                    isDefaultDialerPredicate, isDefaultSmsAppPredicate, scheduledExecutorService,
+                    perUserPeopleDataDir);
+            packageData.loadFromDisk();
+            results.put(packageDir.getName(), packageData);
+        }
+        return results;
+    }
+
+    private void loadFromDisk() {
         mConversationStore.loadConversationsFromDisk();
+        mEventStore.loadFromDisk();
     }
 
     /** Called when device is shutting down. */
     void saveToDisk() {
         mConversationStore.saveConversationsToDisk();
+        mEventStore.saveToDisk();
     }
 
     @NonNull
@@ -222,6 +249,7 @@
     }
 
     void onDestroy() {
-        // TODO: STOPSHIP: Implements this method for the case of package being uninstalled.
+        mEventStore.onDestroy();
+        mConversationStore.onDestroy();
     }
 }
diff --git a/services/people/java/com/android/server/people/data/UserData.java b/services/people/java/com/android/server/people/data/UserData.java
index 7ca4b6c..0f8b91b 100644
--- a/services/people/java/com/android/server/people/data/UserData.java
+++ b/services/people/java/com/android/server/people/data/UserData.java
@@ -37,8 +37,6 @@
 
     private final ScheduledExecutorService mScheduledExecutorService;
 
-    private final ContactsQueryHelper mHelper;
-
     private boolean mIsUnlocked;
 
     private Map<String, PackageData> mPackageDataMap = new ArrayMap<>();
@@ -49,12 +47,10 @@
     @Nullable
     private String mDefaultSmsApp;
 
-    UserData(@UserIdInt int userId, @NonNull ScheduledExecutorService scheduledExecutorService,
-            ContactsQueryHelper helper) {
+    UserData(@UserIdInt int userId, @NonNull ScheduledExecutorService scheduledExecutorService) {
         mUserId = userId;
         mPerUserPeopleDataDir = new File(Environment.getDataSystemCeDirectory(mUserId), "people");
         mScheduledExecutorService = scheduledExecutorService;
-        mHelper = helper;
     }
 
     @UserIdInt int getUserId() {
@@ -73,9 +69,8 @@
         // Ensures per user root directory for people data is present, and attempt to load
         // data from disk.
         mPerUserPeopleDataDir.mkdirs();
-        for (PackageData packageData : mPackageDataMap.values()) {
-            packageData.loadFromDisk();
-        }
+        mPackageDataMap.putAll(PackageData.packagesDataFromDisk(mUserId, this::isDefaultDialer,
+                this::isDefaultSmsApp, mScheduledExecutorService, mPerUserPeopleDataDir));
     }
 
     void setUserStopped() {
@@ -132,7 +127,7 @@
 
     private PackageData createPackageData(String packageName) {
         return new PackageData(packageName, mUserId, this::isDefaultDialer, this::isDefaultSmsApp,
-                mScheduledExecutorService, mPerUserPeopleDataDir, mHelper);
+                mScheduledExecutorService, mPerUserPeopleDataDir);
     }
 
     private boolean isDefaultDialer(String packageName) {
diff --git a/services/people/java/com/android/server/people/prediction/AppTargetPredictor.java b/services/people/java/com/android/server/people/prediction/AppTargetPredictor.java
index 19cf8af..c89dadc 100644
--- a/services/people/java/com/android/server/people/prediction/AppTargetPredictor.java
+++ b/services/people/java/com/android/server/people/prediction/AppTargetPredictor.java
@@ -73,6 +73,7 @@
      */
     @MainThread
     public void onAppTargetEvent(AppTargetEvent event) {
+        mCallbackExecutor.execute(() -> reportAppTargetEvent(event));
     }
 
     /**
@@ -104,6 +105,11 @@
         return mUpdatePredictionsMethod;
     }
 
+    /** To be overridden by the subclass to report app target event. */
+    @WorkerThread
+    void reportAppTargetEvent(AppTargetEvent event) {
+    }
+
     /** To be overridden by the subclass to predict the targets. */
     @WorkerThread
     void predictTargets() {
diff --git a/services/people/java/com/android/server/people/prediction/ShareTargetPredictor.java b/services/people/java/com/android/server/people/prediction/ShareTargetPredictor.java
index 90d8216..8e5d75b 100644
--- a/services/people/java/com/android/server/people/prediction/ShareTargetPredictor.java
+++ b/services/people/java/com/android/server/people/prediction/ShareTargetPredictor.java
@@ -16,7 +16,6 @@
 
 package com.android.server.people.prediction;
 
-import android.annotation.MainThread;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
@@ -28,15 +27,18 @@
 import android.content.IntentFilter;
 import android.content.pm.ShortcutInfo;
 import android.content.pm.ShortcutManager.ShareShortcutInfo;
+import android.util.Range;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.ChooserActivity;
 import com.android.server.people.data.ConversationInfo;
 import com.android.server.people.data.DataManager;
+import com.android.server.people.data.Event;
 import com.android.server.people.data.EventHistory;
 import com.android.server.people.data.PackageData;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 import java.util.function.Consumer;
 
@@ -52,89 +54,139 @@
                 ChooserActivity.APP_PREDICTION_INTENT_FILTER_KEY);
     }
 
-    @MainThread
-    @Override
-    public void onAppTargetEvent(AppTargetEvent event) {
-        getDataManager().reportAppTargetEvent(event, mIntentFilter);
-    }
-
+    /** Reports chosen history of direct/app share targets. */
     @WorkerThread
     @Override
-    protected void predictTargets() {
-        List<ShareTarget> shareTargets = getShareTargets();
-        // TODO: Rank the share targets with the data in ShareTarget.mConversationData.
-        List<AppTarget> appTargets = new ArrayList<>();
-        for (ShareTarget shareTarget : shareTargets) {
-
-            ShortcutInfo shortcutInfo = shareTarget.getShareShortcutInfo().getShortcutInfo();
-            AppTargetId appTargetId = new AppTargetId(shortcutInfo.getId());
-            String shareTargetClassName =
-                    shareTarget.getShareShortcutInfo().getTargetComponent().getClassName();
-            AppTarget appTarget = new AppTarget.Builder(appTargetId, shortcutInfo)
-                    .setClassName(shareTargetClassName)
-                    .build();
-            appTargets.add(appTarget);
-            if (appTargets.size() >= getPredictionContext().getPredictedTargetCount()) {
-                break;
-            }
-        }
-        updatePredictions(appTargets);
+    void reportAppTargetEvent(AppTargetEvent event) {
+        getDataManager().reportShareTargetEvent(event, mIntentFilter);
     }
 
-    @VisibleForTesting
-    List<ShareTarget> getShareTargets() {
+    /** Provides prediction on direct share targets */
+    @WorkerThread
+    @Override
+    void predictTargets() {
+        List<ShareTarget> shareTargets = getDirectShareTargets();
+        rankTargets(shareTargets);
+        List<AppTarget> res = new ArrayList<>();
+        for (int i = 0; i < Math.min(getPredictionContext().getPredictedTargetCount(),
+                shareTargets.size()); i++) {
+            res.add(shareTargets.get(i).getAppTarget());
+        }
+        updatePredictions(res);
+    }
+
+    /** Provides prediction on app share targets */
+    @WorkerThread
+    @Override
+    void sortTargets(List<AppTarget> targets, Consumer<List<AppTarget>> callback) {
+        List<ShareTarget> shareTargets = getAppShareTargets(targets);
+        rankTargets(shareTargets);
+        List<AppTarget> appTargetList = new ArrayList<>();
+        shareTargets.forEach(t -> appTargetList.add(t.getAppTarget()));
+        callback.accept(appTargetList);
+    }
+
+    private void rankTargets(List<ShareTarget> shareTargets) {
+        // Rank targets based on recency of sharing history only for the moment.
+        // TODO: Take more factors into ranking, e.g. frequency, mime type, foreground app.
+        Collections.sort(shareTargets, (t1, t2) -> {
+            if (t1.getEventHistory() == null) {
+                return 1;
+            }
+            if (t2.getEventHistory() == null) {
+                return -1;
+            }
+            Range<Long> timeSlot1 = t1.getEventHistory().getEventIndex(
+                    Event.SHARE_EVENT_TYPES).getMostRecentActiveTimeSlot();
+            Range<Long> timeSlot2 = t2.getEventHistory().getEventIndex(
+                    Event.SHARE_EVENT_TYPES).getMostRecentActiveTimeSlot();
+            if (timeSlot1 == null) {
+                return 1;
+            } else if (timeSlot2 == null) {
+                return -1;
+            } else {
+                return -Long.compare(timeSlot1.getUpper(), timeSlot2.getUpper());
+            }
+        });
+    }
+
+    private List<ShareTarget> getDirectShareTargets() {
         List<ShareTarget> shareTargets = new ArrayList<>();
         List<ShareShortcutInfo> shareShortcuts =
                 getDataManager().getShareShortcuts(mIntentFilter, mCallingUserId);
 
         for (ShareShortcutInfo shareShortcut : shareShortcuts) {
             ShortcutInfo shortcutInfo = shareShortcut.getShortcutInfo();
+            AppTarget appTarget = new AppTarget.Builder(
+                    new AppTargetId(shortcutInfo.getId()),
+                    shortcutInfo)
+                    .setClassName(shareShortcut.getTargetComponent().getClassName())
+                    .build();
             String packageName = shortcutInfo.getPackage();
             int userId = shortcutInfo.getUserId();
             PackageData packageData = getDataManager().getPackage(packageName, userId);
 
-            ConversationData conversationData = null;
+            ConversationInfo conversationInfo = null;
+            EventHistory eventHistory = null;
             if (packageData != null) {
                 String shortcutId = shortcutInfo.getId();
-                ConversationInfo conversationInfo =
-                        packageData.getConversationInfo(shortcutId);
-
+                conversationInfo = packageData.getConversationInfo(shortcutId);
                 if (conversationInfo != null) {
-                    EventHistory eventHistory = packageData.getEventHistory(shortcutId);
-                    conversationData = new ConversationData(
-                            packageName, userId, conversationInfo, eventHistory);
+                    eventHistory = packageData.getEventHistory(shortcutId);
                 }
             }
-            shareTargets.add(new ShareTarget(shareShortcut, conversationData));
+            shareTargets.add(new ShareTarget(appTarget, eventHistory, conversationInfo));
         }
 
         return shareTargets;
     }
 
+    private List<ShareTarget> getAppShareTargets(List<AppTarget> targets) {
+        List<ShareTarget> shareTargets = new ArrayList<>();
+        for (AppTarget target : targets) {
+            PackageData packageData = getDataManager().getPackage(target.getPackageName(),
+                    target.getUser().getIdentifier());
+            shareTargets.add(new ShareTarget(target,
+                    packageData == null ? null
+                            : packageData.getClassLevelEventHistory(target.getClassName()), null));
+        }
+        return shareTargets;
+    }
+
     @VisibleForTesting
     static class ShareTarget {
 
         @NonNull
-        private final ShareShortcutInfo mShareShortcutInfo;
+        private final AppTarget mAppTarget;
         @Nullable
-        private final ConversationData mConversationData;
+        private final EventHistory mEventHistory;
+        @Nullable
+        private final ConversationInfo mConversationInfo;
 
-        private ShareTarget(@NonNull ShareShortcutInfo shareShortcutInfo,
-                @Nullable ConversationData conversationData) {
-            mShareShortcutInfo = shareShortcutInfo;
-            mConversationData = conversationData;
+        private ShareTarget(@NonNull AppTarget appTarget,
+                @Nullable EventHistory eventHistory,
+                @Nullable ConversationInfo conversationInfo) {
+            mAppTarget = appTarget;
+            mEventHistory = eventHistory;
+            mConversationInfo = conversationInfo;
         }
 
         @NonNull
         @VisibleForTesting
-        ShareShortcutInfo getShareShortcutInfo() {
-            return mShareShortcutInfo;
+        AppTarget getAppTarget() {
+            return mAppTarget;
         }
 
         @Nullable
         @VisibleForTesting
-        ConversationData getConversationData() {
-            return mConversationData;
+        EventHistory getEventHistory() {
+            return mEventHistory;
+        }
+
+        @Nullable
+        @VisibleForTesting
+        ConversationInfo getConversationInfo() {
+            return mConversationInfo;
         }
     }
 }
diff --git a/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java b/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java
index 6190802..fa0febd 100644
--- a/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java
+++ b/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java
@@ -46,8 +46,6 @@
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManagerInternal;
 import android.content.pm.ResolveInfo;
-import android.content.pm.parsing.AndroidPackage;
-import android.content.pm.parsing.PackageImpl;
 import android.os.Process;
 import android.os.UserHandle;
 import android.os.UserManager;
@@ -58,6 +56,9 @@
 import com.android.internal.util.FunctionalUtils.ThrowingRunnable;
 import com.android.internal.util.FunctionalUtils.ThrowingSupplier;
 import com.android.server.LocalServices;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.parsing.pkg.PackageImpl;
+import com.android.server.pm.parsing.pkg.ParsedPackage;
 import com.android.server.testing.shadows.ShadowApplicationPackageManager;
 import com.android.server.testing.shadows.ShadowUserManager;
 import com.android.server.wm.ActivityTaskManagerInternal;
@@ -135,7 +136,8 @@
                         eq(userId)))
                 .thenReturn(packageInfo);
         when(mPackageManagerInternal.getPackage(uid))
-                .thenReturn(PackageImpl.forParsing(CROSS_PROFILE_APP_PACKAGE_NAME));
+                .thenReturn(((ParsedPackage) PackageImpl.forTesting(CROSS_PROFILE_APP_PACKAGE_NAME)
+                        .hideAsParsed()).hideAsFinal());
     }
 
     private PackageInfo buildTestPackageInfo() {
@@ -497,7 +499,9 @@
 
     private void declareCrossProfileAttributeOnCrossProfileApp(boolean value) {
         mockCrossProfileAndroidPackage(
-                PackageImpl.forParsing(CROSS_PROFILE_APP_PACKAGE_NAME).setCrossProfile(value));
+                ((ParsedPackage) PackageImpl.forTesting(CROSS_PROFILE_APP_PACKAGE_NAME)
+                        .setCrossProfile(value)
+                        .hideAsParsed()).hideAsFinal());
     }
 
     private class TestInjector implements CrossProfileAppsServiceImpl.Injector {
diff --git a/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java
index 2d5fa23..959dc05 100644
--- a/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java
@@ -50,7 +50,6 @@
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.pm.PackageManagerInternal;
-import android.content.pm.parsing.AndroidPackage;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.Process;
@@ -63,6 +62,7 @@
 
 import com.android.dx.mockito.inline.extended.StaticMockitoSession;
 import com.android.server.LocalServices;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
 
 import org.junit.After;
 import org.junit.Before;
diff --git a/services/tests/mockingservicestests/src/com/android/server/blob/BlobStoreManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/blob/BlobStoreManagerServiceTest.java
index 3778e17..e5450a9 100644
--- a/services/tests/mockingservicestests/src/com/android/server/blob/BlobStoreManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/blob/BlobStoreManagerServiceTest.java
@@ -149,7 +149,7 @@
         final BlobMetadata blobMetadata2 = createBlobMetadataMock(blobId2, blobFile2, false);
         mUserBlobs.put(blobHandle2, blobMetadata2);
 
-        mService.addKnownIdsForTest(sessionId1, sessionId2, sessionId3, sessionId4,
+        mService.addActiveIdsForTest(sessionId1, sessionId2, sessionId3, sessionId4,
                 blobId1, blobId2);
 
         // Invoke test method
@@ -180,8 +180,10 @@
         assertThat(mUserBlobs.get(blobHandle1)).isNotNull();
         assertThat(mUserBlobs.get(blobHandle2)).isNull();
 
-        assertThat(mService.getKnownIdsForTest()).containsExactly(
+        assertThat(mService.getActiveIdsForTest()).containsExactly(
                 sessionId2, sessionId3, blobId1);
+        assertThat(mService.getKnownIdsForTest()).containsExactly(
+                sessionId1, sessionId2, sessionId3, sessionId4, blobId1, blobId2);
     }
 
     @Test
@@ -198,12 +200,12 @@
         doReturn(String.valueOf(testId3)).when(file3).getName();
 
         doReturn(new File[] {file1, file2, file3}).when(mBlobsDir).listFiles();
-        mService.addKnownIdsForTest(testId1, testId3);
+        mService.addActiveIdsForTest(testId1, testId3);
 
         // Invoke test method
         mService.handleIdleMaintenanceLocked();
 
-        // Verify unknown blobs are delete
+        // Verify unknown blobs are deleted
         verify(file1, never()).delete();
         verify(file2).delete();
         verify(file3, never()).delete();
@@ -242,7 +244,7 @@
                 sessionId3, sessionFile3, blobHandle3);
         mUserSessions.append(sessionId3, session3);
 
-        mService.addKnownIdsForTest(sessionId1, sessionId2, sessionId3);
+        mService.addActiveIdsForTest(sessionId1, sessionId2, sessionId3);
 
         // Invoke test method
         mService.handleIdleMaintenanceLocked();
@@ -255,7 +257,9 @@
         assertThat(mUserSessions.size()).isEqualTo(1);
         assertThat(mUserSessions.get(sessionId2)).isNotNull();
 
-        assertThat(mService.getKnownIdsForTest()).containsExactly(sessionId2);
+        assertThat(mService.getActiveIdsForTest()).containsExactly(sessionId2);
+        assertThat(mService.getKnownIdsForTest()).containsExactly(
+                sessionId1, sessionId2, sessionId3);
     }
 
     @Test
@@ -282,7 +286,7 @@
         final BlobMetadata blobMetadata3 = createBlobMetadataMock(blobId3, blobFile3, false);
         mUserBlobs.put(blobHandle3, blobMetadata3);
 
-        mService.addKnownIdsForTest(blobId1, blobId2, blobId3);
+        mService.addActiveIdsForTest(blobId1, blobId2, blobId3);
 
         // Invoke test method
         mService.handleIdleMaintenanceLocked();
@@ -295,7 +299,8 @@
         assertThat(mUserBlobs.size()).isEqualTo(1);
         assertThat(mUserBlobs.get(blobHandle2)).isNotNull();
 
-        assertThat(mService.getKnownIdsForTest()).containsExactly(blobId2);
+        assertThat(mService.getActiveIdsForTest()).containsExactly(blobId2);
+        assertThat(mService.getKnownIdsForTest()).containsExactly(blobId1, blobId2, blobId3);
     }
 
     private BlobStoreSession createBlobStoreSessionMock(String ownerPackageName, int ownerUid,
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java
index d7a3cfd..1bf9c2a 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java
@@ -73,7 +73,9 @@
     private static final double DELTA = 0.00001;
     private static final String TEST_PACKAGE = "job.test.package";
     private static final ComponentName TEST_JOB_COMPONENT = new ComponentName(TEST_PACKAGE, "test");
-    private static final Uri TEST_MEDIA_URI = Uri.parse("content://media/path/to/media");
+
+    private static final Uri IMAGES_MEDIA_URI = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
+    private static final Uri VIDEO_MEDIA_URI = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
 
     @Mock
     private JobSchedulerInternal mJobSchedulerInternal;
@@ -127,7 +129,7 @@
     @Test
     public void testMediaBackupExemption_lateConstraint() {
         final JobInfo triggerContentJob = new JobInfo.Builder(42, TEST_JOB_COMPONENT)
-                .addTriggerContentUri(new JobInfo.TriggerContentUri(TEST_MEDIA_URI, 0))
+                .addTriggerContentUri(new JobInfo.TriggerContentUri(IMAGES_MEDIA_URI, 0))
                 .setOverrideDeadline(12)
                 .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
                 .build();
@@ -138,7 +140,7 @@
     @Test
     public void testMediaBackupExemption_noConnectivityConstraint() {
         final JobInfo triggerContentJob = new JobInfo.Builder(42, TEST_JOB_COMPONENT)
-                .addTriggerContentUri(new JobInfo.TriggerContentUri(TEST_MEDIA_URI, 0))
+                .addTriggerContentUri(new JobInfo.TriggerContentUri(IMAGES_MEDIA_URI, 0))
                 .build();
         when(mJobSchedulerInternal.getMediaBackupPackage()).thenReturn(TEST_PACKAGE);
         assertEffectiveBucketForMediaExemption(createJobStatus(triggerContentJob), false);
@@ -156,7 +158,7 @@
     @Test
     public void testMediaBackupExemption_wrongSourcePackage() {
         final JobInfo networkContentJob = new JobInfo.Builder(42, TEST_JOB_COMPONENT)
-                .addTriggerContentUri(new JobInfo.TriggerContentUri(TEST_MEDIA_URI, 0))
+                .addTriggerContentUri(new JobInfo.TriggerContentUri(IMAGES_MEDIA_URI, 0))
                 .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
                 .build();
         when(mJobSchedulerInternal.getMediaBackupPackage()).thenReturn("not.test.package");
@@ -164,11 +166,12 @@
     }
 
     @Test
-    public void testMediaBackupExemption_nonMediaUri() {
-        final Uri nonMediaUri = Uri.parse("content://not-media/any/path");
+    public void testMediaBackupExemption_nonEligibleUri() {
+        final Uri nonEligibleUri = MediaStore.AUTHORITY_URI.buildUpon()
+                .appendPath("any_path").build();
         final JobInfo networkContentJob = new JobInfo.Builder(42, TEST_JOB_COMPONENT)
-                .addTriggerContentUri(new JobInfo.TriggerContentUri(TEST_MEDIA_URI, 0))
-                .addTriggerContentUri(new JobInfo.TriggerContentUri(nonMediaUri, 0))
+                .addTriggerContentUri(new JobInfo.TriggerContentUri(IMAGES_MEDIA_URI, 0))
+                .addTriggerContentUri(new JobInfo.TriggerContentUri(nonEligibleUri, 0))
                 .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
                 .build();
         when(mJobSchedulerInternal.getMediaBackupPackage()).thenReturn(TEST_PACKAGE);
@@ -177,12 +180,25 @@
 
     @Test
     public void testMediaBackupExemptionGranted() {
-        final JobInfo networkContentJob = new JobInfo.Builder(42, TEST_JOB_COMPONENT)
-                .addTriggerContentUri(new JobInfo.TriggerContentUri(TEST_MEDIA_URI, 0))
+        when(mJobSchedulerInternal.getMediaBackupPackage()).thenReturn(TEST_PACKAGE);
+        final JobInfo imageUriJob = new JobInfo.Builder(42, TEST_JOB_COMPONENT)
+                .addTriggerContentUri(new JobInfo.TriggerContentUri(IMAGES_MEDIA_URI, 0))
                 .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
                 .build();
-        when(mJobSchedulerInternal.getMediaBackupPackage()).thenReturn(TEST_PACKAGE);
-        assertEffectiveBucketForMediaExemption(createJobStatus(networkContentJob), true);
+        assertEffectiveBucketForMediaExemption(createJobStatus(imageUriJob), true);
+
+        final JobInfo videoUriJob = new JobInfo.Builder(42, TEST_JOB_COMPONENT)
+                .addTriggerContentUri(new JobInfo.TriggerContentUri(VIDEO_MEDIA_URI, 0))
+                .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
+                .build();
+        assertEffectiveBucketForMediaExemption(createJobStatus(videoUriJob), true);
+
+        final JobInfo bothUriJob = new JobInfo.Builder(42, TEST_JOB_COMPONENT)
+                .addTriggerContentUri(new JobInfo.TriggerContentUri(IMAGES_MEDIA_URI, 0))
+                .addTriggerContentUri(new JobInfo.TriggerContentUri(VIDEO_MEDIA_URI, 0))
+                .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
+                .build();
+        assertEffectiveBucketForMediaExemption(createJobStatus(bothUriJob), true);
     }
 
     @Test
diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp
index bf2b9be..d148c21 100644
--- a/services/tests/servicestests/Android.bp
+++ b/services/tests/servicestests/Android.bp
@@ -93,6 +93,7 @@
     },
 
     data: [":JobTestApp"],
+    resource_zips: [":FrameworksServicesTests_apks_as_resources"],
 }
 
 java_library {
@@ -115,3 +116,28 @@
         "src/com/android/server/pm/SuspendPackagesTest.java",
     ],
 }
+
+// Rules to copy all the test apks to the intermediate raw resource directory
+java_genrule {
+    name: "FrameworksServicesTests_apks_as_resources",
+    srcs: [
+        ":FrameworksCoreTests_install_complete_package_info",
+        ":FrameworksServicesTests_install_intent_filters",
+        ":FrameworksServicesTests_install_split_base",
+        ":FrameworksServicesTests_install_split_feature_a",
+        ":FrameworksServicesTests_install_uses_sdk_0",
+        ":FrameworksServicesTests_install_uses_sdk_q0",
+        ":FrameworksServicesTests_install_uses_sdk_r",
+        ":FrameworksServicesTests_install_uses_sdk_r0",
+        ":FrameworksServicesTests_install_uses_sdk_r5",
+    ],
+    out: ["FrameworkServicesTests_apks_as_resources.res.zip"],
+    tools: ["soong_zip"],
+
+    cmd: "mkdir -p $(genDir)/res/raw && " +
+        "for i in $(in); do " +
+        "  x=$${i##*FrameworksCoreTests_}; cp $$i $(genDir)/res/raw/$${x%.apk};" +
+        "  x=$${i##*FrameworksServicesTests_}; cp $$i $(genDir)/res/raw/$${x%.apk};" +
+        "done && " +
+        "$(location soong_zip) -o $(out) -C $(genDir)/res -D $(genDir)/res",
+}
diff --git a/services/tests/servicestests/apks/Android.bp b/services/tests/servicestests/apks/Android.bp
new file mode 100644
index 0000000..3e11604
--- /dev/null
+++ b/services/tests/servicestests/apks/Android.bp
@@ -0,0 +1,7 @@
+java_defaults {
+    name: "FrameworksServicesTests_apks_defaults",
+    sdk_version: "current",
+
+    // Every package should have a native library
+    jni_libs: ["libframeworks_coretests_jni"],
+}
diff --git a/services/tests/servicestests/apks/install-split-base/Android.bp b/services/tests/servicestests/apks/install-split-base/Android.bp
new file mode 100644
index 0000000..1b62aa2
--- /dev/null
+++ b/services/tests/servicestests/apks/install-split-base/Android.bp
@@ -0,0 +1,6 @@
+android_test_helper_app {
+    name: "FrameworksServicesTests_install_split_base",
+    defaults: ["FrameworksServicesTests_apks_defaults"],
+
+    srcs: ["**/*.java"],
+}
diff --git a/core/tests/coretests/apks/install-split-base/AndroidManifest.xml b/services/tests/servicestests/apks/install-split-base/AndroidManifest.xml
similarity index 93%
rename from core/tests/coretests/apks/install-split-base/AndroidManifest.xml
rename to services/tests/servicestests/apks/install-split-base/AndroidManifest.xml
index c2bfedd..2979395 100644
--- a/core/tests/coretests/apks/install-split-base/AndroidManifest.xml
+++ b/services/tests/servicestests/apks/install-split-base/AndroidManifest.xml
@@ -15,7 +15,7 @@
 -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-        package="com.android.frameworks.coretests.install_split"
+        package="com.android.frameworks.servicestests.install_split"
         android:isolatedSplits="true">
 
     <application android:label="ClassloaderSplitApp">
diff --git a/core/tests/coretests/apks/install-split-base/src/com/google/android/dexapis/splitapp/BaseActivity.java b/services/tests/servicestests/apks/install-split-base/src/com/google/android/dexapis/splitapp/BaseActivity.java
similarity index 100%
rename from core/tests/coretests/apks/install-split-base/src/com/google/android/dexapis/splitapp/BaseActivity.java
rename to services/tests/servicestests/apks/install-split-base/src/com/google/android/dexapis/splitapp/BaseActivity.java
diff --git a/core/tests/coretests/apks/install-split-feature-a/Android.bp b/services/tests/servicestests/apks/install-split-feature-a/Android.bp
similarity index 60%
rename from core/tests/coretests/apks/install-split-feature-a/Android.bp
rename to services/tests/servicestests/apks/install-split-feature-a/Android.bp
index 9ec9893..45d8917 100644
--- a/core/tests/coretests/apks/install-split-feature-a/Android.bp
+++ b/services/tests/servicestests/apks/install-split-feature-a/Android.bp
@@ -1,6 +1,6 @@
 android_test_helper_app {
-    name: "FrameworksCoreTests_install_split_feature_a",
-    defaults: ["FrameworksCoreTests_apks_defaults"],
+    name: "FrameworksServicesTests_install_split_feature_a",
+    defaults: ["FrameworksServicesTests_apks_defaults"],
 
     srcs: ["**/*.java"],
 
diff --git a/core/tests/coretests/apks/install-split-feature-a/AndroidManifest.xml b/services/tests/servicestests/apks/install-split-feature-a/AndroidManifest.xml
similarity index 93%
rename from core/tests/coretests/apks/install-split-feature-a/AndroidManifest.xml
rename to services/tests/servicestests/apks/install-split-feature-a/AndroidManifest.xml
index 3221c75..a3dd55f 100644
--- a/core/tests/coretests/apks/install-split-feature-a/AndroidManifest.xml
+++ b/services/tests/servicestests/apks/install-split-feature-a/AndroidManifest.xml
@@ -15,7 +15,7 @@
 -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-        package="com.android.frameworks.coretests.install_split"
+        package="com.android.frameworks.servicestests.install_split"
         featureSplit="feature_a">
 
     <application>
diff --git a/core/tests/coretests/apks/install-split-feature-a/src/com/google/android/dexapis/splitapp/feature_a/FeatureAActivity.java b/services/tests/servicestests/apks/install-split-feature-a/src/com/google/android/dexapis/splitapp/feature_a/FeatureAActivity.java
similarity index 100%
rename from core/tests/coretests/apks/install-split-feature-a/src/com/google/android/dexapis/splitapp/feature_a/FeatureAActivity.java
rename to services/tests/servicestests/apks/install-split-feature-a/src/com/google/android/dexapis/splitapp/feature_a/FeatureAActivity.java
diff --git a/services/tests/servicestests/apks/install_intent_filters/Android.bp b/services/tests/servicestests/apks/install_intent_filters/Android.bp
new file mode 100644
index 0000000..59c8524
--- /dev/null
+++ b/services/tests/servicestests/apks/install_intent_filters/Android.bp
@@ -0,0 +1,7 @@
+android_test_helper_app {
+    name: "FrameworksServicesTests_install_intent_filters",
+    defaults: ["FrameworksServicesTests_apks_defaults"],
+
+    srcs: ["**/*.java"],
+}
+
diff --git a/core/tests/coretests/apks/install_intent_filters/AndroidManifest.xml b/services/tests/servicestests/apks/install_intent_filters/AndroidManifest.xml
similarity index 87%
rename from core/tests/coretests/apks/install_intent_filters/AndroidManifest.xml
rename to services/tests/servicestests/apks/install_intent_filters/AndroidManifest.xml
index d7ee76e..fc7134d2 100644
--- a/core/tests/coretests/apks/install_intent_filters/AndroidManifest.xml
+++ b/services/tests/servicestests/apks/install_intent_filters/AndroidManifest.xml
@@ -16,7 +16,7 @@
   -->
 <manifest
     xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.frameworks.coretests.install_intent_filters">
+    package="com.android.frameworks.servicestests.install_intent_filters">
 
 <!--
      This manifest declares an activity for testing intent filters.
@@ -24,7 +24,7 @@
 -->
 
     <uses-feature
-        android:name="com.android.frameworks.coretests.nonexistent" />
+        android:name="com.android.frameworks.servicestests.nonexistent" />
     <uses-configuration
         android:reqFiveWayNav="false" />
 
@@ -41,7 +41,7 @@
     <application
         android:hasCode="true">
         <activity
-            android:name="com.android.frameworks.coretests.TestActivity">
+            android:name="com.android.frameworks.servicestests.TestActivity">
             <intent-filter>
                 <action android:name="action1"/>
                 <data android:mimeGroup="mime_group_1"/>
diff --git a/core/tests/coretests/apks/install_intent_filters/src/com/android/frameworks/coretests/TestActivity.java b/services/tests/servicestests/apks/install_intent_filters/src/com/android/frameworks/servicestests/TestActivity.java
similarity index 100%
rename from core/tests/coretests/apks/install_intent_filters/src/com/android/frameworks/coretests/TestActivity.java
rename to services/tests/servicestests/apks/install_intent_filters/src/com/android/frameworks/servicestests/TestActivity.java
diff --git a/services/tests/servicestests/apks/install_uses_sdk/Android.bp b/services/tests/servicestests/apks/install_uses_sdk/Android.bp
new file mode 100644
index 0000000..c24aa2b
--- /dev/null
+++ b/services/tests/servicestests/apks/install_uses_sdk/Android.bp
@@ -0,0 +1,39 @@
+android_test_helper_app {
+    name: "FrameworksServicesTests_install_uses_sdk_r0",
+    defaults: ["FrameworksServicesTests_apks_defaults"],
+    manifest: "AndroidManifest-r0.xml",
+
+    srcs: ["**/*.java"],
+}
+
+android_test_helper_app {
+    name: "FrameworksServicesTests_install_uses_sdk_r5",
+    defaults: ["FrameworksServicesTests_apks_defaults"],
+    manifest: "AndroidManifest-r5.xml",
+
+    srcs: ["**/*.java"],
+}
+
+android_test_helper_app {
+    name: "FrameworksServicesTests_install_uses_sdk_q0",
+    defaults: ["FrameworksServicesTests_apks_defaults"],
+    manifest: "AndroidManifest-q0.xml",
+
+    srcs: ["**/*.java"],
+}
+
+android_test_helper_app {
+    name: "FrameworksServicesTests_install_uses_sdk_r",
+    defaults: ["FrameworksServicesTests_apks_defaults"],
+    manifest: "AndroidManifest-r.xml",
+
+    srcs: ["**/*.java"],
+}
+
+android_test_helper_app {
+    name: "FrameworksServicesTests_install_uses_sdk_0",
+    defaults: ["FrameworksServicesTests_apks_defaults"],
+    manifest: "AndroidManifest-0.xml",
+
+    srcs: ["**/*.java"],
+}
diff --git a/core/tests/coretests/apks/install_uses_sdk/AndroidManifest-0.xml b/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-0.xml
similarity index 92%
rename from core/tests/coretests/apks/install_uses_sdk/AndroidManifest-0.xml
rename to services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-0.xml
index 634228b..215384b 100644
--- a/core/tests/coretests/apks/install_uses_sdk/AndroidManifest-0.xml
+++ b/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-0.xml
@@ -14,7 +14,7 @@
      limitations under the License.
 -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-        package="com.android.frameworks.coretests.install_uses_sdk">
+        package="com.android.frameworks.servicestests.install_uses_sdk">
 
     <uses-sdk android:minSdkVersion="4" android:targetSdkVersion="29">
         <!-- This is invalid, because there is no sdk version specified -->
diff --git a/core/tests/coretests/apks/install_uses_sdk/AndroidManifest-q0.xml b/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-q0.xml
similarity index 93%
rename from core/tests/coretests/apks/install_uses_sdk/AndroidManifest-q0.xml
rename to services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-q0.xml
index 8994966..c0e5867 100644
--- a/core/tests/coretests/apks/install_uses_sdk/AndroidManifest-q0.xml
+++ b/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-q0.xml
@@ -14,7 +14,7 @@
      limitations under the License.
 -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-        package="com.android.frameworks.coretests.install_uses_sdk">
+        package="com.android.frameworks.servicestests.install_uses_sdk">
 
     <uses-sdk android:minSdkVersion="4" android:targetSdkVersion="29">
         <!-- This fails because 29 doesn't have an extension sdk -->
diff --git a/core/tests/coretests/apks/install_uses_sdk/AndroidManifest-r.xml b/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r.xml
similarity index 93%
rename from core/tests/coretests/apks/install_uses_sdk/AndroidManifest-r.xml
rename to services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r.xml
index 0d0d8b9..5d22577 100644
--- a/core/tests/coretests/apks/install_uses_sdk/AndroidManifest-r.xml
+++ b/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r.xml
@@ -14,7 +14,7 @@
      limitations under the License.
 -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-        package="com.android.frameworks.coretests.install_uses_sdk">
+        package="com.android.frameworks.servicestests.install_uses_sdk">
 
     <uses-sdk android:minSdkVersion="4" android:targetSdkVersion="29">
         <!-- This is invalid, because there is no minimum extension version specified -->
diff --git a/core/tests/coretests/apks/install_uses_sdk/AndroidManifest-r0.xml b/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r0.xml
similarity index 92%
rename from core/tests/coretests/apks/install_uses_sdk/AndroidManifest-r0.xml
rename to services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r0.xml
index a987afa..c1244f2 100644
--- a/core/tests/coretests/apks/install_uses_sdk/AndroidManifest-r0.xml
+++ b/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r0.xml
@@ -14,7 +14,7 @@
      limitations under the License.
 -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-        package="com.android.frameworks.coretests.install_uses_sdk">
+        package="com.android.frameworks.servicestests.install_uses_sdk">
 
     <uses-sdk android:minSdkVersion="4" android:targetSdkVersion="29">
         <extension-sdk android:sdkVersion="10000" android:minExtensionVersion="0" />
diff --git a/core/tests/coretests/apks/install_uses_sdk/AndroidManifest-r5.xml b/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r5.xml
similarity index 93%
rename from core/tests/coretests/apks/install_uses_sdk/AndroidManifest-r5.xml
rename to services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r5.xml
index 9860096..3410938 100644
--- a/core/tests/coretests/apks/install_uses_sdk/AndroidManifest-r5.xml
+++ b/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r5.xml
@@ -14,7 +14,7 @@
      limitations under the License.
 -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-        package="com.android.frameworks.coretests.install_uses_sdk">
+        package="com.android.frameworks.servicestests.install_uses_sdk">
 
     <uses-sdk android:minSdkVersion="4" android:targetSdkVersion="29">
         <!-- This will fail to install, because minExtensionVersion is not met -->
diff --git a/core/tests/coretests/apks/install_uses_sdk/res/values/strings.xml b/services/tests/servicestests/apks/install_uses_sdk/res/values/strings.xml
similarity index 100%
rename from core/tests/coretests/apks/install_uses_sdk/res/values/strings.xml
rename to services/tests/servicestests/apks/install_uses_sdk/res/values/strings.xml
diff --git a/core/tests/coretests/res/raw/com_android_tzdata.apex b/services/tests/servicestests/res/raw/com_android_tzdata.apex
similarity index 100%
rename from core/tests/coretests/res/raw/com_android_tzdata.apex
rename to services/tests/servicestests/res/raw/com_android_tzdata.apex
Binary files differ
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java b/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java
index 1c8b00f..30bb38a 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java
@@ -111,6 +111,29 @@
                 any());
     }
 
+    @Test
+    public void testRegisterAuthenticator_callsInitConfiguredStrength() throws Exception {
+
+        final String[] config = {
+                "0:2:15", // ID0:Fingerprint:Strong
+                "1:4:255", // ID1:Iris:Weak
+                "2:8:4095", // ID2:Face:Convenience
+        };
+
+        when(mInjector.getConfiguration(any())).thenReturn(config);
+
+        mAuthService = new AuthService(mContext, mInjector);
+        mAuthService.onStart();
+
+        final int fingerprintStrength = 15;
+        final int irisStrength = 255;
+        final int faceStrength = 4095;
+
+        verify(mFingerprintService).initConfiguredStrength(eq(fingerprintStrength));
+        verify(mIrisService).initConfiguredStrength(eq(irisStrength));
+        verify(mFaceService).initConfiguredStrength(eq(faceStrength));
+    }
+
 
     // TODO(b/141025588): Check that an exception is thrown when the userId != callingUserId
     @Test
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index dbf2f14..ac818ea 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -3952,13 +3952,8 @@
     }
 
     public void testIsOrganizationOwnedDevice() throws Exception {
-        setupProfileOwner();
         // Set up the user manager to return correct user info
-        UserInfo managedProfileUserInfo = new UserInfo(DpmMockContext.CALLER_USER_HANDLE,
-                "managed profile",
-                UserInfo.FLAG_MANAGED_PROFILE);
-        when(getServices().userManager.getUsers())
-                .thenReturn(Arrays.asList(managedProfileUserInfo));
+        addManagedProfile(admin1, DpmMockContext.CALLER_UID, admin1);
 
         // Any caller should be able to call this method.
         assertFalse(dpm.isOrganizationOwnedDeviceWithManagedProfile());
@@ -5909,8 +5904,6 @@
     }
 
     private void configureProfileOwnerOfOrgOwnedDevice(ComponentName who, int userId) {
-        when(getServices().userManager.getProfileParent(eq(UserHandle.of(userId))))
-                .thenReturn(UserHandle.SYSTEM);
         final long ident = mServiceContext.binder.clearCallingIdentity();
         mServiceContext.binder.callingUid = UserHandle.getUid(userId, DpmMockContext.SYSTEM_UID);
 
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
index 37d4081..01f1a3e 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
@@ -265,6 +265,9 @@
                             .toArray();
                 }
         );
+        when(userManagerInternal.getUserInfos()).thenReturn(
+                mUserInfos.toArray(new UserInfo[mUserInfos.size()]));
+
         when(accountManager.getAccountsAsUser(anyInt())).thenReturn(new Account[0]);
 
         // Create a data directory.
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/SecurityEventTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/SecurityEventTest.java
index 0f05212..8dcf21f 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/SecurityEventTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/SecurityEventTest.java
@@ -1,31 +1,43 @@
 package com.android.server.devicepolicy;
 
 import static android.app.admin.SecurityLog.TAG_ADB_SHELL_CMD;
+import static android.app.admin.SecurityLog.TAG_APP_PROCESS_START;
+import static android.app.admin.SecurityLog.TAG_CERT_AUTHORITY_INSTALLED;
+import static android.app.admin.SecurityLog.TAG_CERT_AUTHORITY_REMOVED;
+import static android.app.admin.SecurityLog.TAG_KEY_DESTRUCTION;
+import static android.app.admin.SecurityLog.TAG_KEY_GENERATED;
+import static android.app.admin.SecurityLog.TAG_KEY_IMPORT;
+import static android.app.admin.SecurityLog.TAG_KEY_INTEGRITY_VIOLATION;
+import static android.app.admin.SecurityLog.TAG_MEDIA_MOUNT;
+import static android.app.admin.SecurityLog.TAG_MEDIA_UNMOUNT;
 
 import android.app.admin.SecurityLog.SecurityEvent;
 import android.os.Parcel;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.os.UserHandle;
+import android.text.TextUtils;
 import android.util.EventLog;
+import android.util.EventLog.Event;
 
-import java.io.IOException;
+import junit.framework.AssertionFailedError;
+
 import java.util.ArrayList;
 import java.util.List;
 
-@SmallTest
 public class SecurityEventTest extends DpmTestBase {
-    private static long ID = 549;
-    private static String DATA = "adb shell some_command";
 
-    public void testSecurityEventId() {
-        SecurityEvent event = buildSecurityEvents(1 /* generate a single event */, ID).get(0);
-        assertEquals(ID, event.getId());
+    public void testSecurityEventId() throws Exception {
+        SecurityEvent event = createEvent(() -> {
+            EventLog.writeEvent(TAG_ADB_SHELL_CMD, 0);
+        }, TAG_ADB_SHELL_CMD);
         event.setId(20);
         assertEquals(20, event.getId());
     }
 
-    public void testSecurityEventParceling() {
+    public void testSecurityEventParceling() throws Exception {
         // GIVEN an event.
-        SecurityEvent event = buildSecurityEvents(1 /* generate a single event */, ID).get(0);
+        SecurityEvent event = createEvent(() -> {
+            EventLog.writeEvent(TAG_ADB_SHELL_CMD, "test");
+        }, TAG_ADB_SHELL_CMD);
         // WHEN parceling the event.
         Parcel p = Parcel.obtain();
         p.writeParcelable(event, 0);
@@ -39,23 +51,104 @@
         assertEquals(event.getId(), unparceledEvent.getId());
     }
 
-    private List<SecurityEvent> buildSecurityEvents(int numEvents, long id) {
-        // Write an event to the EventLog.
-        for (int i = 0; i < numEvents; i++) {
-            EventLog.writeEvent(TAG_ADB_SHELL_CMD, DATA + "_" + i);
+    public void testSecurityEventRedaction() throws Exception {
+        SecurityEvent event;
+
+        // TAG_ADB_SHELL_CMD will has the command redacted
+        event = createEvent(() -> {
+            EventLog.writeEvent(TAG_ADB_SHELL_CMD, "command");
+        }, TAG_ADB_SHELL_CMD);
+        assertFalse(TextUtils.isEmpty((String) event.getData()));
+
+        // TAG_MEDIA_MOUNT will have the volume label redacted (second data)
+        event = createEvent(() -> {
+            EventLog.writeEvent(TAG_MEDIA_MOUNT, new Object[] {"path", "label"});
+        }, TAG_MEDIA_MOUNT);
+        assertFalse(TextUtils.isEmpty(event.getStringData(1)));
+        assertTrue(TextUtils.isEmpty(event.redact(0).getStringData(1)));
+
+        // TAG_MEDIA_UNMOUNT will have the volume label redacted (second data)
+        event = createEvent(() -> {
+            EventLog.writeEvent(TAG_MEDIA_UNMOUNT, new Object[] {"path", "label"});
+        }, TAG_MEDIA_UNMOUNT);
+        assertFalse(TextUtils.isEmpty(event.getStringData(1)));
+        assertTrue(TextUtils.isEmpty(event.redact(0).getStringData(1)));
+
+        // TAG_APP_PROCESS_START will be fully redacted if user does not match
+        event = createEvent(() -> {
+            EventLog.writeEvent(TAG_APP_PROCESS_START, new Object[] {"process", 12345L,
+                    UserHandle.getUid(10, 123), 456, "seinfo", "hash"});
+        }, TAG_APP_PROCESS_START);
+        assertNotNull(event.redact(10));
+        assertNull(event.redact(11));
+
+        // TAG_CERT_AUTHORITY_INSTALLED will be fully redacted if user does not match
+        event = createEvent(() -> {
+            EventLog.writeEvent(TAG_CERT_AUTHORITY_INSTALLED, new Object[] {1, "subject", 10});
+        }, TAG_CERT_AUTHORITY_INSTALLED);
+        assertNotNull(event.redact(10));
+        assertNull(event.redact(11));
+
+        // TAG_CERT_AUTHORITY_REMOVED will be fully redacted if user does not match
+        event = createEvent(() -> {
+            EventLog.writeEvent(TAG_CERT_AUTHORITY_REMOVED, new Object[] {1, "subject", 20});
+        }, TAG_CERT_AUTHORITY_REMOVED);
+        assertNotNull(event.redact(20));
+        assertNull(event.redact(0));
+
+        // TAG_KEY_GENERATED will be fully redacted if user does not match
+        event = createEvent(() -> {
+            EventLog.writeEvent(TAG_KEY_GENERATED,
+                    new Object[] {1, "alias", UserHandle.getUid(0, 123)});
+        }, TAG_KEY_GENERATED);
+        assertNotNull(event.redact(0));
+        assertNull(event.redact(10));
+
+        // TAG_KEY_IMPORT will be fully redacted if user does not match
+        event = createEvent(() -> {
+            EventLog.writeEvent(TAG_KEY_IMPORT,
+                    new Object[] {1, "alias", UserHandle.getUid(1, 123)});
+        }, TAG_KEY_IMPORT);
+        assertNotNull(event.redact(1));
+        assertNull(event.redact(10));
+
+        // TAG_KEY_DESTRUCTION will be fully redacted if user does not match
+        event = createEvent(() -> {
+            EventLog.writeEvent(TAG_KEY_DESTRUCTION,
+                    new Object[] {1, "alias", UserHandle.getUid(2, 123)});
+        }, TAG_KEY_DESTRUCTION);
+        assertNotNull(event.redact(2));
+        assertNull(event.redact(10));
+
+        // TAG_KEY_INTEGRITY_VIOLATION will be fully redacted if user does not match
+        event = createEvent(() -> {
+            EventLog.writeEvent(TAG_KEY_INTEGRITY_VIOLATION,
+                    new Object[] {"alias", UserHandle.getUid(2, 123)});
+        }, TAG_KEY_INTEGRITY_VIOLATION);
+        assertNotNull(event.redact(2));
+        assertNull(event.redact(10));
+
+    }
+
+    /**
+     * Creates an Event object. Only the native code has the serialization and deserialization logic
+     * so need to actually emit a real log in order to generate the object.
+     */
+    private SecurityEvent createEvent(Runnable generator, int expectedTag) throws Exception {
+        Long markerData = System.currentTimeMillis();
+        EventLog.writeEvent(expectedTag, markerData);
+        generator.run();
+
+        List<Event> events = new ArrayList<>();
+        // Give the message some time to show up in the log
+        Thread.sleep(20);
+        EventLog.readEvents(new int[] {expectedTag}, events);
+
+        for (int i = 0; i < events.size() - 1; i++) {
+            if (markerData.equals(events.get(i).getData())) {
+                return new SecurityEvent(0, events.get(i + 1).getBytes());
+            }
         }
-        List<EventLog.Event> events = new ArrayList<>();
-        try {
-            EventLog.readEvents(new int[]{TAG_ADB_SHELL_CMD}, events);
-        } catch (IOException e) {
-            fail("Reading a test event from storage failed: " + e);
-        }
-        assertTrue("Unexpected number of events read from the log.", events.size() >= numEvents);
-        // Read events generated by test, from the end of the log.
-        List<SecurityEvent> securityEvents = new ArrayList<>();
-        for (int i = events.size() - numEvents; i < events.size(); i++) {
-          securityEvents.add(new SecurityEvent(id++, events.get(i).getBytes()));
-        }
-        return securityEvents;
+        throw new AssertionFailedError("Unable to locate marker event");
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
index 25d0778..feae1e1 100644
--- a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
@@ -29,6 +29,12 @@
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.server.display.DisplayModeDirector.DesiredDisplayModeSpecs;
+import com.android.server.display.DisplayModeDirector.RefreshRateRange;
+import com.android.server.display.DisplayModeDirector.Vote;
+
+import com.google.common.truth.Truth;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -37,6 +43,9 @@
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class DisplayModeDirectorTest {
+    // The tolerance within which we consider something approximately equals.
+    private static final float FLOAT_TOLERANCE = 0.01f;
+
     private Context mContext;
 
     @Before
@@ -56,30 +65,22 @@
             modes[i - minFps] = new Display.Mode(
                     /*modeId=*/i, /*width=*/1000, /*height=*/1000, /*refreshRate=*/i);
         }
-        SparseArray<Display.Mode[]> supportedModesByDisplay = new SparseArray<Display.Mode[]>();
+        SparseArray<Display.Mode[]> supportedModesByDisplay = new SparseArray<>();
         supportedModesByDisplay.put(displayId, modes);
         director.injectSupportedModesByDisplay(supportedModesByDisplay);
-        SparseArray<Display.Mode> defaultModesByDisplay = new SparseArray<Display.Mode>();
+        SparseArray<Display.Mode> defaultModesByDisplay = new SparseArray<>();
         defaultModesByDisplay.put(displayId, modes[0]);
         director.injectDefaultModeByDisplay(defaultModesByDisplay);
         return director;
     }
 
-    private int[] intRange(int min, int max) {
-        int[] range = new int[max - min + 1];
-        for (int i = min; i <= max; i++) {
-            range[i - min] = i;
-        }
-        return range;
-    }
-
     @Test
     public void testDisplayModeVoting() {
         int displayId = 0;
 
         // With no votes present, DisplayModeDirector should allow any refresh rate.
-        assertEquals(new DisplayModeDirector.DesiredDisplayModeSpecs(/*baseModeId=*/60,
-                             new DisplayModeDirector.RefreshRateRange(0f, Float.POSITIVE_INFINITY)),
+        assertEquals(new DesiredDisplayModeSpecs(/*baseModeId=*/60,
+                             new RefreshRateRange(0f, Float.POSITIVE_INFINITY)),
                 createDisplayModeDirectorWithDisplayFpsRange(60, 90).getDesiredDisplayModeSpecs(
                         displayId));
 
@@ -93,20 +94,16 @@
             int maxFps = 90;
             DisplayModeDirector director = createDisplayModeDirectorWithDisplayFpsRange(60, 90);
             assertTrue(2 * numPriorities < maxFps - minFps + 1);
-            SparseArray<DisplayModeDirector.Vote> votes =
-                    new SparseArray<DisplayModeDirector.Vote>();
-            SparseArray<SparseArray<DisplayModeDirector.Vote>> votesByDisplay =
-                    new SparseArray<SparseArray<DisplayModeDirector.Vote>>();
+            SparseArray<Vote> votes = new SparseArray<>();
+            SparseArray<SparseArray<Vote>> votesByDisplay = new SparseArray<>();
             votesByDisplay.put(displayId, votes);
             for (int i = 0; i < numPriorities; i++) {
-                int priority = DisplayModeDirector.Vote.MIN_PRIORITY + i;
-                votes.put(
-                        priority, DisplayModeDirector.Vote.forRefreshRates(minFps + i, maxFps - i));
+                int priority = Vote.MIN_PRIORITY + i;
+                votes.put(priority, Vote.forRefreshRates(minFps + i, maxFps - i));
                 director.injectVotesByDisplay(votesByDisplay);
-                assertEquals(
-                        new DisplayModeDirector.DesiredDisplayModeSpecs(
+                assertEquals(new DesiredDisplayModeSpecs(
                                 /*baseModeId=*/minFps + i,
-                                new DisplayModeDirector.RefreshRateRange(minFps + i, maxFps - i)),
+                                new RefreshRateRange(minFps + i, maxFps - i)),
                         director.getDesiredDisplayModeSpecs(displayId));
             }
         }
@@ -116,19 +113,35 @@
         {
             assertTrue(numPriorities >= 2);
             DisplayModeDirector director = createDisplayModeDirectorWithDisplayFpsRange(60, 90);
-            SparseArray<DisplayModeDirector.Vote> votes =
-                    new SparseArray<DisplayModeDirector.Vote>();
-            SparseArray<SparseArray<DisplayModeDirector.Vote>> votesByDisplay =
-                    new SparseArray<SparseArray<DisplayModeDirector.Vote>>();
+            SparseArray<Vote> votes = new SparseArray<>();
+            SparseArray<SparseArray<Vote>> votesByDisplay = new SparseArray<>();
             votesByDisplay.put(displayId, votes);
-            votes.put(DisplayModeDirector.Vote.MAX_PRIORITY,
-                    DisplayModeDirector.Vote.forRefreshRates(65, 85));
-            votes.put(DisplayModeDirector.Vote.MIN_PRIORITY,
-                    DisplayModeDirector.Vote.forRefreshRates(70, 80));
+            votes.put(Vote.MAX_PRIORITY, Vote.forRefreshRates(65, 85));
+            votes.put(Vote.MIN_PRIORITY, Vote.forRefreshRates(70, 80));
             director.injectVotesByDisplay(votesByDisplay);
-            assertEquals(new DisplayModeDirector.DesiredDisplayModeSpecs(/*baseModeId=*/70,
-                                 new DisplayModeDirector.RefreshRateRange(70, 80)),
+            assertEquals(new DesiredDisplayModeSpecs(/*baseModeId=*/70,
+                                 new RefreshRateRange(70, 80)),
                     director.getDesiredDisplayModeSpecs(displayId));
         }
     }
+
+    @Test
+    public void testVotingWithFloatingPointErrors() {
+        int displayId = 0;
+        DisplayModeDirector director = createDisplayModeDirectorWithDisplayFpsRange(50, 90);
+        SparseArray<Vote> votes = new SparseArray<>();
+        SparseArray<SparseArray<Vote>> votesByDisplay = new SparseArray<>();
+        votesByDisplay.put(displayId, votes);
+        float error = FLOAT_TOLERANCE / 4;
+        votes.put(Vote.PRIORITY_USER_SETTING_PEAK_REFRESH_RATE, Vote.forRefreshRates(0, 60));
+        votes.put(Vote.PRIORITY_APP_REQUEST_SIZE, Vote.forRefreshRates(60 + error, 60 + error));
+        votes.put(Vote.PRIORITY_APP_REQUEST_REFRESH_RATE,
+                Vote.forRefreshRates(60 - error, 60 - error));
+        director.injectVotesByDisplay(votesByDisplay);
+        DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(displayId);
+
+        Truth.assertThat(desiredSpecs.refreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(60);
+        Truth.assertThat(desiredSpecs.refreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(60);
+        Truth.assertThat(desiredSpecs.baseModeId).isEqualTo(60);
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/integrity/parser/RuleBinaryParserTest.java b/services/tests/servicestests/src/com/android/server/integrity/parser/RuleBinaryParserTest.java
index 3dc26af..ab21ab0 100644
--- a/services/tests/servicestests/src/com/android/server/integrity/parser/RuleBinaryParserTest.java
+++ b/services/tests/servicestests/src/com/android/server/integrity/parser/RuleBinaryParserTest.java
@@ -73,7 +73,7 @@
     private static final String APP_CERTIFICATE = getBits(AtomicFormula.APP_CERTIFICATE, KEY_BITS);
     private static final String VERSION_CODE = getBits(AtomicFormula.VERSION_CODE, KEY_BITS);
     private static final String PRE_INSTALLED = getBits(AtomicFormula.PRE_INSTALLED, KEY_BITS);
-    private static final int INVALID_KEY_VALUE = 6;
+    private static final int INVALID_KEY_VALUE = 8;
     private static final String INVALID_KEY = getBits(INVALID_KEY_VALUE, KEY_BITS);
 
     private static final String EQ = getBits(AtomicFormula.EQ, OPERATOR_BITS);
diff --git a/services/tests/servicestests/src/com/android/server/location/MockableLocationProviderTest.java b/services/tests/servicestests/src/com/android/server/location/MockableLocationProviderTest.java
index 6fafe11..9b076e8 100644
--- a/services/tests/servicestests/src/com/android/server/location/MockableLocationProviderTest.java
+++ b/services/tests/servicestests/src/com/android/server/location/MockableLocationProviderTest.java
@@ -118,16 +118,6 @@
     }
 
     @Test
-    public void testRequestSetAllowed() {
-        mProvider.requestSetAllowed(true);
-        verify(mRealProvider, times(1)).onRequestSetAllowed(true);
-
-        mProvider.setMockProvider(mMockProvider);
-        mProvider.requestSetAllowed(true);
-        verify(mMockProvider, times(1)).onRequestSetAllowed(true);
-    }
-
-    @Test
     public void testSendExtraCommand() {
         mProvider.sendExtraCommand(0, 0, "command", null);
         verify(mRealProvider, times(1)).onExtraCommand(0, 0, "command", null);
diff --git a/services/tests/servicestests/src/com/android/server/location/test/FakeProvider.java b/services/tests/servicestests/src/com/android/server/location/test/FakeProvider.java
index 762080f..5943f67 100644
--- a/services/tests/servicestests/src/com/android/server/location/test/FakeProvider.java
+++ b/services/tests/servicestests/src/com/android/server/location/test/FakeProvider.java
@@ -38,8 +38,5 @@
     protected void onExtraCommand(int uid, int pid, String command, Bundle extras) {}
 
     @Override
-    protected void onRequestSetAllowed(boolean allowed) {}
-
-    @Override
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {}
 }
diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayReferenceMapperTests.kt b/services/tests/servicestests/src/com/android/server/om/OverlayReferenceMapperTests.kt
index ef12948..063cd5da 100644
--- a/services/tests/servicestests/src/com/android/server/om/OverlayReferenceMapperTests.kt
+++ b/services/tests/servicestests/src/com/android/server/om/OverlayReferenceMapperTests.kt
@@ -16,8 +16,8 @@
 
 package com.android.server.om
 
-import android.content.pm.parsing.AndroidPackage
 import android.net.Uri
+import com.android.server.pm.parsing.pkg.AndroidPackage
 import com.google.common.truth.Truth.assertThat
 import org.junit.Before
 import org.junit.Test
@@ -196,11 +196,13 @@
         whenever(packageName) { "$TARGET_PACKAGE_NAME$increment" }
         whenever(overlayables) { mapOf("overlayableName$increment" to ACTOR_NAME) }
         whenever(toString()) { "Package{$packageName}" }
+        whenever(isOverlay) { false }
     }
 
     private fun mockOverlay(increment: Int = 0) = mockThrowOnUnmocked<AndroidPackage> {
         whenever(packageName) { "$OVERLAY_PACKAGE_NAME$increment" }
         whenever(overlayables) { emptyMap<String, String>() }
         whenever(toString()) { "Package{$packageName}" }
+        whenever(isOverlay) { true }
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/people/data/AggregateEventHistoryImplTest.java b/services/tests/servicestests/src/com/android/server/people/data/AggregateEventHistoryImplTest.java
index b614a4f..443718d 100644
--- a/services/tests/servicestests/src/com/android/server/people/data/AggregateEventHistoryImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/people/data/AggregateEventHistoryImplTest.java
@@ -21,11 +21,16 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
+import android.content.Context;
+
+import androidx.test.InstrumentationRegistry;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
 
+import java.io.File;
 import java.util.List;
 
 @RunWith(JUnit4.class)
@@ -60,11 +65,16 @@
 
         EventHistoryImpl.Injector injector = new EventHistoryImplInjector();
 
-        mEventHistory1 = new EventHistoryImpl(injector);
+        Context ctx = InstrumentationRegistry.getContext();
+        File testDir = new File(ctx.getCacheDir(), "testdir");
+        MockScheduledExecutorService mockScheduledExecutorService =
+                new MockScheduledExecutorService();
+
+        mEventHistory1 = new EventHistoryImpl(injector, testDir, mockScheduledExecutorService);
         mEventHistory1.addEvent(E1);
         mEventHistory1.addEvent(E2);
 
-        mEventHistory2 = new EventHistoryImpl(injector);
+        mEventHistory2 = new EventHistoryImpl(injector, testDir, mockScheduledExecutorService);
         mEventHistory2.addEvent(E3);
         mEventHistory2.addEvent(E4);
     }
diff --git a/services/tests/servicestests/src/com/android/server/people/data/ConversationStoreTest.java b/services/tests/servicestests/src/com/android/server/people/data/ConversationStoreTest.java
index 03b5e38..d138700 100644
--- a/services/tests/servicestests/src/com/android/server/people/data/ConversationStoreTest.java
+++ b/services/tests/servicestests/src/com/android/server/people/data/ConversationStoreTest.java
@@ -21,7 +21,6 @@
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
-import android.annotation.Nullable;
 import android.content.Context;
 import android.content.LocusId;
 import android.content.pm.ShortcutInfo;
@@ -63,7 +62,6 @@
     private static final String PHONE_NUMBER_3 = "+9234567890";
 
     private MockScheduledExecutorService mMockScheduledExecutorService;
-    private TestContactQueryHelper mTestContactQueryHelper;
     private ConversationStore mConversationStore;
     private File mFile;
 
@@ -71,7 +69,6 @@
     public void setUp() {
         Context ctx = InstrumentationRegistry.getContext();
         mFile = new File(ctx.getCacheDir(), "testdir");
-        mTestContactQueryHelper = new TestContactQueryHelper(ctx);
         resetConversationStore();
     }
 
@@ -207,9 +204,6 @@
         mConversationStore.deleteConversation(SHORTCUT_ID_3);
         mMockScheduledExecutorService.fastForwardTime(3L * DateUtils.MINUTE_IN_MILLIS);
 
-        mTestContactQueryHelper.setQueryResult(true, true);
-        mTestContactQueryHelper.setPhoneNumberResult(PHONE_NUMBER, PHONE_NUMBER_2);
-
         resetConversationStore();
         ConversationInfo out1 = mConversationStore.getConversation(SHORTCUT_ID);
         ConversationInfo out2 = mConversationStore.getConversation(SHORTCUT_ID_2);
@@ -240,9 +234,6 @@
         mConversationStore.addOrUpdate(in2);
         mMockScheduledExecutorService.fastForwardTime(DateUtils.MINUTE_IN_MILLIS);
 
-        mTestContactQueryHelper.setQueryResult(true);
-        mTestContactQueryHelper.setPhoneNumberResult(PHONE_NUMBER);
-
         resetConversationStore();
         ConversationInfo out1 = mConversationStore.getConversation(SHORTCUT_ID);
         ConversationInfo out2 = mConversationStore.getConversation(SHORTCUT_ID_2);
@@ -256,10 +247,6 @@
         mConversationStore.addOrUpdate(in3);
         mMockScheduledExecutorService.fastForwardTime(3L * DateUtils.MINUTE_IN_MILLIS);
 
-        mTestContactQueryHelper.reset();
-        mTestContactQueryHelper.setQueryResult(true, true, true);
-        mTestContactQueryHelper.setPhoneNumberResult(PHONE_NUMBER, PHONE_NUMBER_2, PHONE_NUMBER_3);
-
         resetConversationStore();
         out1 = mConversationStore.getConversation(SHORTCUT_ID);
         out2 = mConversationStore.getConversation(SHORTCUT_ID_2);
@@ -290,9 +277,6 @@
         // loadConversationFromDisk gets called each time we call #resetConversationStore().
         assertEquals(2, mMockScheduledExecutorService.getExecutes().size());
 
-        mTestContactQueryHelper.setQueryResult(true, true);
-        mTestContactQueryHelper.setPhoneNumberResult(PHONE_NUMBER, PHONE_NUMBER_2);
-
         resetConversationStore();
         ConversationInfo out1 = mConversationStore.getConversation(SHORTCUT_ID);
         ConversationInfo out2 = mConversationStore.getConversation(SHORTCUT_ID_2);
@@ -303,8 +287,7 @@
     private void resetConversationStore() {
         mFile.mkdir();
         mMockScheduledExecutorService = new MockScheduledExecutorService();
-        mConversationStore = new ConversationStore(mFile, mMockScheduledExecutorService,
-                mTestContactQueryHelper);
+        mConversationStore = new ConversationStore(mFile, mMockScheduledExecutorService);
         mConversationStore.loadConversationsFromDisk();
     }
 
@@ -326,54 +309,4 @@
                 .setBubbled(true)
                 .build();
     }
-
-    private static class TestContactQueryHelper extends ContactsQueryHelper {
-
-        private int mQueryCalls;
-        private boolean[] mQueryResult;
-
-        private int mPhoneNumberCalls;
-        private String[] mPhoneNumberResult;
-
-        TestContactQueryHelper(Context context) {
-            super(context);
-
-            mQueryCalls = 0;
-            mPhoneNumberCalls = 0;
-        }
-
-        private void setQueryResult(boolean... values) {
-            mQueryResult = values;
-        }
-
-        private void setPhoneNumberResult(String... values) {
-            mPhoneNumberResult = values;
-        }
-
-        private void reset() {
-            mQueryCalls = 0;
-            mQueryResult = null;
-            mPhoneNumberCalls = 0;
-            mPhoneNumberResult = null;
-        }
-
-        @Override
-        boolean query(String contactUri) {
-            if (mQueryResult != null && mQueryCalls < mQueryResult.length) {
-                return mQueryResult[mQueryCalls++];
-            }
-            mQueryCalls++;
-            return false;
-        }
-
-        @Override
-        @Nullable
-        String getPhoneNumber() {
-            if (mPhoneNumberResult != null && mPhoneNumberCalls < mPhoneNumberResult.length) {
-                return mPhoneNumberResult[mPhoneNumberCalls++];
-            }
-            mPhoneNumberCalls++;
-            return null;
-        }
-    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java b/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java
index 5e104a5..f0b7d20 100644
--- a/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java
@@ -52,11 +52,12 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.LauncherApps.ShortcutChangeCallback;
+import android.content.pm.PackageManager;
 import android.content.pm.PackageManagerInternal;
 import android.content.pm.ShortcutInfo;
 import android.content.pm.ShortcutServiceInternal;
 import android.content.pm.UserInfo;
-import android.content.pm.parsing.AndroidPackage;
 import android.database.ContentObserver;
 import android.net.Uri;
 import android.os.CancellationSignal;
@@ -73,12 +74,16 @@
 import com.android.internal.app.ChooserActivity;
 import com.android.internal.content.PackageMonitor;
 import com.android.server.LocalServices;
+import com.android.server.notification.NotificationManagerInternal;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
 
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
@@ -87,6 +92,7 @@
 import java.util.Collections;
 import java.util.List;
 import java.util.Set;
+import java.util.concurrent.Executor;
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.ScheduledFuture;
 import java.util.concurrent.TimeUnit;
@@ -100,7 +106,9 @@
     private static final int USER_ID_PRIMARY_MANAGED = 10;
     private static final int USER_ID_SECONDARY = 11;
     private static final String TEST_PKG_NAME = "pkg";
+    private static final String TEST_CLASS_NAME = "class";
     private static final String TEST_SHORTCUT_ID = "sc";
+    private static final int TEST_PKG_UID = 35;
     private static final String CONTACT_URI = "content://com.android.contacts/contacts/lookup/123";
     private static final String PHONE_NUMBER = "+1234567890";
     private static final String NOTIFICATION_CHANNEL_ID = "test : sc";
@@ -110,7 +118,9 @@
     @Mock private ShortcutServiceInternal mShortcutServiceInternal;
     @Mock private UsageStatsManagerInternal mUsageStatsManagerInternal;
     @Mock private PackageManagerInternal mPackageManagerInternal;
+    @Mock private NotificationManagerInternal mNotificationManagerInternal;
     @Mock private UserManager mUserManager;
+    @Mock private PackageManager mPackageManager;
     @Mock private TelephonyManager mTelephonyManager;
     @Mock private TelecomManager mTelecomManager;
     @Mock private ContentResolver mContentResolver;
@@ -120,13 +130,16 @@
     @Mock private StatusBarNotification mStatusBarNotification;
     @Mock private Notification mNotification;
 
+    @Captor private ArgumentCaptor<ShortcutChangeCallback> mShortcutChangeCallbackCaptor;
+
     private NotificationChannel mNotificationChannel;
     private DataManager mDataManager;
     private CancellationSignal mCancellationSignal;
+    private ShortcutChangeCallback mShortcutChangeCallback;
     private TestInjector mInjector;
 
     @Before
-    public void setUp() {
+    public void setUp() throws PackageManager.NameNotFoundException {
         MockitoAnnotations.initMocks(this);
 
         addLocalServiceMock(ShortcutServiceInternal.class, mShortcutServiceInternal);
@@ -142,8 +155,12 @@
             return null;
         }).when(mPackageManagerInternal).forEachInstalledPackage(any(Consumer.class), anyInt());
 
+        addLocalServiceMock(NotificationManagerInternal.class, mNotificationManagerInternal);
+
+        when(mContext.getContentResolver()).thenReturn(mContentResolver);
         when(mContext.getMainLooper()).thenReturn(Looper.getMainLooper());
         when(mContext.getPackageName()).thenReturn("android");
+        when(mContext.getPackageManager()).thenReturn(mPackageManager);
 
         Context originalContext = getInstrumentation().getTargetContext();
         when(mContext.getApplicationInfo()).thenReturn(originalContext.getApplicationInfo());
@@ -174,7 +191,8 @@
         when(mUserManager.getEnabledProfiles(USER_ID_SECONDARY))
                 .thenReturn(Collections.singletonList(buildUserInfo(USER_ID_SECONDARY)));
 
-        when(mContext.getContentResolver()).thenReturn(mContentResolver);
+        when(mPackageManager.getPackageUidAsUser(TEST_PKG_NAME, USER_ID_PRIMARY))
+                .thenReturn(TEST_PKG_UID);
 
         when(mStatusBarNotification.getNotification()).thenReturn(mNotification);
         when(mStatusBarNotification.getPackageName()).thenReturn(TEST_PKG_NAME);
@@ -191,6 +209,10 @@
         mInjector = new TestInjector();
         mDataManager = new DataManager(mContext, mInjector);
         mDataManager.initialize();
+
+        verify(mShortcutServiceInternal).addShortcutChangeCallback(
+                mShortcutChangeCallbackCaptor.capture());
+        mShortcutChangeCallback = mShortcutChangeCallbackCaptor.getValue();
     }
 
     @After
@@ -206,13 +228,13 @@
         mDataManager.onUserUnlocked(USER_ID_PRIMARY_MANAGED);
         mDataManager.onUserUnlocked(USER_ID_SECONDARY);
 
-        mDataManager.onShortcutAddedOrUpdated(
+        mDataManager.addOrUpdateConversationInfo(
                 buildShortcutInfo("pkg_1", USER_ID_PRIMARY, "sc_1",
                         buildPerson(true, false)));
-        mDataManager.onShortcutAddedOrUpdated(
+        mDataManager.addOrUpdateConversationInfo(
                 buildShortcutInfo("pkg_2", USER_ID_PRIMARY_MANAGED, "sc_2",
                         buildPerson(false, true)));
-        mDataManager.onShortcutAddedOrUpdated(
+        mDataManager.addOrUpdateConversationInfo(
                 buildShortcutInfo("pkg_3", USER_ID_SECONDARY, "sc_3", buildPerson()));
 
         List<ConversationInfo> conversations = getConversationsInPrimary();
@@ -236,9 +258,9 @@
     @Test
     public void testAccessConversationForUnlockedUsersOnly() {
         mDataManager.onUserUnlocked(USER_ID_PRIMARY);
-        mDataManager.onShortcutAddedOrUpdated(
+        mDataManager.addOrUpdateConversationInfo(
                 buildShortcutInfo("pkg_1", USER_ID_PRIMARY, "sc_1", buildPerson()));
-        mDataManager.onShortcutAddedOrUpdated(
+        mDataManager.addOrUpdateConversationInfo(
                 buildShortcutInfo("pkg_2", USER_ID_PRIMARY_MANAGED, "sc_2", buildPerson()));
 
         List<ConversationInfo> conversations = getConversationsInPrimary();
@@ -261,11 +283,12 @@
     }
 
     @Test
-    public void testReportAppTargetEvent() throws IntentFilter.MalformedMimeTypeException {
+    public void testReportAppTargetEvent_directSharing()
+            throws IntentFilter.MalformedMimeTypeException {
         mDataManager.onUserUnlocked(USER_ID_PRIMARY);
         ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
                 buildPerson());
-        mDataManager.onShortcutAddedOrUpdated(shortcut);
+        mDataManager.addOrUpdateConversationInfo(shortcut);
 
         AppTarget appTarget = new AppTarget.Builder(new AppTargetId(TEST_SHORTCUT_ID), shortcut)
                 .build();
@@ -274,7 +297,55 @@
                         .setLaunchLocation(ChooserActivity.LAUNCH_LOCATON_DIRECT_SHARE)
                         .build();
         IntentFilter intentFilter = new IntentFilter(Intent.ACTION_SEND, "image/jpg");
-        mDataManager.reportAppTargetEvent(appTargetEvent, intentFilter);
+        mDataManager.reportShareTargetEvent(appTargetEvent, intentFilter);
+
+        List<Range<Long>> activeShareTimeSlots = getActiveSlotsForTestShortcut(
+                Event.SHARE_EVENT_TYPES);
+        assertEquals(1, activeShareTimeSlots.size());
+    }
+
+    @Test
+    public void testReportAppTargetEvent_directSharing_createConversation()
+            throws IntentFilter.MalformedMimeTypeException {
+        mDataManager.onUserUnlocked(USER_ID_PRIMARY);
+        ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
+                null);
+        AppTarget appTarget = new AppTarget.Builder(new AppTargetId(TEST_SHORTCUT_ID), shortcut)
+                .build();
+        AppTargetEvent appTargetEvent =
+                new AppTargetEvent.Builder(appTarget, AppTargetEvent.ACTION_LAUNCH)
+                        .setLaunchLocation(ChooserActivity.LAUNCH_LOCATON_DIRECT_SHARE)
+                        .build();
+        IntentFilter intentFilter = new IntentFilter(Intent.ACTION_SEND, "image/jpg");
+
+        mDataManager.reportShareTargetEvent(appTargetEvent, intentFilter);
+
+        List<Range<Long>> activeShareTimeSlots = getActiveSlotsForTestShortcut(
+                Event.SHARE_EVENT_TYPES);
+        assertEquals(1, activeShareTimeSlots.size());
+        ConversationInfo conversationInfo = mDataManager.getPackage(TEST_PKG_NAME, USER_ID_PRIMARY)
+                .getConversationStore()
+                .getConversation(TEST_SHORTCUT_ID);
+        assertNotNull(conversationInfo);
+        assertEquals(conversationInfo.getShortcutId(), TEST_SHORTCUT_ID);
+    }
+
+    @Test
+    public void testReportAppTargetEvent_appSharing()
+            throws IntentFilter.MalformedMimeTypeException {
+        mDataManager.onUserUnlocked(USER_ID_PRIMARY);
+        AppTarget appTarget = new AppTarget.Builder(
+                    new AppTargetId(TEST_SHORTCUT_ID),
+                    TEST_PKG_NAME,
+                    UserHandle.of(USER_ID_PRIMARY))
+                .setClassName(TEST_CLASS_NAME)
+                .build();
+        AppTargetEvent appTargetEvent =
+                new AppTargetEvent.Builder(appTarget, AppTargetEvent.ACTION_LAUNCH)
+                        .build();
+        IntentFilter intentFilter = new IntentFilter(Intent.ACTION_SEND, "image/jpg");
+
+        mDataManager.reportShareTargetEvent(appTargetEvent, intentFilter);
 
         List<Range<Long>> activeShareTimeSlots = getActiveSlotsForTestShortcut(
                 Event.SHARE_EVENT_TYPES);
@@ -288,7 +359,7 @@
 
         ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
                 buildPerson());
-        mDataManager.onShortcutAddedOrUpdated(shortcut);
+        mDataManager.addOrUpdateConversationInfo(shortcut);
 
         final String newPhoneNumber = "+1000000000";
         mInjector.mContactsQueryHelper.mIsStarred = true;
@@ -312,7 +383,7 @@
 
         ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
                 buildPerson());
-        mDataManager.onShortcutAddedOrUpdated(shortcut);
+        mDataManager.addOrUpdateConversationInfo(shortcut);
 
         NotificationListenerService listenerService =
                 mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
@@ -330,7 +401,7 @@
 
         ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
                 buildPerson());
-        mDataManager.onShortcutAddedOrUpdated(shortcut);
+        mDataManager.addOrUpdateConversationInfo(shortcut);
 
         NotificationListenerService listenerService =
                 mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
@@ -350,7 +421,7 @@
 
         ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
                 buildPerson());
-        mDataManager.onShortcutAddedOrUpdated(shortcut);
+        mDataManager.addOrUpdateConversationInfo(shortcut);
 
         NotificationListenerService listenerService =
                 mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
@@ -375,7 +446,7 @@
 
         ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
                 buildPerson());
-        mDataManager.onShortcutAddedOrUpdated(shortcut);
+        mDataManager.addOrUpdateConversationInfo(shortcut);
 
         NotificationListenerService listenerService =
                 mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
@@ -401,7 +472,7 @@
 
         ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
                 buildPerson());
-        mDataManager.onShortcutAddedOrUpdated(shortcut);
+        mDataManager.addOrUpdateConversationInfo(shortcut);
 
         NotificationListenerService listenerService =
                 mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
@@ -424,13 +495,50 @@
     }
 
     @Test
+    public void testShortcutAddedOrUpdated() {
+        mDataManager.onUserUnlocked(USER_ID_PRIMARY);
+
+        ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
+                buildPerson());
+        mShortcutChangeCallback.onShortcutsAddedOrUpdated(TEST_PKG_NAME,
+                Collections.singletonList(shortcut), UserHandle.of(USER_ID_PRIMARY));
+
+        List<ConversationInfo> conversations = getConversationsInPrimary();
+
+        assertEquals(1, conversations.size());
+        assertEquals(TEST_SHORTCUT_ID, conversations.get(0).getShortcutId());
+    }
+
+    @Test
+    public void testShortcutDeleted() {
+        mDataManager.onUserUnlocked(USER_ID_PRIMARY);
+
+        ShortcutInfo shortcut1 = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, "sc1",
+                buildPerson());
+        ShortcutInfo shortcut2 = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, "sc2",
+                buildPerson());
+        mShortcutChangeCallback.onShortcutsAddedOrUpdated(TEST_PKG_NAME,
+                Arrays.asList(shortcut1, shortcut2), UserHandle.of(USER_ID_PRIMARY));
+        mShortcutChangeCallback.onShortcutsRemoved(TEST_PKG_NAME,
+                Collections.singletonList(shortcut1), UserHandle.of(USER_ID_PRIMARY));
+
+        List<ConversationInfo> conversations = getConversationsInPrimary();
+
+        assertEquals(1, conversations.size());
+        assertEquals("sc2", conversations.get(0).getShortcutId());
+
+        verify(mNotificationManagerInternal)
+                .onConversationRemoved(TEST_PKG_NAME, TEST_PKG_UID, "sc1");
+    }
+
+    @Test
     public void testCallLogContentObserver() {
         mDataManager.onUserUnlocked(USER_ID_PRIMARY);
         mDataManager.onUserUnlocked(USER_ID_SECONDARY);
 
         ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
                 buildPerson());
-        mDataManager.onShortcutAddedOrUpdated(shortcut);
+        mDataManager.addOrUpdateConversationInfo(shortcut);
 
         ContentObserver contentObserver = mDataManager.getCallLogContentObserverForTesting();
         contentObserver.onChange(false);
@@ -453,7 +561,7 @@
 
         ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
                 buildPerson());
-        mDataManager.onShortcutAddedOrUpdated(shortcut);
+        mDataManager.addOrUpdateConversationInfo(shortcut);
         mDataManager.getUserDataForTesting(USER_ID_PRIMARY).setDefaultSmsApp(TEST_PKG_NAME);
 
         ContentObserver contentObserver = mDataManager.getMmsSmsContentObserverForTesting();
@@ -476,7 +584,7 @@
 
         ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
                 buildPerson());
-        mDataManager.onShortcutAddedOrUpdated(shortcut);
+        mDataManager.addOrUpdateConversationInfo(shortcut);
         assertNotNull(mDataManager.getPackage(TEST_PKG_NAME, USER_ID_PRIMARY));
 
         PackageMonitor packageMonitor = mDataManager.getPackageMonitorForTesting(USER_ID_PRIMARY);
@@ -493,7 +601,7 @@
 
         ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
                 buildPerson());
-        mDataManager.onShortcutAddedOrUpdated(shortcut);
+        mDataManager.addOrUpdateConversationInfo(shortcut);
         assertNotNull(mDataManager.getPackage(TEST_PKG_NAME, USER_ID_PRIMARY));
 
         doAnswer(ans -> null).when(mPackageManagerInternal)
@@ -508,7 +616,7 @@
 
         ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
                 buildPerson());
-        mDataManager.onShortcutAddedOrUpdated(shortcut);
+        mDataManager.addOrUpdateConversationInfo(shortcut);
 
         long currentTimestamp = System.currentTimeMillis();
         mInjector.mCallLogQueryHelper.mEventConsumer.accept(PHONE_NUMBER,
@@ -529,7 +637,7 @@
 
         ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
                 buildPerson());
-        mDataManager.onShortcutAddedOrUpdated(shortcut);
+        mDataManager.addOrUpdateConversationInfo(shortcut);
         mDataManager.getUserDataForTesting(USER_ID_PRIMARY).setDefaultSmsApp(TEST_PKG_NAME);
 
         long currentTimestamp = System.currentTimeMillis();
@@ -715,6 +823,11 @@
         }
 
         @Override
+        Executor getBackgroundExecutor() {
+            return Runnable::run;
+        }
+
+        @Override
         ContactsQueryHelper createContactsQueryHelper(Context context) {
             return mContactsQueryHelper;
         }
diff --git a/services/tests/servicestests/src/com/android/server/people/data/EventHistoryImplTest.java b/services/tests/servicestests/src/com/android/server/people/data/EventHistoryImplTest.java
index 43e1001..825ca10 100644
--- a/services/tests/servicestests/src/com/android/server/people/data/EventHistoryImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/people/data/EventHistoryImplTest.java
@@ -21,18 +21,27 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
+import android.content.Context;
+import android.os.FileUtils;
+import android.text.format.DateUtils;
+
+import androidx.test.InstrumentationRegistry;
+
+import com.google.android.collect.Lists;
 import com.google.android.collect.Sets;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
 
+import java.io.File;
 import java.util.List;
+import java.util.Map;
 
 @RunWith(JUnit4.class)
 public final class EventHistoryImplTest {
-
     private static final long CURRENT_TIMESTAMP = timestamp("01-30 18:50");
 
     private static final Event E1 = new Event(timestamp("01-06 05:26"),
@@ -41,26 +50,48 @@
             Event.TYPE_NOTIFICATION_OPENED);
     private static final Event E3 = new Event(timestamp("01-30 03:06"),
             Event.TYPE_SHARE_IMAGE);
-    private static final Event E4 = new Event(timestamp("01-30 18:14"),
+    private static final Event E4 = new Event(timestamp("01-30 16:14"),
+            Event.TYPE_SMS_INCOMING);
+    private static final Event E5 = new Event(timestamp("01-30 18:30"),
             Event.TYPE_SMS_INCOMING);
 
+    private static final EventIndex.Injector EVENT_INDEX_INJECTOR = new EventIndex.Injector() {
+        @Override
+        long currentTimeMillis() {
+            return CURRENT_TIMESTAMP;
+        }
+    };
+    private static final EventHistoryImpl.Injector EVENT_HISTORY_INJECTOR =
+            new EventHistoryImpl.Injector() {
+                @Override
+                EventIndex createEventIndex() {
+                    return new EventIndex(EVENT_INDEX_INJECTOR);
+                }
+
+                @Override
+                long currentTimeMillis() {
+                    return CURRENT_TIMESTAMP;
+                }
+            };
+
     private EventHistoryImpl mEventHistory;
+    private File mCacheDir;
+    private File mFile;
+    private MockScheduledExecutorService mMockScheduledExecutorService;
 
     @Before
     public void setUp() {
-        EventIndex.Injector eventIndexInjector = new EventIndex.Injector() {
-            @Override
-            long currentTimeMillis() {
-                return CURRENT_TIMESTAMP;
-            }
-        };
-        EventHistoryImpl.Injector eventHistoryInjector = new EventHistoryImpl.Injector() {
-            @Override
-            EventIndex createEventIndex() {
-                return new EventIndex(eventIndexInjector);
-            }
-        };
-        mEventHistory = new EventHistoryImpl(eventHistoryInjector);
+        Context ctx = InstrumentationRegistry.getContext();
+        mCacheDir = ctx.getCacheDir();
+        mFile = new File(mCacheDir, "testdir");
+        mMockScheduledExecutorService = new MockScheduledExecutorService();
+        mEventHistory = new EventHistoryImpl(EVENT_HISTORY_INJECTOR, mFile,
+                mMockScheduledExecutorService);
+    }
+
+    @After
+    public void tearDown() {
+        FileUtils.deleteContentsAndDir(mFile);
     }
 
     @Test
@@ -115,4 +146,105 @@
                 Sets.newArraySet(Event.TYPE_SHARE_IMAGE), 0L, Long.MAX_VALUE);
         assertEquals(1, events.size());
     }
+
+    @Test
+    public void testPersistenceAndRestoration() {
+        mEventHistory.addEvent(E1);
+        mEventHistory.addEvent(E2);
+        mEventHistory.addEvent(E3);
+        mEventHistory.addEvent(E4);
+        mEventHistory.addEvent(E5);
+
+        // futures of events and event index flush.
+        long futuresExecuted = mMockScheduledExecutorService.fastForwardTime(
+                3L * DateUtils.MINUTE_IN_MILLIS);
+        assertEquals(2, futuresExecuted);
+
+        EventIndex indexBeforePowerOff = mEventHistory.getEventIndex(Event.ALL_EVENT_TYPES);
+
+        resetAndLoadEventHistory();
+
+        List<Event> events = mEventHistory.queryEvents(Event.ALL_EVENT_TYPES, 0L, Long.MAX_VALUE);
+        assertEquals(2, events.size());
+        assertTrue(events.containsAll(Lists.newArrayList(E4, E5)));
+
+        EventIndex indexAfterPowerOff = mEventHistory.getEventIndex(Event.ALL_EVENT_TYPES);
+        assertEquals(indexBeforePowerOff, indexAfterPowerOff);
+    }
+
+    @Test
+    public void testMimicDevicePowerOff() {
+        mEventHistory.addEvent(E1);
+        mEventHistory.addEvent(E2);
+        mEventHistory.addEvent(E3);
+        mEventHistory.addEvent(E4);
+        mEventHistory.addEvent(E5);
+        mEventHistory.saveToDisk();
+
+        EventIndex indexBeforePowerOff = mEventHistory.getEventIndex(Event.ALL_EVENT_TYPES);
+
+        // Ensure that futures were cancelled and the immediate flush occurred.
+        assertEquals(0, mMockScheduledExecutorService.getFutures().size());
+
+        // Expect to see 2 executes from #saveToDisk, one for events and another for index.
+        assertEquals(2, mMockScheduledExecutorService.getExecutes().size());
+
+        resetAndLoadEventHistory();
+
+        List<Event> events = mEventHistory.queryEvents(Event.ALL_EVENT_TYPES, 0L, Long.MAX_VALUE);
+        assertEquals(2, events.size());
+        assertTrue(events.containsAll(Lists.newArrayList(E4, E5)));
+
+        EventIndex indexAfterPowerOff = mEventHistory.getEventIndex(Event.ALL_EVENT_TYPES);
+        assertEquals(indexBeforePowerOff, indexAfterPowerOff);
+    }
+
+    @Test
+    public void testOnDestroy() {
+        mEventHistory.addEvent(E1);
+        mEventHistory.addEvent(E2);
+        mEventHistory.addEvent(E3);
+        mEventHistory.addEvent(E4);
+        mEventHistory.addEvent(E5);
+        mEventHistory.saveToDisk();
+
+        mEventHistory.onDestroy();
+
+        List<Event> events = mEventHistory.queryEvents(Event.ALL_EVENT_TYPES, 0L, Long.MAX_VALUE);
+        assertTrue(events.isEmpty());
+
+        EventIndex index = mEventHistory.getEventIndex(Event.ALL_EVENT_TYPES);
+        assertTrue(index.isEmpty());
+    }
+
+    @Test
+    public void testEventHistoriesImplFromDisk() {
+        mEventHistory.addEvent(E1);
+        mEventHistory.addEvent(E2);
+        mEventHistory.addEvent(E3);
+        mEventHistory.addEvent(E4);
+        mEventHistory.addEvent(E5);
+        mEventHistory.saveToDisk();
+
+        EventIndex indexBefore = mEventHistory.getEventIndex(Event.ALL_EVENT_TYPES);
+
+        Map<String, EventHistoryImpl> map = EventHistoryImpl.eventHistoriesImplFromDisk(
+                EVENT_HISTORY_INJECTOR, mCacheDir, mMockScheduledExecutorService);
+        assertEquals(1, map.size());
+        assertTrue(map.containsKey("testdir"));
+
+        List<Event> events = map.get("testdir").queryEvents(Event.ALL_EVENT_TYPES, 0L,
+                Long.MAX_VALUE);
+        assertEquals(2, events.size());
+        assertTrue(events.containsAll(Lists.newArrayList(E4, E5)));
+
+        EventIndex indexAfter = map.get("testdir").getEventIndex(Event.ALL_EVENT_TYPES);
+        assertEquals(indexBefore, indexAfter);
+    }
+
+    private void resetAndLoadEventHistory() {
+        mEventHistory = new EventHistoryImpl(EVENT_HISTORY_INJECTOR, mFile,
+                mMockScheduledExecutorService);
+        mEventHistory.loadFromDisk();
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/people/data/MockScheduledExecutorService.java b/services/tests/servicestests/src/com/android/server/people/data/MockScheduledExecutorService.java
index 8b8ba12..aecbc8d 100644
--- a/services/tests/servicestests/src/com/android/server/people/data/MockScheduledExecutorService.java
+++ b/services/tests/servicestests/src/com/android/server/people/data/MockScheduledExecutorService.java
@@ -54,8 +54,8 @@
         long totalExecuted = 0;
         for (MockScheduledFuture<?> future : futuresCopy) {
             if (future.getDelay() < mTimeElapsedMillis) {
-                future.getCommand().run();
-                mExecutes.add(future.getCommand());
+                future.getRunnable().run();
+                mExecutes.add(future.getRunnable());
                 totalExecuted += 1;
             } else {
                 mFutures.add(future);
@@ -96,7 +96,8 @@
     @Override
     public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period,
             TimeUnit unit) {
-        throw new UnsupportedOperationException();
+        Preconditions.checkState(unit == TimeUnit.MILLISECONDS);
+        return new MockScheduledFuture<>(command, period, unit);
     }
 
     @Override
@@ -132,7 +133,13 @@
 
     @Override
     public <T> Future<T> submit(Callable<T> task) {
-        throw new UnsupportedOperationException();
+        MockScheduledFuture<T> future = new MockScheduledFuture<>(task, 0, TimeUnit.MILLISECONDS);
+        try {
+            future.getCallable().call();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return future;
     }
 
     @Override
@@ -141,11 +148,11 @@
     }
 
     @Override
-    public Future<?> submit(Runnable command) {
-        mExecutes.add(command);
-        MockScheduledFuture<?> future = new MockScheduledFuture<>(command, 0,
+    public Future<?> submit(Runnable runnable) {
+        mExecutes.add(runnable);
+        MockScheduledFuture<?> future = new MockScheduledFuture<>(runnable, 0,
                 TimeUnit.MILLISECONDS);
-        future.getCommand().run();
+        future.getRunnable().run();
         return future;
     }
 
@@ -181,12 +188,22 @@
 
     class MockScheduledFuture<V> implements ScheduledFuture<V> {
 
-        private final Runnable mCommand;
+        private final Runnable mRunnable;
+        private final Callable<V> mCallable;
         private final long mDelay;
         private boolean mCancelled = false;
 
-        MockScheduledFuture(Runnable command, long delay, TimeUnit timeUnit) {
-            mCommand = command;
+        MockScheduledFuture(Runnable runnable, long delay, TimeUnit timeUnit) {
+            this(runnable, null, delay);
+        }
+
+        MockScheduledFuture(Callable<V> callable, long delay, TimeUnit timeUnit) {
+            this(null, callable, delay);
+        }
+
+        private MockScheduledFuture(Runnable runnable, Callable<V> callable, long delay) {
+            mCallable = callable;
+            mRunnable = runnable;
             mDelay = delay;
         }
 
@@ -194,8 +211,12 @@
             return mDelay;
         }
 
-        public Runnable getCommand() {
-            return mCommand;
+        public Runnable getRunnable() {
+            return mRunnable;
+        }
+
+        public Callable<V> getCallable() {
+            return mCallable;
         }
 
         @Override
diff --git a/services/tests/servicestests/src/com/android/server/people/data/PackageDataTest.java b/services/tests/servicestests/src/com/android/server/people/data/PackageDataTest.java
index e52cdf5..8191d17 100644
--- a/services/tests/servicestests/src/com/android/server/people/data/PackageDataTest.java
+++ b/services/tests/servicestests/src/com/android/server/people/data/PackageDataTest.java
@@ -61,7 +61,7 @@
         testDir.mkdir();
         mPackageData = new PackageData(
                 PACKAGE_NAME, USER_ID, pkg -> mIsDefaultDialer, pkg -> mIsDefaultSmsApp,
-                new MockScheduledExecutorService(), testDir, new ContactsQueryHelper(ctx));
+                new MockScheduledExecutorService(), testDir);
         ConversationInfo conversationInfo = new ConversationInfo.Builder()
                 .setShortcutId(SHORTCUT_ID)
                 .setLocusId(LOCUS_ID)
diff --git a/services/tests/servicestests/src/com/android/server/people/data/UsageStatsQueryHelperTest.java b/services/tests/servicestests/src/com/android/server/people/data/UsageStatsQueryHelperTest.java
index d444466..7934d33 100644
--- a/services/tests/servicestests/src/com/android/server/people/data/UsageStatsQueryHelperTest.java
+++ b/services/tests/servicestests/src/com/android/server/people/data/UsageStatsQueryHelperTest.java
@@ -16,6 +16,8 @@
 
 package com.android.server.people.data;
 
+import static com.android.server.people.data.TestUtils.timestamp;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
@@ -62,7 +64,8 @@
     private static final LocusId LOCUS_ID_1 = new LocusId("locus_1");
     private static final LocusId LOCUS_ID_2 = new LocusId("locus_2");
 
-    @Mock private UsageStatsManagerInternal mUsageStatsManagerInternal;
+    @Mock
+    private UsageStatsManagerInternal mUsageStatsManagerInternal;
 
     private TestPackageData mPackageData;
     private UsageStatsQueryHelper mHelper;
@@ -76,10 +79,9 @@
         Context ctx = InstrumentationRegistry.getContext();
         File testDir = new File(ctx.getCacheDir(), "testdir");
         ScheduledExecutorService scheduledExecutorService = new MockScheduledExecutorService();
-        ContactsQueryHelper helper = new ContactsQueryHelper(ctx);
 
         mPackageData = new TestPackageData(PKG_NAME, USER_ID_PRIMARY, pkg -> false, pkg -> false,
-                scheduledExecutorService, testDir, helper);
+                scheduledExecutorService, testDir);
         mPackageData.mConversationStore.mConversationInfo = new ConversationInfo.Builder()
                 .setShortcutId(SHORTCUT_ID)
                 .setLocusId(LOCUS_ID_1)
@@ -218,9 +220,8 @@
         private ConversationInfo mConversationInfo;
 
         TestConversationStore(File packageDir,
-                ScheduledExecutorService scheduledExecutorService,
-                ContactsQueryHelper helper) {
-            super(packageDir, scheduledExecutorService, helper);
+                ScheduledExecutorService scheduledExecutorService) {
+            super(packageDir, scheduledExecutorService);
         }
 
         @Override
@@ -233,17 +234,16 @@
     private static class TestPackageData extends PackageData {
 
         private final TestConversationStore mConversationStore;
-        private final TestEventStore mEventStore = new TestEventStore();
+        private final TestEventStore mEventStore;
 
         TestPackageData(@NonNull String packageName, @UserIdInt int userId,
                 @NonNull Predicate<String> isDefaultDialerPredicate,
                 @NonNull Predicate<String> isDefaultSmsAppPredicate,
-                @NonNull ScheduledExecutorService scheduledExecutorService, @NonNull File rootDir,
-                @NonNull ContactsQueryHelper helper) {
+                @NonNull ScheduledExecutorService scheduledExecutorService, @NonNull File rootDir) {
             super(packageName, userId, isDefaultDialerPredicate, isDefaultSmsAppPredicate,
-                    scheduledExecutorService, rootDir, helper);
-            mConversationStore = new TestConversationStore(rootDir, scheduledExecutorService,
-                    helper);
+                    scheduledExecutorService, rootDir);
+            mConversationStore = new TestConversationStore(rootDir, scheduledExecutorService);
+            mEventStore = new TestEventStore(rootDir, scheduledExecutorService);
         }
 
         @Override
@@ -261,8 +261,31 @@
 
     private static class TestEventStore extends EventStore {
 
-        private final EventHistoryImpl mShortcutEventHistory = new TestEventHistoryImpl();
-        private final EventHistoryImpl mLocusEventHistory = new TestEventHistoryImpl();
+        private static final long CURRENT_TIMESTAMP = timestamp("01-30 18:50");
+        private static final EventIndex.Injector EVENT_INDEX_INJECTOR = new EventIndex.Injector() {
+            @Override
+            long currentTimeMillis() {
+                return CURRENT_TIMESTAMP;
+            }
+        };
+        private static final EventHistoryImpl.Injector EVENT_HISTORY_INJECTOR =
+                new EventHistoryImpl.Injector() {
+                    @Override
+                    EventIndex createEventIndex() {
+                        return new EventIndex(EVENT_INDEX_INJECTOR);
+                    }
+                };
+
+        private final EventHistoryImpl mShortcutEventHistory;
+        private final EventHistoryImpl mLocusEventHistory;
+
+        TestEventStore(File rootDir, ScheduledExecutorService scheduledExecutorService) {
+            super(rootDir, scheduledExecutorService);
+            mShortcutEventHistory = new TestEventHistoryImpl(EVENT_HISTORY_INJECTOR, rootDir,
+                    scheduledExecutorService);
+            mLocusEventHistory = new TestEventHistoryImpl(EVENT_HISTORY_INJECTOR, rootDir,
+                    scheduledExecutorService);
+        }
 
         @Override
         @NonNull
@@ -280,6 +303,11 @@
 
         private final List<Event> mEvents = new ArrayList<>();
 
+        TestEventHistoryImpl(Injector injector, File rootDir,
+                ScheduledExecutorService scheduledExecutorService) {
+            super(injector, rootDir, scheduledExecutorService);
+        }
+
         @Override
         @NonNull
         public List<Event> queryEvents(Set<Integer> eventTypes, long startTime, long endTime) {
diff --git a/services/tests/servicestests/src/com/android/server/people/prediction/ShareTargetPredictorTest.java b/services/tests/servicestests/src/com/android/server/people/prediction/ShareTargetPredictorTest.java
index f498a94..c6cd347 100644
--- a/services/tests/servicestests/src/com/android/server/people/prediction/ShareTargetPredictorTest.java
+++ b/services/tests/servicestests/src/com/android/server/people/prediction/ShareTargetPredictorTest.java
@@ -16,16 +16,19 @@
 
 package com.android.server.people.prediction;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.anySet;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.app.prediction.AppPredictionContext;
+import android.app.prediction.AppTarget;
+import android.app.prediction.AppTargetId;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -33,22 +36,26 @@
 import android.content.pm.ShortcutManager.ShareShortcutInfo;
 import android.os.Bundle;
 import android.os.UserHandle;
+import android.util.Range;
 
 import com.android.server.people.data.ConversationInfo;
 import com.android.server.people.data.DataManager;
 import com.android.server.people.data.EventHistory;
+import com.android.server.people.data.EventIndex;
 import com.android.server.people.data.PackageData;
-import com.android.server.people.prediction.ShareTargetPredictor.ShareTarget;
 
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.function.Consumer;
 
 @RunWith(JUnit4.class)
 public final class ShareTargetPredictorTest {
@@ -57,17 +64,32 @@
     private static final int NUM_PREDICTED_TARGETS = 5;
     private static final int USER_ID = 0;
     private static final String PACKAGE_1 = "pkg1";
-    private static final String CLASS_1 = "cls1";
     private static final String PACKAGE_2 = "pkg2";
+    private static final String PACKAGE_3 = "pkg3";
+    private static final String CLASS_1 = "cls1";
     private static final String CLASS_2 = "cls2";
 
     @Mock private Context mContext;
     @Mock private DataManager mDataManager;
+    @Mock private Consumer<List<AppTarget>> mUpdatePredictionsMethod;
     @Mock private PackageData mPackageData1;
     @Mock private PackageData mPackageData2;
+    @Mock private EventHistory mEventHistory1;
+    @Mock private EventHistory mEventHistory2;
+    @Mock private EventHistory mEventHistory3;
+    @Mock private EventHistory mEventHistory4;
+    @Mock private EventHistory mEventHistory5;
+    @Mock private EventHistory mEventHistory6;
+
+    @Mock private EventIndex mEventIndex1;
+    @Mock private EventIndex mEventIndex2;
+    @Mock private EventIndex mEventIndex3;
+    @Mock private EventIndex mEventIndex4;
+    @Mock private EventIndex mEventIndex5;
+    @Mock private EventIndex mEventIndex6;
+    @Captor private ArgumentCaptor<List<AppTarget>> mAppTargetCaptor;
 
     private List<ShareShortcutInfo> mShareShortcuts = new ArrayList<>();
-
     private ShareTargetPredictor mPredictor;
 
     @Before
@@ -84,11 +106,11 @@
                 .setExtras(new Bundle())
                 .build();
         mPredictor = new ShareTargetPredictor(
-                predictionContext, targets -> { }, mDataManager, USER_ID);
+                predictionContext, mUpdatePredictionsMethod, mDataManager, USER_ID);
     }
 
     @Test
-    public void testGetShareTargets() {
+    public void testPredictTargets() {
         mShareShortcuts.add(buildShareShortcut(PACKAGE_1, CLASS_1, "sc1"));
         mShareShortcuts.add(buildShareShortcut(PACKAGE_1, CLASS_1, "sc2"));
         mShareShortcuts.add(buildShareShortcut(PACKAGE_2, CLASS_2, "sc3"));
@@ -99,24 +121,148 @@
         when(mPackageData2.getConversationInfo("sc3")).thenReturn(mock(ConversationInfo.class));
         // "sc4" does not have a ConversationInfo.
 
-        when(mPackageData1.getEventHistory(anyString())).thenReturn(mock(EventHistory.class));
-        when(mPackageData2.getEventHistory(anyString())).thenReturn(mock(EventHistory.class));
+        when(mPackageData1.getEventHistory("sc1")).thenReturn(mEventHistory1);
+        when(mPackageData1.getEventHistory("sc2")).thenReturn(mEventHistory2);
+        when(mPackageData2.getEventHistory("sc3")).thenReturn(mEventHistory3);
+        when(mEventHistory1.getEventIndex(anySet())).thenReturn(mEventIndex1);
+        when(mEventHistory2.getEventIndex(anySet())).thenReturn(mEventIndex2);
+        when(mEventHistory3.getEventIndex(anySet())).thenReturn(mEventIndex3);
+        when(mEventIndex1.getMostRecentActiveTimeSlot()).thenReturn(new Range<>(1L, 2L));
+        when(mEventIndex2.getMostRecentActiveTimeSlot()).thenReturn(new Range<>(2L, 3L));
+        when(mEventIndex3.getMostRecentActiveTimeSlot()).thenReturn(new Range<>(3L, 4L));
 
-        List<ShareTarget> shareTargets = mPredictor.getShareTargets();
+        mPredictor.predictTargets();
 
-        assertEquals(4, shareTargets.size());
+        verify(mUpdatePredictionsMethod).accept(mAppTargetCaptor.capture());
+        List<AppTarget> res = mAppTargetCaptor.getValue();
+        assertEquals(4, res.size());
 
-        assertEquals("sc1", shareTargets.get(0).getShareShortcutInfo().getShortcutInfo().getId());
-        assertNotNull(shareTargets.get(0).getConversationData());
+        assertEquals("sc3", res.get(0).getId().getId());
+        assertEquals(CLASS_2, res.get(0).getClassName());
+        assertEquals(PACKAGE_2, res.get(0).getPackageName());
 
-        assertEquals("sc2", shareTargets.get(1).getShareShortcutInfo().getShortcutInfo().getId());
-        assertNotNull(shareTargets.get(1).getConversationData());
+        assertEquals("sc2", res.get(1).getId().getId());
+        assertEquals(CLASS_1, res.get(1).getClassName());
+        assertEquals(PACKAGE_1, res.get(1).getPackageName());
 
-        assertEquals("sc3", shareTargets.get(2).getShareShortcutInfo().getShortcutInfo().getId());
-        assertNotNull(shareTargets.get(2).getConversationData());
+        assertEquals("sc1", res.get(2).getId().getId());
+        assertEquals(CLASS_1, res.get(2).getClassName());
+        assertEquals(PACKAGE_1, res.get(2).getPackageName());
 
-        assertEquals("sc4", shareTargets.get(3).getShareShortcutInfo().getShortcutInfo().getId());
-        assertNull(shareTargets.get(3).getConversationData());
+        assertEquals("sc4", res.get(3).getId().getId());
+        assertEquals(CLASS_2, res.get(3).getClassName());
+        assertEquals(PACKAGE_2, res.get(3).getPackageName());
+    }
+
+    @Test
+    public void testPredictTargets_reachTargetsLimit() {
+        mShareShortcuts.add(buildShareShortcut(PACKAGE_1, CLASS_1, "sc1"));
+        mShareShortcuts.add(buildShareShortcut(PACKAGE_1, CLASS_1, "sc2"));
+        mShareShortcuts.add(buildShareShortcut(PACKAGE_2, CLASS_2, "sc3"));
+        mShareShortcuts.add(buildShareShortcut(PACKAGE_2, CLASS_2, "sc4"));
+        mShareShortcuts.add(buildShareShortcut(PACKAGE_1, CLASS_1, "sc5"));
+        mShareShortcuts.add(buildShareShortcut(PACKAGE_2, CLASS_2, "sc6"));
+
+        when(mPackageData1.getConversationInfo("sc1")).thenReturn(mock(ConversationInfo.class));
+        when(mPackageData1.getConversationInfo("sc2")).thenReturn(mock(ConversationInfo.class));
+        when(mPackageData2.getConversationInfo("sc3")).thenReturn(mock(ConversationInfo.class));
+        when(mPackageData2.getConversationInfo("sc4")).thenReturn(mock(ConversationInfo.class));
+        when(mPackageData1.getConversationInfo("sc5")).thenReturn(mock(ConversationInfo.class));
+        when(mPackageData2.getConversationInfo("sc6")).thenReturn(mock(ConversationInfo.class));
+
+        when(mPackageData1.getEventHistory("sc1")).thenReturn(mEventHistory1);
+        when(mPackageData1.getEventHistory("sc2")).thenReturn(mEventHistory2);
+        when(mPackageData2.getEventHistory("sc3")).thenReturn(mEventHistory3);
+        when(mPackageData2.getEventHistory("sc4")).thenReturn(mEventHistory4);
+        when(mPackageData1.getEventHistory("sc5")).thenReturn(mEventHistory5);
+        when(mPackageData2.getEventHistory("sc6")).thenReturn(mEventHistory6);
+
+        when(mEventHistory1.getEventIndex(anySet())).thenReturn(mEventIndex1);
+        when(mEventHistory2.getEventIndex(anySet())).thenReturn(mEventIndex2);
+        when(mEventHistory3.getEventIndex(anySet())).thenReturn(mEventIndex3);
+        when(mEventHistory4.getEventIndex(anySet())).thenReturn(mEventIndex4);
+        when(mEventHistory5.getEventIndex(anySet())).thenReturn(mEventIndex5);
+        when(mEventHistory6.getEventIndex(anySet())).thenReturn(mEventIndex6);
+        when(mEventIndex1.getMostRecentActiveTimeSlot()).thenReturn(new Range<>(1L, 2L));
+        when(mEventIndex2.getMostRecentActiveTimeSlot()).thenReturn(new Range<>(2L, 3L));
+        when(mEventIndex3.getMostRecentActiveTimeSlot()).thenReturn(new Range<>(3L, 4L));
+        when(mEventIndex4.getMostRecentActiveTimeSlot()).thenReturn(new Range<>(4L, 5L));
+        when(mEventIndex5.getMostRecentActiveTimeSlot()).thenReturn(new Range<>(5L, 6L));
+        when(mEventIndex6.getMostRecentActiveTimeSlot()).thenReturn(new Range<>(6L, 7L));
+
+        mPredictor.predictTargets();
+
+        verify(mUpdatePredictionsMethod).accept(mAppTargetCaptor.capture());
+        List<AppTarget> res = mAppTargetCaptor.getValue();
+        assertEquals(5, res.size());
+
+        assertEquals("sc6", res.get(0).getId().getId());
+        assertEquals(CLASS_2, res.get(0).getClassName());
+        assertEquals(PACKAGE_2, res.get(0).getPackageName());
+
+        assertEquals("sc5", res.get(1).getId().getId());
+        assertEquals(CLASS_1, res.get(1).getClassName());
+        assertEquals(PACKAGE_1, res.get(1).getPackageName());
+
+        assertEquals("sc4", res.get(2).getId().getId());
+        assertEquals(CLASS_2, res.get(2).getClassName());
+        assertEquals(PACKAGE_2, res.get(2).getPackageName());
+
+        assertEquals("sc3", res.get(3).getId().getId());
+        assertEquals(CLASS_2, res.get(3).getClassName());
+        assertEquals(PACKAGE_2, res.get(3).getPackageName());
+
+        assertEquals("sc2", res.get(4).getId().getId());
+        assertEquals(CLASS_1, res.get(4).getClassName());
+        assertEquals(PACKAGE_1, res.get(4).getPackageName());
+    }
+
+    @Test
+    public void testSortTargets() {
+        AppTarget appTarget1 = new AppTarget.Builder(
+                    new AppTargetId("cls1#pkg1"), PACKAGE_1, UserHandle.of(USER_ID))
+                .setClassName(CLASS_1)
+                .build();
+        AppTarget appTarget2 = new AppTarget.Builder(
+                    new AppTargetId("cls2#pkg1"), PACKAGE_1, UserHandle.of(USER_ID))
+                .setClassName(CLASS_2)
+                .build();
+        AppTarget appTarget3 = new AppTarget.Builder(
+                    new AppTargetId("cls1#pkg2"), PACKAGE_2, UserHandle.of(USER_ID))
+                .setClassName(CLASS_1)
+                .build();
+        AppTarget appTarget4 = new AppTarget.Builder(
+                    new AppTargetId("cls2#pkg2"), PACKAGE_2, UserHandle.of(USER_ID))
+                .setClassName(CLASS_2)
+                .build();
+        AppTarget appTarget5 = new AppTarget.Builder(
+                new AppTargetId("cls1#pkg3"), PACKAGE_3, UserHandle.of(USER_ID))
+                .setClassName(CLASS_1)
+                .build();
+
+        when(mPackageData1.getClassLevelEventHistory(CLASS_1)).thenReturn(mEventHistory1);
+        when(mPackageData1.getClassLevelEventHistory(CLASS_2)).thenReturn(mEventHistory2);
+        when(mPackageData2.getClassLevelEventHistory(CLASS_1)).thenReturn(mEventHistory3);
+        when(mPackageData2.getClassLevelEventHistory(CLASS_2)).thenReturn(mEventHistory4);
+        // PackageData of PACKAGE_3 is empty.
+        when(mDataManager.getPackage(PACKAGE_3, USER_ID)).thenReturn(null);
+
+        when(mEventHistory1.getEventIndex(anySet())).thenReturn(mEventIndex1);
+        when(mEventHistory2.getEventIndex(anySet())).thenReturn(mEventIndex2);
+        when(mEventHistory3.getEventIndex(anySet())).thenReturn(mEventIndex3);
+        when(mEventHistory4.getEventIndex(anySet())).thenReturn(mEventIndex4);
+        when(mEventIndex1.getMostRecentActiveTimeSlot()).thenReturn(new Range<>(1L, 2L));
+        when(mEventIndex2.getMostRecentActiveTimeSlot()).thenReturn(new Range<>(2L, 3L));
+        when(mEventIndex3.getMostRecentActiveTimeSlot()).thenReturn(new Range<>(3L, 4L));
+        when(mEventIndex4.getMostRecentActiveTimeSlot()).thenReturn(new Range<>(4L, 5L));
+
+        mPredictor.sortTargets(
+                List.of(appTarget1, appTarget2, appTarget3, appTarget4, appTarget5),
+                mUpdatePredictionsMethod);
+
+        verify(mUpdatePredictionsMethod).accept(mAppTargetCaptor.capture());
+        assertThat(mAppTargetCaptor.getValue()).containsExactly(
+                appTarget4, appTarget3, appTarget2, appTarget1, appTarget5);
     }
 
     private ShareShortcutInfo buildShareShortcut(
diff --git a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
index 9670658..5d5c714 100644
--- a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
@@ -29,12 +29,10 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageParser;
 import android.content.pm.Signature;
-import android.content.pm.parsing.AndroidPackage;
-import android.content.pm.parsing.ComponentParseUtils;
-import android.content.pm.parsing.ComponentParseUtils.ParsedActivity;
-import android.content.pm.parsing.ComponentParseUtils.ParsedActivityIntentInfo;
-import android.content.pm.parsing.PackageImpl;
 import android.content.pm.parsing.ParsingPackage;
+import android.content.pm.parsing.component.ParsedActivity;
+import android.content.pm.parsing.component.ParsedIntentInfo;
+import android.content.pm.parsing.component.ParsedProvider;
 import android.os.Build;
 import android.os.Process;
 import android.platform.test.annotations.Presubmit;
@@ -44,6 +42,9 @@
 import androidx.annotation.NonNull;
 
 import com.android.server.om.OverlayReferenceMapper;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.parsing.pkg.PackageImpl;
+import com.android.server.pm.parsing.pkg.ParsedPackage;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -74,7 +75,7 @@
     private ArrayMap<String, PackageSetting> mExisting = new ArrayMap<>();
 
     private static ParsingPackage pkg(String packageName) {
-        return PackageImpl.forParsing(packageName)
+        return PackageImpl.forTesting(packageName)
                 .setTargetSdkVersion(Build.VERSION_CODES.R);
     }
 
@@ -113,7 +114,7 @@
         ParsedActivity activity = new ParsedActivity();
         activity.setPackageName(packageName);
         for (IntentFilter filter : filters) {
-            final ParsedActivityIntentInfo info = new ParsedActivityIntentInfo(packageName, null);
+            final ParsedIntentInfo info = new ParsedIntentInfo();
             if (filter.countActions() > 0) {
                 filter.actionsIterator().forEachRemaining(info::addAction);
             }
@@ -127,7 +128,7 @@
                 filter.schemesIterator().forEachRemaining(info::addDataScheme);
             }
             activity.addIntent(info);
-            activity.exported = true;
+            activity.setExported(true);
         }
 
         return pkg(packageName)
@@ -135,7 +136,7 @@
     }
 
     private static ParsingPackage pkgWithProvider(String packageName, String authority) {
-        ComponentParseUtils.ParsedProvider provider = new ComponentParseUtils.ParsedProvider();
+        ParsedProvider provider = new ParsedProvider();
         provider.setPackageName(packageName);
         provider.setExported(true);
         provider.setAuthority(authority);
@@ -437,7 +438,7 @@
         ParsingPackage target = pkg("com.some.package.target")
                 .addOverlayable("overlayableName", actorName);
         ParsingPackage overlay = pkg("com.some.package.overlay")
-                .setIsOverlay(true)
+                .setOverlay(true)
                 .setOverlayTarget(target.getPackageName())
                 .setOverlayTargetName("overlayableName");
         ParsingPackage actor = pkg("com.some.package.actor");
@@ -499,7 +500,7 @@
         ParsingPackage target = pkg("com.some.package.target")
                 .addOverlayable("overlayableName", actorName);
         ParsingPackage overlay = pkg("com.some.package.overlay")
-                .setIsOverlay(true)
+                .setOverlay(true)
                 .setOverlayTarget(target.getPackageName())
                 .setOverlayTargetName("overlayableName");
         ParsingPackage actorOne = pkg("com.some.package.actor.one");
@@ -618,7 +619,7 @@
 
     private PackageSetting simulateAddPackage(AppsFilter filter,
             ParsingPackage newPkgBuilder, int appId, @Nullable WithSettingBuilder action) {
-        AndroidPackage newPkg = newPkgBuilder.hideAsParsed().hideAsFinal();
+        AndroidPackage newPkg = ((ParsedPackage) newPkgBuilder.hideAsParsed()).hideAsFinal();
 
         final PackageSettingBuilder settingBuilder = new PackageSettingBuilder()
                 .setPackage(newPkg)
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
index 56ac7c5..d2ec500 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
@@ -21,6 +21,7 @@
 import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
 
+import android.annotation.NonNull;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.ConfigurationInfo;
@@ -31,32 +32,34 @@
 import android.content.pm.PackageUserState;
 import android.content.pm.ProviderInfo;
 import android.content.pm.ServiceInfo;
-import android.content.pm.SharedLibraryInfo;
 import android.content.pm.Signature;
-import android.content.pm.parsing.AndroidPackage;
-import android.content.pm.parsing.ComponentParseUtils;
-import android.content.pm.parsing.ComponentParseUtils.ParsedActivity;
-import android.content.pm.parsing.ComponentParseUtils.ParsedComponent;
-import android.content.pm.parsing.ComponentParseUtils.ParsedInstrumentation;
-import android.content.pm.parsing.ComponentParseUtils.ParsedIntentInfo;
-import android.content.pm.parsing.ComponentParseUtils.ParsedPermission;
-import android.content.pm.parsing.ComponentParseUtils.ParsedPermissionGroup;
-import android.content.pm.parsing.ComponentParseUtils.ParsedProvider;
-import android.content.pm.parsing.ComponentParseUtils.ParsedService;
-import android.content.pm.parsing.PackageImpl;
-import android.content.pm.parsing.PackageInfoUtils;
-import android.content.pm.parsing.ParsedPackage;
 import android.content.pm.parsing.ParsingPackage;
+import android.content.pm.parsing.component.ParsedActivity;
+import android.content.pm.parsing.component.ParsedComponent;
+import android.content.pm.parsing.component.ParsedInstrumentation;
+import android.content.pm.parsing.component.ParsedIntentInfo;
+import android.content.pm.parsing.component.ParsedPermission;
+import android.content.pm.parsing.component.ParsedPermissionGroup;
+import android.content.pm.parsing.component.ParsedProvider;
+import android.content.pm.parsing.component.ParsedService;
 import android.os.Bundle;
 import android.os.Parcel;
 import android.platform.test.annotations.Presubmit;
 import android.util.ArraySet;
+import android.util.DisplayMetrics;
 
+import androidx.annotation.Nullable;
 import androidx.test.filters.MediumTest;
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.internal.util.ArrayUtils;
+import com.android.server.pm.parsing.PackageCacher;
+import com.android.server.pm.parsing.PackageInfoUtils;
+import com.android.server.pm.parsing.PackageParser2;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.parsing.pkg.PackageImpl;
+import com.android.server.pm.parsing.pkg.ParsedPackage;
 
 import org.junit.Before;
 import org.junit.Rule;
@@ -70,12 +73,12 @@
 import java.lang.reflect.Field;
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 
+@Presubmit
 @RunWith(AndroidJUnit4.class)
 @MediumTest
 public class PackageParserTest {
@@ -96,13 +99,13 @@
 
     @Test
     public void testParse_noCache() throws Exception {
-        PackageParser pp = new CachePackageNameParser();
-        ParsedPackage pkg = pp.parseParsedPackage(FRAMEWORK, 0 /* parseFlags */,
+        CachePackageNameParser pp = new CachePackageNameParser(null, false, null, null, null);
+        ParsedPackage pkg = pp.parsePackage(FRAMEWORK, 0 /* parseFlags */,
                 false /* useCaches */);
         assertNotNull(pkg);
 
         pp.setCacheDir(mTmpDir);
-        pkg = pp.parseParsedPackage(FRAMEWORK, 0 /* parseFlags */,
+        pkg = pp.parsePackage(FRAMEWORK, 0 /* parseFlags */,
                 false /* useCaches */);
         assertNotNull(pkg);
 
@@ -113,39 +116,37 @@
 
     @Test
     public void testParse_withCache() throws Exception {
-        PackageParser pp = new CachePackageNameParser();
+        CachePackageNameParser pp = new CachePackageNameParser(null, false, null, null, null);
 
         pp.setCacheDir(mTmpDir);
         // The first parse will write this package to the cache.
-        pp.parseParsedPackage(FRAMEWORK, 0 /* parseFlags */, true /* useCaches */);
+        pp.parsePackage(FRAMEWORK, 0 /* parseFlags */, true /* useCaches */);
 
         // Now attempt to parse the package again, should return the
         // cached result.
-        ParsedPackage pkg = pp.parseParsedPackage(FRAMEWORK, 0 /* parseFlags */,
+        ParsedPackage pkg = pp.parsePackage(FRAMEWORK, 0 /* parseFlags */,
                 true /* useCaches */);
         assertEquals("cache_android", pkg.getPackageName());
 
         // Try again, with useCaches == false, shouldn't return the parsed
         // result.
-        pkg = pp.parseParsedPackage(FRAMEWORK, 0 /* parseFlags */, false /* useCaches */);
+        pkg = pp.parsePackage(FRAMEWORK, 0 /* parseFlags */, false /* useCaches */);
         assertEquals("android", pkg.getPackageName());
 
         // We haven't set a cache directory here : the parse should still succeed,
         // just not using the cached results.
-        pp = new CachePackageNameParser();
-        pkg = pp.parseParsedPackage(FRAMEWORK, 0 /* parseFlags */, true /* useCaches */);
+        pp = new CachePackageNameParser(null, false, null, null, null);
+        pkg = pp.parsePackage(FRAMEWORK, 0 /* parseFlags */, true /* useCaches */);
         assertEquals("android", pkg.getPackageName());
 
-        pkg = pp.parseParsedPackage(FRAMEWORK, 0 /* parseFlags */, false /* useCaches */);
+        pkg = pp.parsePackage(FRAMEWORK, 0 /* parseFlags */, false /* useCaches */);
         assertEquals("android", pkg.getPackageName());
     }
 
     @Test
     public void test_serializePackage() throws Exception {
-        PackageParser pp = new PackageParser();
-        pp.setCacheDir(mTmpDir);
-
-        ParsedPackage pkg = pp.parseParsedPackage(FRAMEWORK, 0 /* parseFlags */,
+        PackageParser2 pp = new PackageParser2(null, false, null, mTmpDir, null);
+        ParsedPackage pkg = pp.parsePackage(FRAMEWORK, 0 /* parseFlags */,
                 true /* useCaches */);
 
         Parcel p = Parcel.obtain();
@@ -161,7 +162,7 @@
     @SmallTest
     @Presubmit
     public void test_roundTripKnownFields() throws Exception {
-        ParsingPackage pkg = PackageImpl.forParsing("foo");
+        ParsingPackage pkg = PackageImpl.forTesting("foo");
         setKnownFields(pkg);
 
         Parcel p = Parcel.obtain();
@@ -174,7 +175,7 @@
 
     @Test
     public void test_stringInterning() throws Exception {
-        ParsingPackage pkg = PackageImpl.forParsing("foo");
+        ParsingPackage pkg = PackageImpl.forTesting("foo");
         setKnownFields(pkg);
 
         Parcel p = Parcel.obtain();
@@ -212,19 +213,44 @@
      * A trivial subclass of package parser that only caches the package name, and throws away
      * all other information.
      */
-    public static class CachePackageNameParser extends PackageParser {
-        @Override
-        public byte[] toCacheEntry(ParsedPackage pkg) {
-            return ("cache_" + pkg.getPackageName()).getBytes(StandardCharsets.UTF_8);
+    public static class CachePackageNameParser extends PackageParser2 {
+
+        CachePackageNameParser(String[] separateProcesses, boolean onlyCoreApps,
+                DisplayMetrics displayMetrics, @Nullable File cacheDir,
+                PackageParser2.Callback callback) {
+            super(separateProcesses, onlyCoreApps, displayMetrics, cacheDir, callback);
+            if (cacheDir != null) {
+                setCacheDir(cacheDir);
+            }
         }
 
-        @Override
-        public ParsedPackage fromCacheEntry(byte[] cacheEntry) {
-            return PackageImpl.forParsing(new String(cacheEntry, StandardCharsets.UTF_8))
-                    .hideAsParsed();
+        void setCacheDir(@NonNull File cacheDir) {
+            this.mCacher = new PackageCacher(cacheDir) {
+                @Override
+                public byte[] toCacheEntry(ParsedPackage pkg) {
+                    return ("cache_" + pkg.getPackageName()).getBytes(StandardCharsets.UTF_8);
+                }
+
+                @Override
+                public ParsedPackage fromCacheEntry(byte[] cacheEntry) {
+                    return ((ParsedPackage) PackageImpl.forTesting(
+                            new String(cacheEntry, StandardCharsets.UTF_8))
+                            .hideAsParsed());
+                }
+            };
         }
     }
 
+    private static PackageSetting mockPkgSetting(AndroidPackage pkg) {
+        return new PackageSetting(pkg.getPackageName(), pkg.getRealPackage(),
+                new File(pkg.getCodePath()), new File(pkg.getCodePath()), null,
+                pkg.getPrimaryCpuAbi(), pkg.getSecondaryCpuAbi(),
+                null, pkg.getVersionCode(),
+                PackageInfoUtils.appInfoFlags(pkg, null),
+                PackageInfoUtils.appInfoPrivateFlags(pkg, null),
+                pkg.getSharedUserLabel(), null, null, null);
+    }
+
     // NOTE: The equality assertions below are based on code autogenerated by IntelliJ.
 
     public static void assertPackagesEqual(AndroidPackage a, AndroidPackage b) {
@@ -232,7 +258,6 @@
         assertEquals(a.isBaseHardwareAccelerated(), b.isBaseHardwareAccelerated());
         assertEquals(a.getVersionCode(), b.getVersionCode());
         assertEquals(a.getSharedUserLabel(), b.getSharedUserLabel());
-        assertEquals(a.getPreferredOrder(), b.getPreferredOrder());
         assertEquals(a.getInstallLocation(), b.getInstallLocation());
         assertEquals(a.isCoreApp(), b.isCoreApp());
         assertEquals(a.isRequiredForAllUsers(), b.isRequiredForAllUsers());
@@ -249,9 +274,9 @@
         assertArrayEquals(a.getSplitFlags(), b.getSplitFlags());
 
         PackageInfo aInfo = PackageInfoUtils.generate(a, new int[]{}, 0, 0, 0,
-                Collections.emptySet(), new PackageUserState(), 0);
+                Collections.emptySet(), new PackageUserState(), 0, mockPkgSetting(a));
         PackageInfo bInfo = PackageInfoUtils.generate(b, new int[]{}, 0, 0, 0,
-                Collections.emptySet(), new PackageUserState(), 0);
+                Collections.emptySet(), new PackageUserState(), 0, mockPkgSetting(b));
         assertApplicationInfoEqual(aInfo.applicationInfo, bInfo.applicationInfo);
 
         assertEquals(ArrayUtils.size(a.getPermissions()), ArrayUtils.size(b.getPermissions()));
@@ -298,15 +323,13 @@
         assertEquals(a.getLibraryNames(), b.getLibraryNames());
         assertEquals(a.getUsesLibraries(), b.getUsesLibraries());
         assertEquals(a.getUsesOptionalLibraries(), b.getUsesOptionalLibraries());
-        assertArrayEquals(a.getUsesLibraryFiles(), b.getUsesLibraryFiles());
         assertEquals(a.getOriginalPackages(), b.getOriginalPackages());
         assertEquals(a.getRealPackage(), b.getRealPackage());
         assertEquals(a.getAdoptPermissions(), b.getAdoptPermissions());
-        assertBundleApproximateEquals(a.getAppMetaData(), b.getAppMetaData());
+        assertBundleApproximateEquals(a.getMetaData(), b.getMetaData());
         assertEquals(a.getVersionName(), b.getVersionName());
         assertEquals(a.getSharedUserId(), b.getSharedUserId());
         assertArrayEquals(a.getSigningDetails().signatures, b.getSigningDetails().signatures);
-        assertArrayEquals(a.getLastPackageUsageTimeInMills(), b.getLastPackageUsageTimeInMills());
         assertEquals(a.getRestrictedAccountType(), b.getRestrictedAccountType());
         assertEquals(a.getRequiredAccountType(), b.getRequiredAccountType());
         assertEquals(a.getOverlayTarget(), b.getOverlayTarget());
@@ -317,7 +340,6 @@
         assertEquals(a.getSigningDetails().publicKeys, b.getSigningDetails().publicKeys);
         assertEquals(a.getUpgradeKeySets(), b.getUpgradeKeySets());
         assertEquals(a.getKeySetMapping(), b.getKeySetMapping());
-        assertEquals(a.getCpuAbiOverride(), b.getCpuAbiOverride());
         assertArrayEquals(a.getRestrictUpdateHash(), b.getRestrictUpdateHash());
     }
 
@@ -333,44 +355,42 @@
         assertEquals(a.toString(), b.toString());
     }
 
-    private static void assertComponentsEqual(ParsedComponent<?> a,
-            ParsedComponent<?> b) {
-        assertEquals(a.className, b.className);
+    private static void assertComponentsEqual(ParsedComponent a, ParsedComponent b) {
+        assertEquals(a.getName(), b.getName());
         assertBundleApproximateEquals(a.getMetaData(), b.getMetaData());
         assertEquals(a.getComponentName(), b.getComponentName());
 
-        if (a.intents != null && b.intents != null) {
-            assertEquals(a.intents.size(), b.intents.size());
-        } else if (a.intents == null || b.intents == null) {
+        if (a.getIntents() != null && b.getIntents() != null) {
+            assertEquals(a.getIntents().size(), b.getIntents().size());
+        } else if (a.getIntents() == null || b.getIntents() == null) {
             return;
         }
 
-        for (int i = 0; i < a.intents.size(); ++i) {
-            ParsedIntentInfo aIntent = a.intents.get(i);
-            ParsedIntentInfo bIntent = b.intents.get(i);
+        for (int i = 0; i < a.getIntents().size(); ++i) {
+            ParsedIntentInfo aIntent = a.getIntents().get(i);
+            ParsedIntentInfo bIntent = b.getIntents().get(i);
 
-            assertEquals(aIntent.hasDefault, bIntent.hasDefault);
-            assertEquals(aIntent.labelRes, bIntent.labelRes);
-            assertEquals(aIntent.nonLocalizedLabel, bIntent.nonLocalizedLabel);
-            assertEquals(aIntent.icon, bIntent.icon);
+            assertEquals(aIntent.isHasDefault(), bIntent.isHasDefault());
+            assertEquals(aIntent.getLabelRes(), bIntent.getLabelRes());
+            assertEquals(aIntent.getNonLocalizedLabel(), bIntent.getNonLocalizedLabel());
+            assertEquals(aIntent.getIcon(), bIntent.getIcon());
         }
     }
 
-    private static void assertPermissionsEqual(ParsedPermission a,
-            ParsedPermission b) {
+    private static void assertPermissionsEqual(ParsedPermission a, ParsedPermission b) {
         assertComponentsEqual(a, b);
-        assertEquals(a.tree, b.tree);
+        assertEquals(a.isTree(), b.isTree());
 
         // Verify basic flags in PermissionInfo to make sure they're consistent. We don't perform
         // a full structural equality here because the code that serializes them isn't parser
         // specific and is tested elsewhere.
         assertEquals(a.getProtection(), b.getProtection());
         assertEquals(a.getGroup(), b.getGroup());
-        assertEquals(a.flags, b.flags);
+        assertEquals(a.getFlags(), b.getFlags());
 
-        if (a.parsedPermissionGroup != null && b.parsedPermissionGroup != null) {
-            assertPermissionGroupsEqual(a.parsedPermissionGroup, b.parsedPermissionGroup);
-        } else if (a.parsedPermissionGroup != null || b.parsedPermissionGroup != null) {
+        if (a.getParsedPermissionGroup() != null && b.getParsedPermissionGroup() != null) {
+            assertPermissionGroupsEqual(a.getParsedPermissionGroup(), b.getParsedPermissionGroup());
+        } else if (a.getParsedPermissionGroup() != null || b.getParsedPermissionGroup() != null) {
             throw new AssertionError();
         }
     }
@@ -382,6 +402,8 @@
         // Sanity check for InstrumentationInfo.
         assertEquals(a.getTargetPackage(), b.getTargetPackage());
         assertEquals(a.getTargetProcesses(), b.getTargetProcesses());
+        assertEquals(a.isHandleProfiling(), b.isHandleProfiling());
+        assertEquals(a.isFunctionalTest(), b.isFunctionalTest());
     }
 
     private static void assertServicesEqual(
@@ -393,10 +415,10 @@
         assertComponentsEqual(a, b);
 
         // Sanity check for ServiceInfo.
-        ServiceInfo aInfo = PackageInfoUtils.generateServiceInfo(aPkg, a, 0, new PackageUserState(),
-                0);
-        ServiceInfo bInfo = PackageInfoUtils.generateServiceInfo(bPkg, b, 0, new PackageUserState(),
-                0);
+        ServiceInfo aInfo = PackageInfoUtils.generateServiceInfo(aPkg, a, 0,
+                new PackageUserState(), 0, mockPkgSetting(aPkg));
+        ServiceInfo bInfo = PackageInfoUtils.generateServiceInfo(bPkg, b, 0,
+                new PackageUserState(), 0, mockPkgSetting(bPkg));
         assertApplicationInfoEqual(aInfo.applicationInfo, bInfo.applicationInfo);
         assertEquals(a.getName(), b.getName());
     }
@@ -411,9 +433,9 @@
 
         // Sanity check for ProviderInfo
         ProviderInfo aInfo = PackageInfoUtils.generateProviderInfo(aPkg, a, 0,
-                new PackageUserState(), 0);
+                new PackageUserState(), 0, mockPkgSetting(aPkg));
         ProviderInfo bInfo = PackageInfoUtils.generateProviderInfo(bPkg, b, 0,
-                new PackageUserState(), 0);
+                new PackageUserState(), 0, mockPkgSetting(bPkg));
         assertApplicationInfoEqual(aInfo.applicationInfo, bInfo.applicationInfo);
         assertEquals(a.getName(), b.getName());
     }
@@ -428,9 +450,9 @@
 
         // Sanity check for ActivityInfo.
         ActivityInfo aInfo = PackageInfoUtils.generateActivityInfo(aPkg, a, 0,
-                new PackageUserState(), 0);
+                new PackageUserState(), 0, mockPkgSetting(aPkg));
         ActivityInfo bInfo = PackageInfoUtils.generateActivityInfo(bPkg, b, 0,
-                new PackageUserState(), 0);
+                new PackageUserState(), 0, mockPkgSetting(bPkg));
         assertApplicationInfoEqual(aInfo.applicationInfo, bInfo.applicationInfo);
         assertEquals(a.getName(), b.getName());
     }
@@ -441,7 +463,7 @@
 
         // Sanity check for PermissionGroupInfo.
         assertEquals(a.getName(), b.getName());
-        assertEquals(a.descriptionRes, b.descriptionRes);
+        assertEquals(a.getDescriptionRes(), b.getDescriptionRes());
     }
 
     private static void assertApplicationInfoEqual(ApplicationInfo a, ApplicationInfo that) {
@@ -494,12 +516,11 @@
         bundle.putString("key", "value");
 
         ParsedPermission permission = new ParsedPermission();
-        permission.parsedPermissionGroup = new ParsedPermissionGroup();
+        permission.setParsedPermissionGroup(new ParsedPermissionGroup());
 
-        pkg.setBaseRevisionCode(100)
+        ((ParsedPackage) pkg.setBaseRevisionCode(100)
                 .setBaseHardwareAccelerated(true)
                 .setSharedUserLabel(100)
-                .setPreferredOrder(100)
                 .setInstallLocation(100)
                 .setRequiredForAllUsers(true)
                 .asSplit(
@@ -510,7 +531,6 @@
                 )
                 .setUse32BitAbi(true)
                 .setVolumeUuid("foo3")
-                .setCodePath("foo4")
                 .addPermission(permission)
                 .addPermissionGroup(new ParsedPermissionGroup())
                 .addActivity(new ParsedActivity())
@@ -532,7 +552,7 @@
                 .addOriginalPackage("foo14")
                 .setRealPackage("foo15")
                 .addAdoptPermission("foo16")
-                .setAppMetaData(bundle)
+                .setMetaData(bundle)
                 .setVersionName("foo17")
                 .setSharedUserId("foo18")
                 .setSigningDetails(
@@ -547,8 +567,7 @@
                 .setOverlayTarget("foo21")
                 .setOverlayPriority(100)
                 .setUpgradeKeySets(new ArraySet<>())
-                .addPreferredActivityFilter(
-                        new ComponentParseUtils.ParsedActivityIntentInfo("foo", "className"))
+                .addPreferredActivityFilter("className", new ParsedIntentInfo())
                 .addConfigPreference(new ConfigurationInfo())
                 .addReqFeature(new FeatureInfo())
                 .addFeatureGroup(new FeatureGroupInfo())
@@ -559,19 +578,14 @@
                 .setOverlayTargetName("foo26")
                 .setVisibleToInstantApps(true)
                 .setSplitHasCode(0, true)
-                .hideAsParsed()
+                .hideAsParsed())
                 .setBaseCodePath("foo5")
+                .setCodePath("foo4")
                 .setVersionCode(100)
-                .setCpuAbiOverride("foo22")
                 .setRestrictUpdateHash(new byte[16])
                 .setVersionCodeMajor(100)
                 .setCoreApp(true)
-                .hideAsFinal()
-                .mutate()
-                .setUsesLibraryInfos(Arrays.asList(
-                        new SharedLibraryInfo(null, null, null, null, 0L, 0, null, null, null)
-                ))
-                .setUsesLibraryFiles(new String[]{"foo13"});
+                .hideAsFinal();
     }
 
     private static void assertAllFieldsExist(ParsedPackage pkg) throws Exception {
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java b/services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java
index 841cea2..d12ea894 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java
@@ -18,10 +18,11 @@
 
 import android.content.pm.PackageParser;
 import android.content.pm.PackageUserState;
-import android.content.pm.parsing.AndroidPackage;
 import android.util.ArraySet;
 import android.util.SparseArray;
 
+import com.android.server.pm.parsing.pkg.AndroidPackage;
+
 import java.io.File;
 import java.util.Map;
 
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..9d3ac17 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,14 @@
 package com.android.server.pm;
 
 import android.content.pm.PackageParser;
-import android.content.pm.parsing.ParsedPackage;
+import android.platform.test.annotations.Presubmit;
 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;
@@ -36,6 +39,7 @@
 /**
  * Tests for {@link ParallelPackageParser}
  */
+@Presubmit
 @RunWith(AndroidJUnit4.class)
 public class ParallelPackageParserTest {
     private static final String TAG = ParallelPackageParserTest.class.getSimpleName();
@@ -44,7 +48,7 @@
 
     @Before
     public void setUp() {
-        mParser = new TestParallelPackageParser(new PackageParser(),
+        mParser = new TestParallelPackageParser(new PackageParser2(null, false, null, null, null),
                 ParallelPackageParser.makeExecutorService());
     }
 
@@ -72,7 +76,7 @@
 
     private class TestParallelPackageParser extends ParallelPackageParser {
 
-        TestParallelPackageParser(PackageParser packageParser, ExecutorService executorService) {
+        TestParallelPackageParser(PackageParser2 packageParser, ExecutorService executorService) {
             super(packageParser, executorService);
         }
 
diff --git a/services/tests/servicestests/src/com/android/server/pm/SELinuxMMACTest.java b/services/tests/servicestests/src/com/android/server/pm/SELinuxMMACTest.java
index 30108c6..efc1c05 100644
--- a/services/tests/servicestests/src/com/android/server/pm/SELinuxMMACTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/SELinuxMMACTest.java
@@ -22,12 +22,13 @@
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.when;
 
-import android.content.pm.parsing.AndroidPackage;
-import android.content.pm.parsing.PackageImpl;
 import android.os.Build;
 import android.platform.test.annotations.Presubmit;
 
 import com.android.server.compat.PlatformCompat;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.parsing.pkg.PackageImpl;
+import com.android.server.pm.parsing.pkg.ParsedPackage;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -79,9 +80,9 @@
     }
 
     private AndroidPackage makePackage(int targetSdkVersion) {
-        return PackageImpl.forParsing(PACKAGE_NAME)
+        return ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
                 .setTargetSdkVersion(targetSdkVersion)
-                .hideAsParsed()
+                .hideAsParsed())
                 .hideAsFinal();
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/pm/ScanRequestBuilder.java b/services/tests/servicestests/src/com/android/server/pm/ScanRequestBuilder.java
index 11f154b..12fb400 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ScanRequestBuilder.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ScanRequestBuilder.java
@@ -16,10 +16,13 @@
 
 package com.android.server.pm;
 
-import android.content.pm.parsing.AndroidPackage;
-import android.content.pm.parsing.ParsedPackage;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.os.UserHandle;
 
+import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.parsing.pkg.ParsedPackage;
+
 class ScanRequestBuilder {
     private final ParsedPackage mPkg;
     private AndroidPackage mOldPkg;
@@ -32,6 +35,8 @@
     private int mScanFlags;
     private UserHandle mUser;
     private boolean mIsPlatformPackage;
+    @Nullable
+    private String mCpuAbiOverride;
 
     ScanRequestBuilder(ParsedPackage pkg) {
         this.mPkg = pkg;
@@ -97,10 +102,16 @@
         return this;
     }
 
+    @NonNull
+    public ScanRequestBuilder setCpuAbiOverride(@Nullable String cpuAbiOverride) {
+        this.mCpuAbiOverride = cpuAbiOverride;
+        return this;
+    }
+
     PackageManagerService.ScanRequest build() {
         return new PackageManagerService.ScanRequest(
                 mPkg, mSharedUserSetting, mOldPkg, mPkgSetting, mDisabledPkgSetting,
                 mOriginalPkgSetting, mRealPkgName, mParseFlags, mScanFlags, mIsPlatformPackage,
-                mUser);
+                mUser, mCpuAbiOverride);
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/pm/ScanTests.java b/services/tests/servicestests/src/com/android/server/pm/ScanTests.java
index 583cf58..09f946d 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ScanTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ScanTests.java
@@ -42,9 +42,6 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.SharedLibraryInfo;
-import android.content.pm.parsing.PackageImpl;
-import android.content.pm.parsing.PackageInfoUtils;
-import android.content.pm.parsing.ParsedPackage;
 import android.content.pm.parsing.ParsingPackage;
 import android.content.res.TypedArray;
 import android.os.Environment;
@@ -54,6 +51,10 @@
 import android.util.Pair;
 
 import com.android.server.compat.PlatformCompat;
+import com.android.server.pm.parsing.PackageInfoUtils;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.parsing.pkg.PackageImpl;
+import com.android.server.pm.parsing.pkg.ParsedPackage;
 
 import org.hamcrest.BaseMatcher;
 import org.hamcrest.Description;
@@ -101,18 +102,18 @@
     @Before
     public void setupDefaultAbiBehavior() throws Exception {
         when(mMockPackageAbiHelper.derivePackageAbi(
-                any(ParsedPackage.class), nullable(String.class), anyBoolean()))
+                any(AndroidPackage.class), anyBoolean(), nullable(String.class), anyBoolean()))
                 .thenReturn(new Pair<>(
                         new PackageAbiHelper.Abis("derivedPrimary", "derivedSecondary"),
                         new PackageAbiHelper.NativeLibraryPaths(
                                 "derivedRootDir", true, "derivedNativeDir", "derivedNativeDir2")));
         when(mMockPackageAbiHelper.getNativeLibraryPaths(
-                any(ParsedPackage.class), any(File.class)))
+                any(AndroidPackage.class), any(PackageSetting.class), any(File.class)))
                 .thenReturn(new PackageAbiHelper.NativeLibraryPaths(
                         "getRootDir", true, "getNativeDir", "getNativeDir2"
                 ));
         when(mMockPackageAbiHelper.getBundledAppAbis(
-                any(ParsedPackage.class)))
+                any(AndroidPackage.class)))
                 .thenReturn(new PackageAbiHelper.Abis("bundledPrimary", "bundledSecondary"));
     }
 
@@ -223,10 +224,10 @@
 
     @Test
     public void installStaticSharedLibrary() throws Exception {
-        final ParsedPackage pkg = createBasicPackage("static.lib.pkg")
+        final ParsedPackage pkg = ((ParsedPackage) createBasicPackage("static.lib.pkg")
                 .setStaticSharedLibName("static.lib")
                 .setStaticSharedLibVersion(123L)
-                .hideAsParsed()
+                .hideAsParsed())
                 .setPackageName("static.lib.pkg.123")
                 .setVersionCodeMajor(1)
                 .setVersionCode(234)
@@ -255,10 +256,11 @@
 
     @Test
     public void installDynamicLibraries() throws Exception {
-        final ParsedPackage pkg = createBasicPackage("dynamic.lib.pkg")
+        final ParsedPackage pkg = ((ParsedPackage) createBasicPackage(
+                "dynamic.lib.pkg")
                 .addLibraryName("liba")
                 .addLibraryName("libb")
-                .hideAsParsed()
+                .hideAsParsed())
                 .setVersionCodeMajor(1)
                 .setVersionCode(234)
                 .setBaseCodePath("/some/path.apk")
@@ -304,9 +306,9 @@
                         .setVolumeUuid("someUuid")
                         .build();
 
-        final ParsedPackage basicPackage = createBasicPackage(DUMMY_PACKAGE_NAME)
-                .hideAsParsed()
-                .setApplicationVolumeUuid(UUID_TWO.toString());
+        final ParsedPackage basicPackage = ((ParsedPackage) createBasicPackage(DUMMY_PACKAGE_NAME)
+                .setVolumeUuid(UUID_TWO.toString())
+                .hideAsParsed());
 
 
         final PackageManagerService.ScanResult scanResult = executeScan(
@@ -321,9 +323,8 @@
                 createBasicPackageSettingBuilder(DUMMY_PACKAGE_NAME).build();
 
         final ParsedPackage basicPackage =
-                createBasicPackage(DUMMY_PACKAGE_NAME)
-                        .hideAsParsed()
-                        .setCpuAbiOverride("testOverride");
+                ((ParsedPackage) createBasicPackage(DUMMY_PACKAGE_NAME)
+                        .hideAsParsed());
 
 
         final PackageManagerService.ScanResult scanResult = executeScan(new ScanRequestBuilder(
@@ -341,7 +342,7 @@
                 createBasicPackageSettingBuilder("original.package").build();
 
         final ParsedPackage basicPackage =
-                createBasicPackage(DUMMY_PACKAGE_NAME)
+                (ParsedPackage) createBasicPackage(DUMMY_PACKAGE_NAME)
                         .hideAsParsed();
 
 
@@ -411,8 +412,9 @@
 
         final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
 
-        assertThat(scanResult.request.parsedPackage.getFlags(),
-                hasFlag(ApplicationInfo.FLAG_UPDATED_SYSTEM_APP));
+        int appInfoFlags = PackageInfoUtils.appInfoFlags(scanResult.request.parsedPackage,
+                scanResult.pkgSetting);
+        assertThat(appInfoFlags, hasFlag(ApplicationInfo.FLAG_UPDATED_SYSTEM_APP));
     }
 
     @Test
@@ -426,14 +428,15 @@
                 true /*isUnderFactoryTest*/,
                 System.currentTimeMillis());
 
-        assertThat(scanResult.request.parsedPackage.getFlags(),
-                hasFlag(ApplicationInfo.FLAG_FACTORY_TEST));
+        int appInfoFlags = PackageInfoUtils.appInfoFlags(scanResult.request.parsedPackage,
+                scanResult.request.pkgSetting);
+        assertThat(appInfoFlags, hasFlag(ApplicationInfo.FLAG_FACTORY_TEST));
     }
 
     @Test
     public void scanSystemApp_isOrphanedTrue() throws Exception {
-        final ParsedPackage pkg = createBasicPackage(DUMMY_PACKAGE_NAME)
-                .hideAsParsed()
+        final ParsedPackage pkg = ((ParsedPackage) createBasicPackage(DUMMY_PACKAGE_NAME)
+                .hideAsParsed())
                 .setSystem(true);
 
         final PackageManagerService.ScanRequest scanRequest =
@@ -474,10 +477,6 @@
                 System.currentTimeMillis());
     }
 
-    private static String createResourcePath(String packageName) {
-        return "/data/app/" + packageName + "-randompath/base.apk";
-    }
-
     private static String createCodePath(String packageName) {
         return "/data/app/" + packageName + "-randompath";
     }
@@ -486,11 +485,11 @@
         return new PackageSettingBuilder()
                 .setName(packageName)
                 .setCodePath(createCodePath(packageName))
-                .setResourcePath(createResourcePath(packageName));
+                .setResourcePath(createCodePath(packageName));
     }
 
     private static ScanRequestBuilder createBasicScanRequestBuilder(ParsingPackage pkg) {
-        return new ScanRequestBuilder(pkg.hideAsParsed())
+        return new ScanRequestBuilder((ParsedPackage) pkg.hideAsParsed())
                 .setUser(UserHandle.of(0));
     }
 
@@ -501,16 +500,15 @@
 
     private static ParsingPackage createBasicPackage(String packageName) {
         // TODO(b/135203078): Make this use PackageImpl.forParsing and separate the steps
-        return new PackageImpl(packageName, null, mock(TypedArray.class), false)
-                .setCodePath("/data/tmp/randompath")
-                .setApplicationInfoCodePath(createCodePath(packageName))
-                .setApplicationInfoResourcePath(createResourcePath(packageName))
-                .setApplicationVolumeUuid(UUID_ONE.toString())
-                .setBaseCodePath("/data/tmp/randompath/base.apk")
+        return (ParsingPackage) ((ParsedPackage) new PackageImpl(packageName,
+                "/data/tmp/randompath/base.apk", createCodePath(packageName),
+                mock(TypedArray.class), false)
+                .setVolumeUuid(UUID_ONE.toString())
                 .addUsesStaticLibrary("some.static.library")
                 .addUsesStaticLibraryVersion(234L)
                 .addUsesStaticLibrary("some.other.static.library")
                 .addUsesStaticLibraryVersion(456L)
+                .hideAsParsed())
                 .setNativeLibraryRootDir("/data/tmp/randompath/base.apk:/lib")
                 .setVersionCodeMajor(1)
                 .setVersionCode(2345);
@@ -524,7 +522,7 @@
         assertBasicPackageSetting(scanResult, packageName, isInstant, pkgSetting);
 
         final ApplicationInfo applicationInfo = PackageInfoUtils.generateApplicationInfo(
-                pkgSetting.pkg, 0, pkgSetting.readUserState(0), 0);
+                pkgSetting.pkg, 0, pkgSetting.readUserState(0), 0, pkgSetting);
         assertBasicApplicationInfo(scanResult, applicationInfo);
     }
 
@@ -537,7 +535,7 @@
         assertThat(pkgSetting.usesStaticLibrariesVersions, is(new long[]{234L, 456L}));
         assertThat(pkgSetting.pkg, is(scanResult.request.parsedPackage));
         assertThat(pkgSetting.codePath, is(new File(createCodePath(packageName))));
-        assertThat(pkgSetting.resourcePath, is(new File(createResourcePath(packageName))));
+        assertThat(pkgSetting.resourcePath, is(new File(createCodePath(packageName))));
         assertThat(pkgSetting.versionCode, is(PackageInfo.composeLongVersionCode(1, 2345)));
     }
 
@@ -559,7 +557,7 @@
     private static void assertAbiAndPathssDerived(PackageManagerService.ScanResult scanResult) {
         PackageSetting pkgSetting = scanResult.pkgSetting;
         final ApplicationInfo applicationInfo = PackageInfoUtils.generateApplicationInfo(
-                pkgSetting.pkg, 0, pkgSetting.readUserState(0), 0);
+                pkgSetting.pkg, 0, pkgSetting.readUserState(0), 0, pkgSetting);
         assertThat(applicationInfo.primaryCpuAbi, is("derivedPrimary"));
         assertThat(applicationInfo.secondaryCpuAbi, is("derivedSecondary"));
 
@@ -573,7 +571,7 @@
     private static void assertPathsNotDerived(PackageManagerService.ScanResult scanResult) {
         PackageSetting pkgSetting = scanResult.pkgSetting;
         final ApplicationInfo applicationInfo = PackageInfoUtils.generateApplicationInfo(
-                pkgSetting.pkg, 0, pkgSetting.readUserState(0), 0);
+                pkgSetting.pkg, 0, pkgSetting.readUserState(0), 0, pkgSetting);
         assertThat(applicationInfo.nativeLibraryRootDir, is("getRootDir"));
         assertThat(pkgSetting.legacyNativeLibraryPathString, is("getRootDir"));
         assertThat(applicationInfo.nativeLibraryRootRequiresIsa, is(true));
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
index 2936bdd..56460fb 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
@@ -379,6 +379,113 @@
         });
     }
 
+    public void testPushDynamicShortcut() {
+
+        setCaller(CALLING_PACKAGE_1, USER_0);
+
+        final ShortcutInfo s1 = makeShortcut("s1");
+        final ShortcutInfo s2 = makeShortcut("s2");
+        final ShortcutInfo s3 = makeShortcut("s3");
+        final ShortcutInfo s4 = makeShortcut("s4");
+
+        final ShortcutInfo s10 = makeShortcut("s10");
+        final ShortcutInfo s11 = makeShortcut("s11");
+        final ShortcutInfo s12 = makeShortcut("s12");
+        final ShortcutInfo s13 = makeShortcut("s13");
+        final ShortcutInfo s14 = makeShortcut("s14");
+
+        // Test push as first shortcut
+        mManager.pushDynamicShortcut(s1);
+        assertShortcutIds(assertAllNotKeyFieldsOnly(mManager.getDynamicShortcuts()), "s1");
+        assertEquals(0, getCallerShortcut("s1").getRank());
+
+        // Test push when other shortcuts exist
+        assertTrue(mManager.setDynamicShortcuts(list(s1, s2)));
+        assertShortcutIds(assertAllNotKeyFieldsOnly(mManager.getDynamicShortcuts()), "s1", "s2");
+        mManager.pushDynamicShortcut(s3);
+        assertShortcutIds(assertAllNotKeyFieldsOnly(mManager.getDynamicShortcuts()),
+                "s1", "s2", "s3");
+        assertEquals(0, getCallerShortcut("s3").getRank());
+        assertEquals(1, getCallerShortcut("s1").getRank());
+        assertEquals(2, getCallerShortcut("s2").getRank());
+
+        mInjectedCurrentTimeMillis += INTERVAL; // reset
+
+        // Push with set rank
+        s4.setRank(2);
+        mManager.pushDynamicShortcut(s4);
+        assertEquals(2, getCallerShortcut("s4").getRank());
+        assertEquals(3, getCallerShortcut("s2").getRank());
+
+        // Push existing shortcut with set rank
+        final ShortcutInfo s4_2 = makeShortcut("s4");
+        s4_2.setRank(4);
+        mManager.pushDynamicShortcut(s4_2);
+        assertEquals(2, getCallerShortcut("s2").getRank());
+        assertEquals(3, getCallerShortcut("s4").getRank());
+
+        mInjectedCurrentTimeMillis += INTERVAL; // reset
+
+        // Test push as last
+        assertTrue(mManager.addDynamicShortcuts(makeShortcuts("s5", "s6", "s7", "s8", "s9")));
+        mManager.pushDynamicShortcut(s10);
+        assertShortcutIds(assertAllNotKeyFieldsOnly(mManager.getDynamicShortcuts()),
+                "s1", "s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9", "s10");
+        assertEquals(0, getCallerShortcut("s10").getRank());
+        assertEquals(1, getCallerShortcut("s5").getRank());
+        assertEquals(6, getCallerShortcut("s3").getRank());
+        assertEquals(7, getCallerShortcut("s1").getRank());
+        assertEquals(8, getCallerShortcut("s2").getRank());
+        assertEquals(9, getCallerShortcut("s4").getRank());
+
+        // Push when max has already reached
+        mManager.pushDynamicShortcut(s11);
+        assertShortcutIds(assertAllNotKeyFieldsOnly(mManager.getDynamicShortcuts()),
+                "s1", "s2", "s3", "s5", "s6", "s7", "s8", "s9", "s10", "s11");
+        assertEquals(0, getCallerShortcut("s11").getRank());
+        assertEquals(1, getCallerShortcut("s10").getRank());
+        assertEquals(9, getCallerShortcut("s2").getRank());
+
+        mInjectedCurrentTimeMillis += INTERVAL; // reset
+
+        // Push with different activity
+        s12.setActivity(makeComponent(ShortcutActivity2.class));
+        mManager.pushDynamicShortcut(s12);
+        assertEquals(makeComponent(ShortcutActivity2.class),
+                getCallerShortcut("s12").getActivity());
+        assertEquals(0, getCallerShortcut("s12").getRank());
+
+        // Push to update shortcut with different activity
+        final ShortcutInfo s1_2 = makeShortcut("s1");
+        s1_2.setActivity(makeComponent(ShortcutActivity2.class));
+        s1_2.setRank(1);
+        mManager.pushDynamicShortcut(s1_2);
+        assertEquals(0, getCallerShortcut("s12").getRank());
+        assertEquals(1, getCallerShortcut("s1").getRank());
+        assertEquals(0, getCallerShortcut("s11").getRank());
+        assertEquals(1, getCallerShortcut("s10").getRank());
+        assertEquals(7, getCallerShortcut("s3").getRank());
+        assertEquals(8, getCallerShortcut("s2").getRank());
+
+        mInjectedCurrentTimeMillis += INTERVAL; // reset
+
+        // Test push when dropped shortcut is cached
+        s13.setLongLived();
+        s13.setRank(100);
+        mManager.pushDynamicShortcut(s13);
+        assertEquals(9, getCallerShortcut("s13").getRank());
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s13"), HANDLE_USER_0);
+        });
+
+        mManager.pushDynamicShortcut(s14);
+        assertShortcutIds(assertAllNotKeyFieldsOnly(mManager.getDynamicShortcuts()),
+                "s1", "s2", "s3", "s5", "s6", "s7", "s8", "s9", "s10", "s11", "s12", "s14");
+        // Verify s13 stayed as cached
+        assertShortcutIds(mManager.getShortcuts(ShortcutManager.FLAG_MATCH_CACHED),
+                "s13");
+    }
+
     public void testUnlimitedCalls() {
         setCaller(CALLING_PACKAGE_1, USER_0);
 
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
index 118c540..bec37e9 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
@@ -812,7 +812,7 @@
                 "android", 0, mUserManager.getPrimaryUser().getUserHandle())
                 .getSystemService(Context.USER_SERVICE);
 
-        List<UserHandle> profiles = um.getUserProfiles(false);
+        List<UserHandle> profiles = um.getAllProfiles();
         assertThat(profiles.size()).isEqualTo(2);
         assertThat(profiles.get(0).equals(userProfile.getUserHandle())
                 || profiles.get(1).equals(userProfile.getUserHandle())).isTrue();
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java
index 3db832b..ce21099 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java
@@ -39,8 +39,6 @@
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.UserInfo;
-import android.content.pm.parsing.AndroidPackage;
-import android.content.pm.parsing.PackageImpl;
 import android.os.Looper;
 import android.os.SystemProperties;
 import android.os.UserManager;
@@ -56,6 +54,9 @@
 
 import com.android.server.LocalServices;
 import com.android.server.SystemConfig;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.parsing.pkg.PackageImpl;
+import com.android.server.pm.parsing.pkg.ParsedPackage;
 
 import org.junit.After;
 import org.junit.Before;
@@ -252,14 +253,14 @@
         final Set<String> userWhitelist = new ArraySet<>();
         userWhitelist.add(packageName1);
 
-        final AndroidPackage pkg1 = PackageImpl.forParsing(packageName1)
-                .hideAsParsed().hideAsFinal();
-        final AndroidPackage pkg2 = PackageImpl.forParsing(packageName2)
-                .hideAsParsed().hideAsFinal();
-        final AndroidPackage pkg3 = PackageImpl.forParsing(packageName3)
-                .hideAsParsed().hideAsFinal();
-        final AndroidPackage pkg4 = PackageImpl.forParsing(packageName4)
-                .hideAsParsed().hideAsFinal();
+        final AndroidPackage pkg1 = ((ParsedPackage) PackageImpl.forTesting(packageName1)
+                .hideAsParsed()).hideAsFinal();
+        final AndroidPackage pkg2 = ((ParsedPackage) PackageImpl.forTesting(packageName2)
+                .hideAsParsed()).hideAsFinal();
+        final AndroidPackage pkg3 = ((ParsedPackage) PackageImpl.forTesting(packageName3)
+                .hideAsParsed()).hideAsFinal();
+        final AndroidPackage pkg4 = ((ParsedPackage) PackageImpl.forTesting(packageName4)
+                .hideAsParsed()).hideAsFinal();
 
         // No implicit whitelist, so only install pkg1.
         boolean implicit = false;
diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java b/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java
index f5e5e2a..d69e1b8 100644
--- a/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java
@@ -532,6 +532,61 @@
         assertHasDclInfo(mBarUser0, mBarUser0, secondaries);
     }
 
+    @Test
+    public void testPrimaryAndSecondaryDexLoad() {
+        // Foo loads both primary and secondary dexes
+        List<String> fooSecondaries = mFooUser0.getSecondaryDexPaths();
+        List<String> fooDexes = new ArrayList<>(mFooUser0.getBaseAndSplitDexPaths());
+        int primaryCount = fooDexes.size();
+        fooDexes.addAll(fooSecondaries);
+
+        notifyDexLoad(mFooUser0, fooDexes, mUser0);
+
+        PackageUseInfo pui = getPackageUseInfo(mFooUser0);
+        assertIsUsedByOtherApps(mFooUser0, pui, false);
+        assertEquals(fooSecondaries.size(), pui.getDexUseInfoMap().size());
+
+        // Below we want to verify that the secondary dex files within fooDexes have been correctly
+        // reported and their class loader contexts were correctly recorded.
+        //
+        // In order to achieve this we first use DexoptUtils.processContextForDexLoad to compute the
+        // class loader contexts for all the dex files.
+        String[] allClassLoaderContexts = DexoptUtils.processContextForDexLoad(
+                Arrays.asList(mFooUser0.mClassLoader),
+                Arrays.asList(String.join(File.pathSeparator, fooDexes)));
+        // Next we filter out the class loader contexts corresponding to non-secondary dex files.
+        String[] secondaryClassLoaderContexts = Arrays.copyOfRange(allClassLoaderContexts,
+                primaryCount, allClassLoaderContexts.length);
+        assertSecondaryUse(mFooUser0, pui, fooSecondaries, /*isUsedByOtherApps*/false, mUser0,
+                secondaryClassLoaderContexts);
+
+        assertHasDclInfo(mFooUser0, mFooUser0, fooSecondaries);
+    }
+
+    @Test
+    public void testNotifySecondary_withSharedLibrary() {
+        // Foo loads its own secondary files.
+        List<String> fooSecondaries = mFooUser0.getSecondaryDexPaths();
+
+        String contextSuffix = "{PCL[/system/framework/org.apache.http.legacy.jar]}";
+        String[] expectedContexts = DexoptUtils.processContextForDexLoad(
+                Arrays.asList(mFooUser0.mClassLoader),
+                Arrays.asList(String.join(File.pathSeparator, fooSecondaries)));
+        for (int i = 0; i < expectedContexts.length; i++) {
+            expectedContexts[i] += contextSuffix;
+        }
+
+        notifyDexLoad(mFooUser0, fooSecondaries, expectedContexts, mUser0);
+
+        PackageUseInfo pui = getPackageUseInfo(mFooUser0);
+        assertIsUsedByOtherApps(mFooUser0, pui, false);
+        assertEquals(fooSecondaries.size(), pui.getDexUseInfoMap().size());
+        assertSecondaryUse(mFooUser0, pui, fooSecondaries, /*isUsedByOtherApps*/false, mUser0,
+                expectedContexts);
+
+        assertHasDclInfo(mFooUser0, mFooUser0, fooSecondaries);
+    }
+
     private void assertSecondaryUse(TestData testData, PackageUseInfo pui,
             List<String> secondaries, boolean isUsedByOtherApps, int ownerUserId,
             String[] expectedContexts) {
@@ -572,17 +627,43 @@
         // By default, assume a single class loader in the chain.
         // This makes writing tests much easier.
         List<String> classLoaders = Arrays.asList(testData.mClassLoader);
-        List<String> classPaths = (dexPaths == null)
-                                  ? Arrays.asList((String) null)
-                                  : Arrays.asList(String.join(File.pathSeparator, dexPaths));
+        List<String> classPaths = dexPaths != null
+                ? Arrays.<String>asList(String.join(File.pathSeparator, dexPaths)) : null;
         notifyDexLoad(testData, classLoaders, classPaths, loaderUserId);
     }
 
     private void notifyDexLoad(TestData testData, List<String> classLoaders,
             List<String> classPaths, int loaderUserId) {
+        String[] classLoaderContexts = computeClassLoaderContexts(classLoaders, classPaths);
         // We call the internal function so any exceptions thrown cause test failures.
-        mDexManager.notifyDexLoadInternal(testData.mPackageInfo.applicationInfo, classLoaders,
-                classPaths, testData.mLoaderIsa, loaderUserId);
+        List<String> dexPaths = classPaths != null
+                ? Arrays.asList(classPaths.get(0).split(File.pathSeparator)) : Arrays.asList();
+        notifyDexLoad(testData, dexPaths, classLoaderContexts, loaderUserId);
+    }
+
+    private void notifyDexLoad(TestData testData, List<String> dexPaths,
+            String[] classLoaderContexts, int loaderUserId) {
+        assertTrue(dexPaths.size() == classLoaderContexts.length);
+        HashMap<String, String> dexPathMapping = new HashMap<>(dexPaths.size());
+        for (int i = 0; i < dexPaths.size(); i++) {
+            dexPathMapping.put(dexPaths.get(i), classLoaderContexts != null
+                    ? classLoaderContexts[i] : PackageDexUsage.UNSUPPORTED_CLASS_LOADER_CONTEXT);
+        }
+        mDexManager.notifyDexLoadInternal(testData.mPackageInfo.applicationInfo, dexPathMapping,
+                testData.mLoaderIsa, loaderUserId);
+    }
+
+    private String[] computeClassLoaderContexts(List<String> classLoaders,
+            List<String> classPaths) {
+        if (classPaths == null) {
+            return new String[0];
+        }
+        String[] results = DexoptUtils.processContextForDexLoad(classLoaders, classPaths);
+        if (results == null) {
+            results = new String[classPaths.get(0).split(File.pathSeparator).length];
+            Arrays.fill(results, PackageDexUsage.UNSUPPORTED_CLASS_LOADER_CONTEXT);
+        }
+        return results;
     }
 
     private PackageUseInfo getPackageUseInfo(TestData testData) {
diff --git a/core/tests/coretests/src/android/content/pm/dex/DexMetadataHelperTest.java b/services/tests/servicestests/src/com/android/server/pm/dex/DexMetadataHelperTest.java
similarity index 86%
rename from core/tests/coretests/src/android/content/pm/dex/DexMetadataHelperTest.java
rename to services/tests/servicestests/src/com/android/server/pm/dex/DexMetadataHelperTest.java
index 1e0bfb0..f87f68d 100644
--- a/core/tests/coretests/src/android/content/pm/dex/DexMetadataHelperTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/dex/DexMetadataHelperTest.java
@@ -1,5 +1,5 @@
-/**
- * Copyright (C) 2018 The Android Open Source Project
+/*
+ * 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.
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.content.pm.dex;
+package com.android.server.pm.dex;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
@@ -27,14 +27,17 @@
 import android.content.pm.PackageParser.ApkLite;
 import android.content.pm.PackageParser.PackageLite;
 import android.content.pm.PackageParser.PackageParserException;
-import android.content.pm.parsing.ParsedPackage;
+import android.content.pm.dex.DexMetadataHelper;
 import android.os.FileUtils;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import com.android.frameworks.coretests.R;
+import com.android.frameworks.servicestests.R;
+import com.android.server.pm.parsing.PackageParser2;
+import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
+import com.android.server.pm.parsing.pkg.ParsedPackage;
 
 import org.junit.Assert;
 import org.junit.Before;
@@ -90,13 +93,17 @@
         return outFile;
     }
 
+    private PackageParser2 makeParser() {
+        return new PackageParser2(null, false, null, null, null);
+    }
+
     @Test
     public void testParsePackageWithDmFileValid() throws IOException, PackageParserException {
         copyApkToToTmpDir("install_split_base.apk", R.raw.install_split_base);
         createDexMetadataFile("install_split_base.apk");
-        ParsedPackage pkg = new PackageParser().parseParsedPackage(mTmpDir, 0 /* flags */, false);
+        ParsedPackage pkg = makeParser().parsePackage(mTmpDir, 0 /* flags */, false);
 
-        Map<String, String> packageDexMetadata = DexMetadataHelper.getPackageDexMetadata(pkg);
+        Map<String, String> packageDexMetadata = AndroidPackageUtils.getPackageDexMetadata(pkg);
         assertEquals(1, packageDexMetadata.size());
         String baseDexMetadata = packageDexMetadata.get(pkg.getBaseCodePath());
         assertNotNull(baseDexMetadata);
@@ -110,9 +117,9 @@
         copyApkToToTmpDir("install_split_feature_a.apk", R.raw.install_split_feature_a);
         createDexMetadataFile("install_split_base.apk");
         createDexMetadataFile("install_split_feature_a.apk");
-        ParsedPackage pkg = new PackageParser().parseParsedPackage(mTmpDir, 0 /* flags */, false);
+        ParsedPackage pkg = makeParser().parsePackage(mTmpDir, 0 /* flags */, false);
 
-        Map<String, String> packageDexMetadata = DexMetadataHelper.getPackageDexMetadata(pkg);
+        Map<String, String> packageDexMetadata = AndroidPackageUtils.getPackageDexMetadata(pkg);
         assertEquals(2, packageDexMetadata.size());
         String baseDexMetadata = packageDexMetadata.get(pkg.getBaseCodePath());
         assertNotNull(baseDexMetadata);
@@ -129,9 +136,9 @@
         copyApkToToTmpDir("install_split_base.apk", R.raw.install_split_base);
         copyApkToToTmpDir("install_split_feature_a.apk", R.raw.install_split_feature_a);
         createDexMetadataFile("install_split_feature_a.apk");
-        ParsedPackage pkg = new PackageParser().parseParsedPackage(mTmpDir, 0 /* flags */, false);
+        ParsedPackage pkg = makeParser().parsePackage(mTmpDir, 0 /* flags */, false);
 
-        Map<String, String> packageDexMetadata = DexMetadataHelper.getPackageDexMetadata(pkg);
+        Map<String, String> packageDexMetadata = AndroidPackageUtils.getPackageDexMetadata(pkg);
         assertEquals(1, packageDexMetadata.size());
 
         String splitDexMetadata = packageDexMetadata.get(pkg.getSplitCodePaths()[0]);
@@ -145,9 +152,8 @@
         File invalidDmFile = new File(mTmpDir, "install_split_base.dm");
         Files.createFile(invalidDmFile.toPath());
         try {
-            ParsedPackage pkg = new PackageParser()
-                    .parseParsedPackage(mTmpDir, 0 /* flags */, false);
-            DexMetadataHelper.validatePackageDexMetadata(pkg);
+            ParsedPackage pkg = makeParser().parsePackage(mTmpDir, 0 /* flags */, false);
+            AndroidPackageUtils.validatePackageDexMetadata(pkg);
         } catch (PackageParserException e) {
             assertEquals(e.error, PackageManager.INSTALL_FAILED_BAD_DEX_METADATA);
         }
@@ -163,9 +169,8 @@
         Files.createFile(invalidDmFile.toPath());
 
         try {
-            ParsedPackage pkg = new PackageParser()
-                    .parseParsedPackage(mTmpDir, 0 /* flags */, false);
-            DexMetadataHelper.validatePackageDexMetadata(pkg);
+            ParsedPackage pkg = makeParser().parsePackage(mTmpDir, 0 /* flags */, false);
+            AndroidPackageUtils.validatePackageDexMetadata(pkg);
         } catch (PackageParserException e) {
             assertEquals(e.error, PackageManager.INSTALL_FAILED_BAD_DEX_METADATA);
         }
diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java b/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java
index 66a4946..3846be0 100644
--- a/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java
@@ -23,15 +23,16 @@
 import static org.junit.Assert.fail;
 
 import android.content.pm.SharedLibraryInfo;
-import android.content.pm.parsing.AndroidPackage;
-import android.content.pm.parsing.PackageImpl;
-import android.content.pm.parsing.ParsedPackage;
 import android.content.pm.parsing.ParsingPackage;
 import android.util.SparseArray;
 
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.parsing.pkg.PackageImpl;
+import com.android.server.pm.parsing.pkg.ParsedPackage;
+
 import dalvik.system.DelegateLastClassLoader;
 import dalvik.system.DexClassLoader;
 import dalvik.system.PathClassLoader;
@@ -61,7 +62,8 @@
     private TestData createMockApplicationInfo(String baseClassLoader, boolean addSplits,
             boolean addSplitDependencies, boolean isolatedSplitLoading) {
         String codeDir = "/data/app/mock.android.com";
-        ParsingPackage parsingPackage = PackageImpl.forParsing("mock.android.com")
+        ParsingPackage parsingPackage = PackageImpl.forTesting("mock.android.com",
+                codeDir + "/base.dex")
                 .setClassLoaderName(baseClassLoader);
 
         parsingPackage.setIsolatedSplitLoading(isolatedSplitLoading);
@@ -122,8 +124,7 @@
                     .setSplitClassLoaderName(7, null);
         }
 
-        ParsedPackage parsedPackage = parsingPackage.hideAsParsed()
-                .setBaseCodePath(codeDir + "/base.dex");
+        ParsedPackage parsedPackage = (ParsedPackage) parsingPackage.hideAsParsed();
 
         TestData data = new TestData();
         data.pkg = parsedPackage.hideAsFinal();
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageInfoFlagBehaviorTest.kt b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageInfoFlagBehaviorTest.kt
index 27d02e1..0a32e4a 100644
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageInfoFlagBehaviorTest.kt
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageInfoFlagBehaviorTest.kt
@@ -20,9 +20,10 @@
 import android.content.pm.PackageInfo
 import android.content.pm.PackageManager
 import android.content.pm.PackageParser
-import android.content.pm.parsing.AndroidPackage
+import android.platform.test.annotations.Presubmit
 import com.android.server.pm.parsing.AndroidPackageInfoFlagBehaviorTest.Companion.Param.Companion.appInfo
 import com.android.server.pm.parsing.AndroidPackageInfoFlagBehaviorTest.Companion.Param.Companion.pkgInfo
+import com.android.server.pm.parsing.pkg.AndroidPackage
 import com.google.common.truth.Truth.assertThat
 import com.google.common.truth.Truth.assertWithMessage
 import org.junit.Test
@@ -36,6 +37,7 @@
  * This test has to be updated manually whenever the info generation behavior changes, since
  * there's no single place where flag -> field is defined besides this test.
  */
+@Presubmit
 @RunWith(Parameterized::class)
 class AndroidPackageInfoFlagBehaviorTest : AndroidPackageParsingTestBase() {
 
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingEquivalenceTest.kt b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingEquivalenceTest.kt
index 925af7f..191c038 100644
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingEquivalenceTest.kt
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingEquivalenceTest.kt
@@ -17,6 +17,7 @@
 package com.android.server.pm.parsing
 
 import android.content.pm.PackageManager
+import android.platform.test.annotations.Presubmit
 import com.google.common.truth.Truth.assertWithMessage
 import org.junit.Test
 
@@ -24,6 +25,7 @@
  * Collects APKs from the device and verifies that the new parsing behavior outputs
  * the same exposed Info object as the old parsing logic.
  */
+@Presubmit
 class AndroidPackageParsingEquivalenceTest : AndroidPackageParsingTestBase() {
 
     @Test
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt
index afd6e18..ca6b296 100644
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt
@@ -27,26 +27,27 @@
 import android.content.pm.PackageUserState
 import android.content.pm.PermissionInfo
 import android.content.pm.ProviderInfo
-import android.content.pm.parsing.AndroidPackage
-import android.content.pm.parsing.PackageImpl
-import android.content.pm.parsing.PackageInfoUtils
 import android.os.Debug
 import android.os.Environment
 import android.util.SparseArray
 import androidx.test.platform.app.InstrumentationRegistry
+import com.android.server.om.mockThrowOnUnmocked
+import com.android.server.om.whenever
 import com.android.server.pm.PackageManagerService
+import com.android.server.pm.PackageSetting
+import com.android.server.pm.parsing.pkg.AndroidPackage
+import com.android.server.pm.pkg.PackageStateUnserialized
 import org.junit.BeforeClass
 import org.mockito.Mockito
+import org.mockito.Mockito.anyInt
+import org.mockito.Mockito.mock
 import java.io.File
 
 open class AndroidPackageParsingTestBase {
 
     companion object {
 
-        /**
-         * By default, don't parse all APKs on device, only the framework one.
-         * Toggle this manually if working on package parsing.
-         */
+        // TODO(chiuwinson): Enable in separate change to fail all presubmit builds and fix errors
         private const val VERIFY_ALL_APKS = false
 
         /** For auditing memory usage differences */
@@ -59,6 +60,11 @@
             setCallback { true }
         }
 
+        protected val packageParser2 = PackageParser2(null, false, context.resources.displayMetrics,
+                null, object : PackageParser2.Callback() {
+            override fun hasFeature(feature: String?) = true
+        })
+
         /**
          * It would be difficult to mock all possibilities, so just use the APKs on device.
          * Unfortunately, this means the device must be bootable to verify potentially
@@ -80,9 +86,9 @@
                             .toList()
                 }
 
-        private val dummyState = Mockito.mock(PackageUserState::class.java).apply {
+        private val dummyUserState = mock(PackageUserState::class.java).apply {
             installed = true
-            Mockito.`when`(isAvailable(Mockito.anyInt())).thenReturn(true)
+            Mockito.`when`(isAvailable(anyInt())).thenReturn(true)
         }
 
         lateinit var oldPackages: List<PackageParser.Package>
@@ -98,7 +104,7 @@
             }
 
             this.newPackages = apks.map {
-                packageParser.parseParsedPackage(it, PackageParser.PARSE_IS_SYSTEM_DIR, false)
+                packageParser2.parsePackage(it, PackageParser.PARSE_IS_SYSTEM_DIR, false)
             }
 
             if (DUMP_HPROF_TO_EXTERNAL) {
@@ -111,19 +117,27 @@
         }
 
         fun oldAppInfo(pkg: PackageParser.Package, flags: Int = 0): ApplicationInfo? {
-            return PackageParser.generateApplicationInfo(pkg, flags, dummyState, 0)
+            return PackageParser.generateApplicationInfo(pkg, flags, dummyUserState, 0)
         }
 
         fun newAppInfo(pkg: AndroidPackage, flags: Int = 0): ApplicationInfo? {
-            return PackageInfoUtils.generateApplicationInfo(pkg, flags, dummyState, 0)
+            return PackageInfoUtils.generateApplicationInfo(pkg, flags, dummyUserState, 0,
+                    mockPkgSetting(pkg))
         }
 
         fun oldPackageInfo(pkg: PackageParser.Package, flags: Int = 0): PackageInfo? {
-            return PackageParser.generatePackageInfo(pkg, intArrayOf(), flags, 5, 6, emptySet(), dummyState)
+            return PackageParser.generatePackageInfo(pkg, intArrayOf(), flags, 5, 6, emptySet(),
+                    dummyUserState)
         }
 
         fun newPackageInfo(pkg: AndroidPackage, flags: Int = 0): PackageInfo? {
-            return PackageInfoUtils.generate(pkg, intArrayOf(), flags, 5, 6, emptySet(), dummyState, 0)
+            return PackageInfoUtils.generate(pkg, intArrayOf(), flags, 5, 6, emptySet(),
+                    dummyUserState, 0, mockPkgSetting(pkg))
+        }
+
+        private fun mockPkgSetting(aPkg: AndroidPackage) = mockThrowOnUnmocked<PackageSetting> {
+            this.pkg = aPkg
+            whenever(pkgState) { PackageStateUnserialized() }
         }
     }
 
diff --git a/core/tests/coretests/src/android/content/pm/PackageParserTest.java b/services/tests/servicestests/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java
similarity index 91%
rename from core/tests/coretests/src/android/content/pm/PackageParserTest.java
rename to services/tests/servicestests/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java
index 46e992e..66cd466 100644
--- a/core/tests/coretests/src/android/content/pm/PackageParserTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.content.pm;
+package com.android.server.pm.parsing;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
@@ -24,21 +24,26 @@
 
 import android.apex.ApexInfo;
 import android.content.Context;
-import android.content.pm.parsing.AndroidPackage;
-import android.content.pm.parsing.ComponentParseUtils.ParsedComponent;
-import android.content.pm.parsing.ComponentParseUtils.ParsedPermission;
-import android.content.pm.parsing.ParsedPackage;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageParser;
+import android.content.pm.PermissionInfo;
+import android.content.pm.parsing.component.ParsedComponent;
+import android.content.pm.parsing.component.ParsedPermission;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.FileUtils;
-import android.util.Log;
+import android.platform.test.annotations.Presubmit;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import com.android.frameworks.coretests.R;
+import com.android.frameworks.servicestests.R;
 import com.android.internal.util.ArrayUtils;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.parsing.pkg.ParsedPackage;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -47,9 +52,19 @@
 import java.io.InputStream;
 import java.util.function.Function;
 
+/**
+ * {@link ParsedPackage} was moved to the server, so this test moved along with it.
+ *
+ * This should be eventually refactored to a comprehensive parsing test, combined with its
+ * server variant in the parent package.
+ *
+ * TODO(b/135203078): Remove this test and replicate the cases in the actual com.android.server
+ *  variant.
+ */
+@Presubmit
 @SmallTest
 @RunWith(AndroidJUnit4.class)
-public class PackageParserTest {
+public class PackageParserLegacyCoreTest {
     private static final String RELEASED = null;
     private static final String OLDER_PRE_RELEASE = "A";
     private static final String PRE_RELEASE = "B";
@@ -87,6 +102,10 @@
         }
     }
 
+    private PackageParser2 makeParser() {
+        return new PackageParser2(null, false, null, null, null);
+    }
+
     @Test
     public void testComputeMinSdkVersion_preReleasePlatform() {
         // Do allow older release minSdkVersion on pre-release platform.
@@ -339,7 +358,7 @@
         try {
             outFile = copyRawResourceToFile(apkFileName, apkResourceId);
             return converter.apply(
-                    new PackageParser().parseParsedPackage(outFile, 0 /* flags */, false));
+                    makeParser().parsePackage(outFile, 0 /* flags */, false));
         } finally {
             if (outFile != null) {
                 outFile.delete();
@@ -350,9 +369,9 @@
     /**
      * Asserts basic properties about a component.
      */
-    private void assertComponent(String className, int numIntents, ParsedComponent<?> component) {
-        assertEquals(className, component.className);
-        assertEquals(numIntents, component.intents.size());
+    private void assertComponent(String className, int numIntents, ParsedComponent component) {
+        assertEquals(className, component.getName());
+        assertEquals(numIntents, component.getIntents().size());
     }
 
     /**
@@ -406,7 +425,7 @@
     @Test
     public void testPackageWithComponents_cached() throws Exception {
         checkPackageWithComponents(p ->
-                PackageParser.fromCacheEntryStatic(PackageParser.toCacheEntryStatic(p)));
+                PackageCacher.fromCacheEntryStatic(PackageCacher.toCacheEntryStatic(p)));
     }
 
     private void checkPackageWithComponents(
@@ -426,7 +445,7 @@
 
         assertOneComponentOfEachType("com.android.frameworks.coretests.Test%s", p);
 
-        assertMetadata(p.getAppMetaData(),
+        assertMetadata(p.getMetaData(),
                 "key1", "value1",
                 "key2", "this_is_app");
         assertMetadata(p.getActivities().get(0).getMetaData(),
@@ -448,7 +467,7 @@
         // Hidden "app details" activity is added to every package.
         boolean foundAppDetailsActivity = false;
         for (int i = 0; i < ArrayUtils.size(p.getActivities()); i++) {
-            if (p.getActivities().get(i).className.equals(
+            if (p.getActivities().get(i).getClassName().equals(
                     PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME)) {
                 foundAppDetailsActivity = true;
                 p.getActivities().remove(i);
@@ -466,7 +485,7 @@
     @Test
     public void testPackageWithIntentFilters_cached() throws Exception {
         checkPackageWithIntentFilters(p ->
-                PackageParser.fromCacheEntryStatic(PackageParser.toCacheEntryStatic(p)));
+                PackageCacher.fromCacheEntryStatic(PackageCacher.toCacheEntryStatic(p)));
     }
 
     private void checkPackageWithIntentFilters(
@@ -474,20 +493,19 @@
         ParsedPackage p = parsePackage(
                 "install_intent_filters.apk", R.raw.install_intent_filters,
                 converter);
-        String packageName = "com.android.frameworks.coretests.install_intent_filters";
+        String packageName = "com.android.frameworks.servicestests.install_intent_filters";
 
         assertEquals(packageName, p.getPackageName());
 
         findAndRemoveAppDetailsActivity(p);
 
-        Log.e("ParserTest", "" + p.getActivities());
         assertEquals("Expected exactly one activity", 1, p.getActivities().size());
         assertEquals("Expected exactly one intent filter",
-                1, p.getActivities().get(0).intents.size());
+                1, p.getActivities().get(0).getIntents().size());
         assertEquals("Expected exactly one mime group in intent filter",
-                1, p.getActivities().get(0).intents.get(0).countMimeGroups());
+                1, p.getActivities().get(0).getIntents().get(0).countMimeGroups());
         assertTrue("Did not find expected mime group 'mime_group_1'",
-                p.getActivities().get(0).intents.get(0).hasMimeGroup("mime_group_1"));
+                p.getActivities().get(0).getIntents().get(0).hasMimeGroup("mime_group_1"));
     }
 
     @Test
diff --git a/core/tests/coretests/src/android/content/pm/parsing/library/AndroidHidlUpdaterTest.java b/services/tests/servicestests/src/com/android/server/pm/parsing/library/AndroidHidlUpdaterTest.java
similarity index 67%
rename from core/tests/coretests/src/android/content/pm/parsing/library/AndroidHidlUpdaterTest.java
rename to services/tests/servicestests/src/com/android/server/pm/parsing/library/AndroidHidlUpdaterTest.java
index 21479c0..6b60042 100644
--- a/core/tests/coretests/src/android/content/pm/parsing/library/AndroidHidlUpdaterTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/library/AndroidHidlUpdaterTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2019 The Android Open Source Project
+ * 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.
@@ -14,25 +14,28 @@
  * limitations under the License.
  */
 
-package android.content.pm.parsing.library;
+package com.android.server.pm.parsing.library;
 
-import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_HIDL_BASE;
-import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_HIDL_MANAGER;
+import static com.android.server.pm.parsing.library.SharedLibraryNames.ANDROID_HIDL_BASE;
+import static com.android.server.pm.parsing.library.SharedLibraryNames.ANDROID_HIDL_MANAGER;
 
-import android.content.pm.parsing.AndroidPackage;
-import android.content.pm.parsing.PackageImpl;
-import android.content.pm.parsing.ParsedPackage;
 import android.os.Build;
+import android.platform.test.annotations.Presubmit;
 
 import androidx.test.filters.SmallTest;
 
+import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.parsing.pkg.PackageImpl;
+import com.android.server.pm.parsing.pkg.ParsedPackage;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
 
 /**
- * Test for {@link AndroidHidlUpdater}
+ * Test for {@link com.android.server.pm.parsing.library.AndroidHidlUpdater}
  */
+@Presubmit
 @SmallTest
 @RunWith(JUnit4.class)
 public class AndroidHidlUpdaterTest extends PackageSharedLibraryUpdaterTest {
@@ -41,13 +44,13 @@
 
     @Test
     public void targeted_at_P() {
-        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+        ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
                 .setTargetSdkVersion(Build.VERSION_CODES.P)
-                .hideAsParsed();
+                .hideAsParsed());
 
-        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+        AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
                 .setTargetSdkVersion(Build.VERSION_CODES.P)
-                .hideAsParsed()
+                .hideAsParsed())
                 .hideAsFinal();
 
         // no change, not system
@@ -56,17 +59,17 @@
 
     @Test
     public void targeted_at_P_system() {
-        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+        ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
                 .setTargetSdkVersion(Build.VERSION_CODES.P)
-                .hideAsParsed()
+                .hideAsParsed())
                 .setSystem(true);
 
         // Should add both HIDL libraries
-        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+        AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
                 .setTargetSdkVersion(Build.VERSION_CODES.P)
                 .addUsesLibrary(ANDROID_HIDL_MANAGER)
                 .addUsesLibrary(ANDROID_HIDL_BASE)
-                .hideAsParsed()
+                .hideAsParsed())
                 .setSystem(true)
                 .hideAsFinal();
 
@@ -75,15 +78,15 @@
 
     @Test
     public void targeted_at_P_not_empty_usesLibraries() {
-        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+        ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
                 .setTargetSdkVersion(Build.VERSION_CODES.P)
                 .addUsesLibrary(OTHER_LIBRARY)
-                .hideAsParsed();
+                .hideAsParsed());
 
-        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+        AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
                 .setTargetSdkVersion(Build.VERSION_CODES.P)
                 .addUsesLibrary(OTHER_LIBRARY)
-                .hideAsParsed()
+                .hideAsParsed())
                 .hideAsFinal();
 
         // no change, not system
@@ -92,20 +95,20 @@
 
     @Test
     public void targeted_at_P_not_empty_usesLibraries_system() {
-        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+        ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
                 .setTargetSdkVersion(Build.VERSION_CODES.P)
                 .addUsesLibrary(OTHER_LIBRARY)
-                .hideAsParsed()
+                .hideAsParsed())
                 .setSystem(true);
 
         // The hidl jars should be added at the start of the list because it
         // is not on the bootclasspath and the package targets pre-P.
-        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+        AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
                 .setTargetSdkVersion(Build.VERSION_CODES.P)
                 .addUsesLibrary(ANDROID_HIDL_MANAGER)
                 .addUsesLibrary(ANDROID_HIDL_BASE)
                 .addUsesLibrary(OTHER_LIBRARY)
-                .hideAsParsed()
+                .hideAsParsed())
                 .setSystem(true)
                 .hideAsFinal();
 
@@ -114,15 +117,15 @@
 
     @Test
     public void targeted_at_P_in_usesLibraries() {
-        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+        ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
                 .setTargetSdkVersion(Build.VERSION_CODES.P)
                 .addUsesLibrary(ANDROID_HIDL_MANAGER)
                 .addUsesLibrary(ANDROID_HIDL_BASE)
-                .hideAsParsed();
+                .hideAsParsed());
 
-        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+        AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
                 .setTargetSdkVersion(Build.VERSION_CODES.P)
-                .hideAsParsed()
+                .hideAsParsed())
                 .hideAsFinal();
 
         // Libraries are removed because they are not available for non-system apps
@@ -131,18 +134,18 @@
 
     @Test
     public void targeted_at_P_in_usesLibraries_system() {
-        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+        ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
                 .setTargetSdkVersion(Build.VERSION_CODES.P)
                 .addUsesLibrary(ANDROID_HIDL_MANAGER)
                 .addUsesLibrary(ANDROID_HIDL_BASE)
-                .hideAsParsed()
+                .hideAsParsed())
                 .setSystem(true);
 
-        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+        AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
                 .setTargetSdkVersion(Build.VERSION_CODES.P)
                 .addUsesLibrary(ANDROID_HIDL_MANAGER)
                 .addUsesLibrary(ANDROID_HIDL_BASE)
-                .hideAsParsed()
+                .hideAsParsed())
                 .setSystem(true)
                 .hideAsFinal();
 
@@ -153,15 +156,15 @@
 
     @Test
     public void in_usesLibraries() {
-        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+        ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
                 .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
                 .addUsesLibrary(ANDROID_HIDL_BASE)
-                .hideAsParsed();
+                .hideAsParsed());
 
         // Dependency is removed, it is not available.
-        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+        AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
                 .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
-                .hideAsParsed()
+                .hideAsParsed())
                 .hideAsFinal();
 
         // Libraries are removed because they are not available for apps targeting Q+
@@ -170,15 +173,15 @@
 
     @Test
     public void in_usesOptionalLibraries() {
-        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+        ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
                 .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
                 .addUsesOptionalLibrary(ANDROID_HIDL_BASE)
-                .hideAsParsed();
+                .hideAsParsed());
 
         // Dependency is removed, it is not available.
-        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+        AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
                 .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
-                .hideAsParsed()
+                .hideAsParsed())
                 .hideAsFinal();
 
         // Libraries are removed because they are not available for apps targeting Q+
diff --git a/core/tests/coretests/src/android/content/pm/parsing/library/AndroidTestBaseUpdaterTest.java b/services/tests/servicestests/src/com/android/server/pm/parsing/library/AndroidTestBaseUpdaterTest.java
similarity index 68%
rename from core/tests/coretests/src/android/content/pm/parsing/library/AndroidTestBaseUpdaterTest.java
rename to services/tests/servicestests/src/com/android/server/pm/parsing/library/AndroidTestBaseUpdaterTest.java
index 65ae219..f536052 100644
--- a/core/tests/coretests/src/android/content/pm/parsing/library/AndroidTestBaseUpdaterTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/library/AndroidTestBaseUpdaterTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2019 The Android Open Source Project
+ * 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.
@@ -14,42 +14,44 @@
  * limitations under the License.
  */
 
-package android.content.pm.parsing.library;
+package com.android.server.pm.parsing.library;
 
-import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_BASE;
+import static com.android.server.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_BASE;
 
-import android.content.pm.OptionalClassRunner;
-import android.content.pm.parsing.AndroidPackage;
-import android.content.pm.parsing.PackageImpl;
-import android.content.pm.parsing.ParsedPackage;
 import android.os.Build;
+import android.platform.test.annotations.Presubmit;
 
 import androidx.test.filters.SmallTest;
 
+import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.parsing.pkg.PackageImpl;
+import com.android.server.pm.parsing.pkg.ParsedPackage;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 /**
  * Test for {@link AndroidTestBaseUpdater}
  */
+@Presubmit
 @SmallTest
 @RunWith(OptionalClassRunner.class)
-@OptionalClassRunner.OptionalClass("android.content.pm.parsing.library.AndroidTestBaseUpdater")
+@OptionalClassRunner.OptionalClass("com.android.server.pm.parsing.library.AndroidTestBaseUpdater")
 public class AndroidTestBaseUpdaterTest extends PackageSharedLibraryUpdaterTest {
 
     private static final String OTHER_LIBRARY = "other.library";
 
     @Test
     public void targeted_at_Q() {
-        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+        ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
                 .setTargetSdkVersion(Build.VERSION_CODES.Q)
-                .hideAsParsed();
+                .hideAsParsed());
 
         // Should add org.apache.http.legacy.
-        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+        AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
                 .setTargetSdkVersion(Build.VERSION_CODES.Q)
                 .addUsesLibrary(ANDROID_TEST_BASE)
-                .hideAsParsed()
+                .hideAsParsed())
                 .hideAsFinal();
 
         checkBackwardsCompatibility(before, after);
@@ -57,18 +59,18 @@
 
     @Test
     public void targeted_at_Q_not_empty_usesLibraries() {
-        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+        ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
                 .setTargetSdkVersion(Build.VERSION_CODES.Q)
                 .addUsesLibrary(OTHER_LIBRARY)
-                .hideAsParsed();
+                .hideAsParsed());
 
         // The org.apache.http.legacy jar should be added at the start of the list because it
         // is not on the bootclasspath and the package targets pre-Q.
-        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+        AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
                 .setTargetSdkVersion(Build.VERSION_CODES.Q)
                 .addUsesLibrary(ANDROID_TEST_BASE)
                 .addUsesLibrary(OTHER_LIBRARY)
-                .hideAsParsed()
+                .hideAsParsed())
                 .hideAsFinal();
 
         checkBackwardsCompatibility(before, after);
@@ -76,15 +78,15 @@
 
     @Test
     public void targeted_at_Q_in_usesLibraries() {
-        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+        ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
                 .setTargetSdkVersion(Build.VERSION_CODES.Q)
                 .addUsesLibrary(ANDROID_TEST_BASE)
-                .hideAsParsed();
+                .hideAsParsed());
 
-        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+        AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
                 .setTargetSdkVersion(Build.VERSION_CODES.Q)
                 .addUsesLibrary(ANDROID_TEST_BASE)
-                .hideAsParsed()
+                .hideAsParsed())
                 .hideAsFinal();
 
         // No change is required because although org.apache.http.legacy has been removed from
@@ -94,15 +96,15 @@
 
     @Test
     public void targeted_at_Q_in_usesOptionalLibraries() {
-        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+        ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
                 .setTargetSdkVersion(Build.VERSION_CODES.Q)
                 .addUsesOptionalLibrary(ANDROID_TEST_BASE)
-                .hideAsParsed();
+                .hideAsParsed());
 
-        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+        AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
                 .setTargetSdkVersion(Build.VERSION_CODES.Q)
                 .addUsesOptionalLibrary(ANDROID_TEST_BASE)
-                .hideAsParsed()
+                .hideAsParsed())
                 .hideAsFinal();
 
         // No change is required because although org.apache.http.legacy has been removed from
@@ -112,15 +114,15 @@
 
     @Test
     public void in_usesLibraries() {
-        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+        ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
                 .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
                 .addUsesLibrary(ANDROID_TEST_BASE)
-                .hideAsParsed();
+                .hideAsParsed());
 
-        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+        AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
                 .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
                 .addUsesLibrary(ANDROID_TEST_BASE)
-                .hideAsParsed()
+                .hideAsParsed())
                 .hideAsFinal();
 
         // No change is required because the package explicitly requests org.apache.http.legacy
@@ -130,15 +132,15 @@
 
     @Test
     public void in_usesOptionalLibraries() {
-        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+        ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
                 .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
                 .addUsesOptionalLibrary(ANDROID_TEST_BASE)
-                .hideAsParsed();
+                .hideAsParsed());
 
-        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+        AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
                 .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
                 .addUsesOptionalLibrary(ANDROID_TEST_BASE)
-                .hideAsParsed()
+                .hideAsParsed())
                 .hideAsFinal();
 
         // No change is required because the package explicitly requests org.apache.http.legacy
diff --git a/core/tests/coretests/src/android/content/pm/parsing/library/AndroidTestRunnerSplitUpdaterTest.java b/services/tests/servicestests/src/com/android/server/pm/parsing/library/AndroidTestRunnerSplitUpdaterTest.java
similarity index 68%
rename from core/tests/coretests/src/android/content/pm/parsing/library/AndroidTestRunnerSplitUpdaterTest.java
rename to services/tests/servicestests/src/com/android/server/pm/parsing/library/AndroidTestRunnerSplitUpdaterTest.java
index 38755b9..77197e3 100644
--- a/core/tests/coretests/src/android/content/pm/parsing/library/AndroidTestRunnerSplitUpdaterTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/library/AndroidTestRunnerSplitUpdaterTest.java
@@ -14,19 +14,21 @@
  * limitations under the License.
  */
 
-package android.content.pm.parsing.library;
+package com.android.server.pm.parsing.library;
 
-import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_MOCK;
-import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_RUNNER;
+import static com.android.server.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_MOCK;
+import static com.android.server.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_RUNNER;
 
-import android.content.pm.parsing.AndroidPackage;
-import android.content.pm.parsing.PackageImpl;
-import android.content.pm.parsing.ParsedPackage;
-import android.content.pm.parsing.library.PackageBackwardCompatibility.AndroidTestRunnerSplitUpdater;
 import android.os.Build;
+import android.platform.test.annotations.Presubmit;
 
 import androidx.test.filters.SmallTest;
 
+import com.android.server.pm.parsing.library.PackageBackwardCompatibility.AndroidTestRunnerSplitUpdater;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.parsing.pkg.PackageImpl;
+import com.android.server.pm.parsing.pkg.ParsedPackage;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
@@ -34,22 +36,23 @@
 /**
  * Test for {@link AndroidTestRunnerSplitUpdater}
  */
+@Presubmit
 @SmallTest
 @RunWith(JUnit4.class)
 public class AndroidTestRunnerSplitUpdaterTest extends PackageSharedLibraryUpdaterTest {
 
     @Test
     public void android_test_runner_in_usesOptionalLibraries() {
-        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+        ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
                 .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
                 .addUsesOptionalLibrary(ANDROID_TEST_RUNNER)
-                .hideAsParsed();
+                .hideAsParsed());
 
-        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+        AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
                 .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
                 .addUsesOptionalLibrary(ANDROID_TEST_MOCK)
                 .addUsesOptionalLibrary(ANDROID_TEST_RUNNER)
-                .hideAsParsed()
+                .hideAsParsed())
                 .hideAsFinal();
 
         checkBackwardsCompatibility(before, after);
@@ -57,17 +60,17 @@
 
     @Test
     public void android_test_runner_in_usesLibraries_android_test_mock_in_usesOptionalLibraries() {
-        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+        ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
                 .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
                 .addUsesLibrary(ANDROID_TEST_RUNNER)
                 .addUsesOptionalLibrary(ANDROID_TEST_MOCK)
-                .hideAsParsed();
+                .hideAsParsed());
 
-        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+        AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
                 .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
                 .addUsesLibrary(ANDROID_TEST_RUNNER)
                 .addUsesOptionalLibrary(ANDROID_TEST_MOCK)
-                .hideAsParsed()
+                .hideAsParsed())
                 .hideAsFinal();
 
         checkBackwardsCompatibility(before, after);
diff --git a/core/tests/coretests/src/android/content/pm/OptionalClassRunner.java b/services/tests/servicestests/src/com/android/server/pm/parsing/library/OptionalClassRunner.java
similarity index 97%
rename from core/tests/coretests/src/android/content/pm/OptionalClassRunner.java
rename to services/tests/servicestests/src/com/android/server/pm/parsing/library/OptionalClassRunner.java
index 05db8ee..0ebfe1a 100644
--- a/core/tests/coretests/src/android/content/pm/OptionalClassRunner.java
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/library/OptionalClassRunner.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2019 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.content.pm;
+package com.android.server.pm.parsing.library;
 
 import org.junit.Assume;
 import org.junit.runner.Description;
diff --git a/core/tests/coretests/src/android/content/pm/parsing/library/OrgApacheHttpLegacyUpdaterTest.java b/services/tests/servicestests/src/com/android/server/pm/parsing/library/OrgApacheHttpLegacyUpdaterTest.java
similarity index 68%
rename from core/tests/coretests/src/android/content/pm/parsing/library/OrgApacheHttpLegacyUpdaterTest.java
rename to services/tests/servicestests/src/com/android/server/pm/parsing/library/OrgApacheHttpLegacyUpdaterTest.java
index 4c7899b..95b8d3f 100644
--- a/core/tests/coretests/src/android/content/pm/parsing/library/OrgApacheHttpLegacyUpdaterTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/library/OrgApacheHttpLegacyUpdaterTest.java
@@ -14,42 +14,44 @@
  * limitations under the License.
  */
 
-package android.content.pm.parsing.library;
+package com.android.server.pm.parsing.library;
 
-import static android.content.pm.parsing.library.SharedLibraryNames.ORG_APACHE_HTTP_LEGACY;
+import static com.android.server.pm.parsing.library.SharedLibraryNames.ORG_APACHE_HTTP_LEGACY;
 
-import android.content.pm.OptionalClassRunner;
-import android.content.pm.parsing.AndroidPackage;
-import android.content.pm.parsing.PackageImpl;
-import android.content.pm.parsing.ParsedPackage;
 import android.os.Build;
+import android.platform.test.annotations.Presubmit;
 
 import androidx.test.filters.SmallTest;
 
+import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.parsing.pkg.PackageImpl;
+import com.android.server.pm.parsing.pkg.ParsedPackage;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 /**
- * Test for {@link OrgApacheHttpLegacyUpdater}
+ * Test for {@link com.android.server.pm.parsing.library.OrgApacheHttpLegacyUpdater}
  */
+@Presubmit
 @SmallTest
 @RunWith(OptionalClassRunner.class)
-@OptionalClassRunner.OptionalClass("android.content.pm.parsing.library.OrgApacheHttpLegacyUpdater")
+@OptionalClassRunner.OptionalClass("com.android.server.pm.parsing.library.OrgApacheHttpLegacyUpdater")
 public class OrgApacheHttpLegacyUpdaterTest extends PackageSharedLibraryUpdaterTest {
 
     private static final String OTHER_LIBRARY = "other.library";
 
     @Test
     public void targeted_at_O() {
-        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+        ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
                 .setTargetSdkVersion(Build.VERSION_CODES.O)
-                .hideAsParsed();
+                .hideAsParsed());
 
         // Should add org.apache.http.legacy.
-        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+        AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
                 .setTargetSdkVersion(Build.VERSION_CODES.O)
                 .addUsesLibrary(ORG_APACHE_HTTP_LEGACY)
-                .hideAsParsed()
+                .hideAsParsed())
                 .hideAsFinal();
 
         checkBackwardsCompatibility(before, after);
@@ -57,18 +59,18 @@
 
     @Test
     public void targeted_at_O_not_empty_usesLibraries() {
-        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+        ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
                 .setTargetSdkVersion(Build.VERSION_CODES.O)
                 .addUsesLibrary(OTHER_LIBRARY)
-                .hideAsParsed();
+                .hideAsParsed());
 
         // The org.apache.http.legacy jar should be added at the start of the list because it
         // is not on the bootclasspath and the package targets pre-P.
-        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+        AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
                 .setTargetSdkVersion(Build.VERSION_CODES.O)
                 .addUsesLibrary(ORG_APACHE_HTTP_LEGACY)
                 .addUsesLibrary(OTHER_LIBRARY)
-                .hideAsParsed()
+                .hideAsParsed())
                 .hideAsFinal();
 
         checkBackwardsCompatibility(before, after);
@@ -76,15 +78,15 @@
 
     @Test
     public void targeted_at_O_in_usesLibraries() {
-        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+        ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
                 .setTargetSdkVersion(Build.VERSION_CODES.O)
                 .addUsesLibrary(ORG_APACHE_HTTP_LEGACY)
-                .hideAsParsed();
+                .hideAsParsed());
 
-        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+        AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
                 .setTargetSdkVersion(Build.VERSION_CODES.O)
                 .addUsesLibrary(ORG_APACHE_HTTP_LEGACY)
-                .hideAsParsed()
+                .hideAsParsed())
                 .hideAsFinal();
 
         // No change is required because although org.apache.http.legacy has been removed from
@@ -94,15 +96,15 @@
 
     @Test
     public void targeted_at_O_in_usesOptionalLibraries() {
-        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+        ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
                 .setTargetSdkVersion(Build.VERSION_CODES.O)
                 .addUsesOptionalLibrary(ORG_APACHE_HTTP_LEGACY)
-                .hideAsParsed();
+                .hideAsParsed());
 
-        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+        AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
                 .setTargetSdkVersion(Build.VERSION_CODES.O)
                 .addUsesOptionalLibrary(ORG_APACHE_HTTP_LEGACY)
-                .hideAsParsed()
+                .hideAsParsed())
                 .hideAsFinal();
 
         // No change is required because although org.apache.http.legacy has been removed from
@@ -112,15 +114,15 @@
 
     @Test
     public void in_usesLibraries() {
-        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+        ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
                 .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
                 .addUsesLibrary(ORG_APACHE_HTTP_LEGACY)
-                .hideAsParsed();
+                .hideAsParsed());
 
-        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+        AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
                 .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
                 .addUsesLibrary(ORG_APACHE_HTTP_LEGACY)
-                .hideAsParsed()
+                .hideAsParsed())
                 .hideAsFinal();
 
         // No change is required because the package explicitly requests org.apache.http.legacy
@@ -130,15 +132,15 @@
 
     @Test
     public void in_usesOptionalLibraries() {
-        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+        ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
                 .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
                 .addUsesOptionalLibrary(ORG_APACHE_HTTP_LEGACY)
-                .hideAsParsed();
+                .hideAsParsed());
 
-        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+        AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
                 .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
                 .addUsesOptionalLibrary(ORG_APACHE_HTTP_LEGACY)
-                .hideAsParsed()
+                .hideAsParsed())
                 .hideAsFinal();
 
         // No change is required because the package explicitly requests org.apache.http.legacy
diff --git a/core/tests/coretests/src/android/content/pm/parsing/library/PackageBackwardCompatibilityTest.java b/services/tests/servicestests/src/com/android/server/pm/parsing/library/PackageBackwardCompatibilityTest.java
similarity index 71%
rename from core/tests/coretests/src/android/content/pm/parsing/library/PackageBackwardCompatibilityTest.java
rename to services/tests/servicestests/src/com/android/server/pm/parsing/library/PackageBackwardCompatibilityTest.java
index 00d468d..ca38860 100644
--- a/core/tests/coretests/src/android/content/pm/parsing/library/PackageBackwardCompatibilityTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/library/PackageBackwardCompatibilityTest.java
@@ -14,40 +14,43 @@
  * limitations under the License.
  */
 
-package android.content.pm.parsing.library;
+package com.android.server.pm.parsing.library;
 
-import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_BASE;
-import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_MOCK;
-import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_RUNNER;
-import static android.content.pm.parsing.library.SharedLibraryNames.ORG_APACHE_HTTP_LEGACY;
+import static com.android.server.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_BASE;
+import static com.android.server.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_MOCK;
+import static com.android.server.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_RUNNER;
+import static com.android.server.pm.parsing.library.SharedLibraryNames.ORG_APACHE_HTTP_LEGACY;
 
-import android.content.pm.parsing.AndroidPackage;
-import android.content.pm.parsing.PackageImpl;
-import android.content.pm.parsing.ParsedPackage;
 import android.content.pm.parsing.ParsingPackage;
-import android.content.pm.parsing.library.PackageBackwardCompatibility.RemoveUnnecessaryAndroidTestBaseLibrary;
 import android.os.Build;
+import android.platform.test.annotations.Presubmit;
 
 import androidx.test.filters.SmallTest;
 
+import com.android.server.pm.parsing.library.PackageBackwardCompatibility.RemoveUnnecessaryAndroidTestBaseLibrary;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.parsing.pkg.PackageImpl;
+import com.android.server.pm.parsing.pkg.ParsedPackage;
+
 import org.junit.Assume;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
 
+@Presubmit
 @SmallTest
 @RunWith(JUnit4.class)
 public class PackageBackwardCompatibilityTest extends PackageSharedLibraryUpdaterTest {
 
     @Test
     public void null_usesLibraries_and_usesOptionalLibraries() {
-        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+        ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
                 .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
-                .hideAsParsed();
+                .hideAsParsed());
 
-        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+        AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
                 .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
-                .hideAsParsed()
+                .hideAsParsed())
                 .hideAsFinal();
 
         checkBackwardsCompatibility(before, after);
@@ -74,12 +77,12 @@
      */
     @Test
     public void targeted_at_O() {
-        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+        ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
                 .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
                 .setTargetSdkVersion(Build.VERSION_CODES.O)
-                .hideAsParsed();
+                .hideAsParsed());
 
-        ParsingPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+        ParsingPackage after = PackageImpl.forTesting(PACKAGE_NAME)
                 .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
                 .setTargetSdkVersion(Build.VERSION_CODES.O);
 
@@ -88,7 +91,7 @@
         }
         after.addUsesLibrary(ORG_APACHE_HTTP_LEGACY);
 
-        checkBackwardsCompatibility(before, after.hideAsParsed().hideAsFinal());
+        checkBackwardsCompatibility(before, ((ParsedPackage) after.hideAsParsed()).hideAsFinal());
     }
 
     /**
@@ -105,16 +108,16 @@
                         + ANDROID_TEST_BASE + " is on the bootclasspath",
                 PackageBackwardCompatibility.bootClassPathContainsATB());
 
-        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+        ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
                 .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
                 .addUsesLibrary(ANDROID_TEST_BASE)
-                .hideAsParsed();
+                .hideAsParsed());
 
         // android.test.base should be removed from the libraries because it is provided
         // on the bootclasspath and providing both increases start up cost unnecessarily.
-        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+        AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
                 .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
-                .hideAsParsed()
+                .hideAsParsed())
                 .hideAsFinal();
 
         checkBackwardsCompatibility(before, after);
@@ -129,12 +132,12 @@
      */
     @Test
     public void android_test_runner_in_usesLibraries() {
-        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+        ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
                 .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
                 .addUsesLibrary(ANDROID_TEST_RUNNER)
-                .hideAsParsed();
+                .hideAsParsed());
 
-        ParsingPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+        ParsingPackage after = PackageImpl.forTesting(PACKAGE_NAME)
                 .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT);
         if (!PackageBackwardCompatibility.bootClassPathContainsATB()) {
             after.addUsesLibrary(ANDROID_TEST_BASE);
@@ -142,7 +145,7 @@
         after.addUsesLibrary(ANDROID_TEST_MOCK);
         after.addUsesLibrary(ANDROID_TEST_RUNNER);
 
-        checkBackwardsCompatibility(before, after.hideAsParsed().hideAsFinal());
+        checkBackwardsCompatibility(before, ((ParsedPackage) after.hideAsParsed()).hideAsFinal());
     }
 
     private void checkBackwardsCompatibility(ParsedPackage before, AndroidPackage after) {
diff --git a/core/tests/coretests/src/android/content/pm/parsing/library/PackageSharedLibraryUpdaterTest.java b/services/tests/servicestests/src/com/android/server/pm/parsing/library/PackageSharedLibraryUpdaterTest.java
similarity index 88%
rename from core/tests/coretests/src/android/content/pm/parsing/library/PackageSharedLibraryUpdaterTest.java
rename to services/tests/servicestests/src/com/android/server/pm/parsing/library/PackageSharedLibraryUpdaterTest.java
index e7a80e1a..a71572f 100644
--- a/core/tests/coretests/src/android/content/pm/parsing/library/PackageSharedLibraryUpdaterTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/library/PackageSharedLibraryUpdaterTest.java
@@ -14,12 +14,12 @@
  * limitations under the License.
  */
 
-package android.content.pm.parsing.library;
+package com.android.server.pm.parsing.library;
 
 import static org.junit.Assert.assertEquals;
 
-import android.content.pm.parsing.AndroidPackage;
-import android.content.pm.parsing.ParsedPackage;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.parsing.pkg.ParsedPackage;
 
 import java.util.function.Supplier;
 
@@ -32,7 +32,7 @@
 
     static void checkBackwardsCompatibility(ParsedPackage before, AndroidPackage after,
             Supplier<PackageSharedLibraryUpdater> updaterSupplier) {
-        updaterSupplier.get().updatePackage(before);
+        updaterSupplier.get().updatePackage(before, false);
         check(before.hideAsFinal(), after);
     }
 
diff --git a/core/tests/coretests/src/android/content/pm/parsing/library/RemoveUnnecessaryAndroidTestBaseLibraryTest.java b/services/tests/servicestests/src/com/android/server/pm/parsing/library/RemoveUnnecessaryAndroidTestBaseLibraryTest.java
similarity index 69%
rename from core/tests/coretests/src/android/content/pm/parsing/library/RemoveUnnecessaryAndroidTestBaseLibraryTest.java
rename to services/tests/servicestests/src/com/android/server/pm/parsing/library/RemoveUnnecessaryAndroidTestBaseLibraryTest.java
index fd3ba2b..1122490 100644
--- a/core/tests/coretests/src/android/content/pm/parsing/library/RemoveUnnecessaryAndroidTestBaseLibraryTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/library/RemoveUnnecessaryAndroidTestBaseLibraryTest.java
@@ -14,18 +14,20 @@
  * limitations under the License.
  */
 
-package android.content.pm.parsing.library;
+package com.android.server.pm.parsing.library;
 
-import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_BASE;
+import static com.android.server.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_BASE;
 
-import android.content.pm.parsing.AndroidPackage;
-import android.content.pm.parsing.PackageImpl;
-import android.content.pm.parsing.ParsedPackage;
-import android.content.pm.parsing.library.PackageBackwardCompatibility.RemoveUnnecessaryAndroidTestBaseLibrary;
 import android.os.Build;
+import android.platform.test.annotations.Presubmit;
 
 import androidx.test.filters.SmallTest;
 
+import com.android.server.pm.parsing.library.PackageBackwardCompatibility.RemoveUnnecessaryAndroidTestBaseLibrary;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.parsing.pkg.PackageImpl;
+import com.android.server.pm.parsing.pkg.ParsedPackage;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
@@ -33,6 +35,7 @@
 /**
  * Test for {@link RemoveUnnecessaryAndroidTestBaseLibrary}
  */
+@Presubmit
 @SmallTest
 @RunWith(JUnit4.class)
 public class RemoveUnnecessaryAndroidTestBaseLibraryTest
@@ -42,13 +45,13 @@
 
     @Test
     public void targeted_at_O() {
-        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+        ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
                 .setTargetSdkVersion(Build.VERSION_CODES.O)
-                .hideAsParsed();
+                .hideAsParsed());
 
-        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+        AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
                 .setTargetSdkVersion(Build.VERSION_CODES.O)
-                .hideAsParsed()
+                .hideAsParsed())
                 .hideAsFinal();
 
         // No change required.
@@ -57,15 +60,15 @@
 
     @Test
     public void targeted_at_O_not_empty_usesLibraries() {
-        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+        ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
                 .setTargetSdkVersion(Build.VERSION_CODES.O)
                 .addUsesLibrary(OTHER_LIBRARY)
-                .hideAsParsed();
+                .hideAsParsed());
 
-        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+        AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
                 .setTargetSdkVersion(Build.VERSION_CODES.O)
                 .addUsesLibrary(OTHER_LIBRARY)
-                .hideAsParsed()
+                .hideAsParsed())
                 .hideAsFinal();
 
         // No change required.
@@ -74,16 +77,16 @@
 
     @Test
     public void targeted_at_O_in_usesLibraries() {
-        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+        ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
                 .setTargetSdkVersion(Build.VERSION_CODES.O)
                 .addUsesLibrary(ANDROID_TEST_BASE)
-                .hideAsParsed();
+                .hideAsParsed());
 
         // android.test.base should be removed from the libraries because it is provided
         // on the bootclasspath and providing both increases start up cost unnecessarily.
-        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+        AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
                 .setTargetSdkVersion(Build.VERSION_CODES.O)
-                .hideAsParsed()
+                .hideAsParsed())
                 .hideAsFinal();
 
         checkBackwardsCompatibility(before, after);
@@ -91,16 +94,16 @@
 
     @Test
     public void targeted_at_O_in_usesOptionalLibraries() {
-        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+        ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
                 .setTargetSdkVersion(Build.VERSION_CODES.O)
                 .addUsesOptionalLibrary(ANDROID_TEST_BASE)
-                .hideAsParsed();
+                .hideAsParsed());
 
         // android.test.base should be removed from the libraries because it is provided
         // on the bootclasspath and providing both increases start up cost unnecessarily.
-        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+        AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
                 .setTargetSdkVersion(Build.VERSION_CODES.O)
-                .hideAsParsed()
+                .hideAsParsed())
                 .hideAsFinal();
 
         checkBackwardsCompatibility(before, after);
@@ -108,14 +111,14 @@
 
     @Test
     public void in_usesLibraries() {
-        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+        ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
                 .addUsesLibrary(ANDROID_TEST_BASE)
-                .hideAsParsed();
+                .hideAsParsed());
 
         // android.test.base should be removed from the libraries because it is provided
         // on the bootclasspath and providing both increases start up cost unnecessarily.
-        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
-                .hideAsParsed()
+        AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
+                .hideAsParsed())
                 .hideAsFinal();
 
         checkBackwardsCompatibility(before, after);
@@ -123,16 +126,16 @@
 
     @Test
     public void in_usesOptionalLibraries() {
-        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+        ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
                 .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
                 .addUsesOptionalLibrary(ANDROID_TEST_BASE)
-                .hideAsParsed();
+                .hideAsParsed());
 
         // android.test.base should be removed from the libraries because it is provided
         // on the bootclasspath and providing both increases start up cost unnecessarily.
-        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+        AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
                 .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
-                .hideAsParsed()
+                .hideAsParsed())
                 .hideAsFinal();
 
         checkBackwardsCompatibility(before, after);
@@ -140,17 +143,17 @@
 
     @Test
     public void in_bothLibraries() {
-        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+        ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
                 .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
                 .addUsesLibrary(ANDROID_TEST_BASE)
                 .addUsesOptionalLibrary(ANDROID_TEST_BASE)
-                .hideAsParsed();
+                .hideAsParsed());
 
         // android.test.base should be removed from the libraries because it is provided
         // on the bootclasspath and providing both increases start up cost unnecessarily.
-        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+        AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
                 .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
-                .hideAsParsed()
+                .hideAsParsed())
                 .hideAsFinal();
 
         checkBackwardsCompatibility(before, after);
diff --git a/core/tests/coretests/src/android/content/pm/parsing/library/RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest.java b/services/tests/servicestests/src/com/android/server/pm/parsing/library/RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest.java
similarity index 68%
rename from core/tests/coretests/src/android/content/pm/parsing/library/RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest.java
rename to services/tests/servicestests/src/com/android/server/pm/parsing/library/RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest.java
index d3494d9..3cc8475 100644
--- a/core/tests/coretests/src/android/content/pm/parsing/library/RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/library/RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest.java
@@ -14,18 +14,20 @@
  * limitations under the License.
  */
 
-package android.content.pm.parsing.library;
+package com.android.server.pm.parsing.library;
 
-import static android.content.pm.parsing.library.SharedLibraryNames.ORG_APACHE_HTTP_LEGACY;
+import static com.android.server.pm.parsing.library.SharedLibraryNames.ORG_APACHE_HTTP_LEGACY;
 
-import android.content.pm.parsing.AndroidPackage;
-import android.content.pm.parsing.PackageImpl;
-import android.content.pm.parsing.ParsedPackage;
-import android.content.pm.parsing.library.PackageBackwardCompatibility.RemoveUnnecessaryOrgApacheHttpLegacyLibrary;
 import android.os.Build;
+import android.platform.test.annotations.Presubmit;
 
 import androidx.test.filters.SmallTest;
 
+import com.android.server.pm.parsing.library.PackageBackwardCompatibility.RemoveUnnecessaryOrgApacheHttpLegacyLibrary;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.parsing.pkg.PackageImpl;
+import com.android.server.pm.parsing.pkg.ParsedPackage;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
@@ -33,6 +35,7 @@
 /**
  * Test for {@link RemoveUnnecessaryOrgApacheHttpLegacyLibrary}
  */
+@Presubmit
 @SmallTest
 @RunWith(JUnit4.class)
 public class RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest
@@ -42,13 +45,13 @@
 
     @Test
     public void targeted_at_O() {
-        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+        ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
                 .setTargetSdkVersion(Build.VERSION_CODES.O)
-                .hideAsParsed();
+                .hideAsParsed());
 
-        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+        AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
                 .setTargetSdkVersion(Build.VERSION_CODES.O)
-                .hideAsParsed()
+                .hideAsParsed())
                 .hideAsFinal();
 
         // No change required.
@@ -57,15 +60,15 @@
 
     @Test
     public void targeted_at_O_not_empty_usesLibraries() {
-        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+        ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
                 .setTargetSdkVersion(Build.VERSION_CODES.O)
                 .addUsesLibrary(OTHER_LIBRARY)
-                .hideAsParsed();
+                .hideAsParsed());
 
-        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+        AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
                 .setTargetSdkVersion(Build.VERSION_CODES.O)
                 .addUsesLibrary(OTHER_LIBRARY)
-                .hideAsParsed()
+                .hideAsParsed())
                 .hideAsFinal();
 
         // No change required.
@@ -74,16 +77,16 @@
 
     @Test
     public void targeted_at_O_in_usesLibraries() {
-        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+        ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
                 .setTargetSdkVersion(Build.VERSION_CODES.O)
                 .addUsesLibrary(ORG_APACHE_HTTP_LEGACY)
-                .hideAsParsed();
+                .hideAsParsed());
 
         // org.apache.http.legacy should be removed from the libraries because it is provided
         // on the bootclasspath and providing both increases start up cost unnecessarily.
-        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+        AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
                 .setTargetSdkVersion(Build.VERSION_CODES.O)
-                .hideAsParsed()
+                .hideAsParsed())
                 .hideAsFinal();
 
         checkBackwardsCompatibility(before, after);
@@ -91,16 +94,16 @@
 
     @Test
     public void targeted_at_O_in_usesOptionalLibraries() {
-        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+        ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
                 .setTargetSdkVersion(Build.VERSION_CODES.O)
                 .addUsesOptionalLibrary(ORG_APACHE_HTTP_LEGACY)
-                .hideAsParsed();
+                .hideAsParsed());
 
         // org.apache.http.legacy should be removed from the libraries because it is provided
         // on the bootclasspath and providing both increases start up cost unnecessarily.
-        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+        AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
                 .setTargetSdkVersion(Build.VERSION_CODES.O)
-                .hideAsParsed()
+                .hideAsParsed())
                 .hideAsFinal();
 
         checkBackwardsCompatibility(before, after);
@@ -108,15 +111,16 @@
 
     @Test
     public void in_usesLibraries() {
-        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+        ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
                 .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
                 .addUsesLibrary(ORG_APACHE_HTTP_LEGACY)
-                .hideAsParsed();
+                .hideAsParsed());
 
         // org.apache.http.legacy should be removed from the libraries because it is provided
         // on the bootclasspath and providing both increases start up cost unnecessarily.
-        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
-                .hideAsParsed()
+        AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+                .hideAsParsed())
                 .hideAsFinal();
 
         checkBackwardsCompatibility(before, after);
@@ -124,15 +128,16 @@
 
     @Test
     public void in_usesOptionalLibraries() {
-        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+        ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
                 .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
                 .addUsesOptionalLibrary(ORG_APACHE_HTTP_LEGACY)
-                .hideAsParsed();
+                .hideAsParsed());
 
         // org.apache.http.legacy should be removed from the libraries because it is provided
         // on the bootclasspath and providing both increases start up cost unnecessarily.
-        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
-                .hideAsParsed()
+        AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+                .hideAsParsed())
                 .hideAsFinal();
 
         checkBackwardsCompatibility(before, after);
@@ -140,17 +145,17 @@
 
     @Test
     public void in_bothLibraries() {
-        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+        ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
                 .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
                 .addUsesLibrary(ORG_APACHE_HTTP_LEGACY)
                 .addUsesOptionalLibrary(ORG_APACHE_HTTP_LEGACY)
-                .hideAsParsed();
+                .hideAsParsed());
 
         // org.apache.http.legacy should be removed from the libraries because it is provided
         // on the bootclasspath and providing both increases start up cost unnecessarily.
-        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+        AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
                 .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
-                .hideAsParsed()
+                .hideAsParsed())
                 .hideAsFinal();
 
         checkBackwardsCompatibility(before, after);
diff --git a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
index 9e57763..0fdffd5 100644
--- a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
@@ -66,6 +66,7 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.os.RemoteException;
+import android.os.UserHandle;
 import android.platform.test.annotations.Presubmit;
 import android.util.ArraySet;
 import android.view.Display;
@@ -83,6 +84,7 @@
 import java.io.File;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
 import java.util.Set;
 import java.util.concurrent.TimeUnit;
@@ -101,6 +103,8 @@
     private static final int UID_EXEMPTED_1 = 10001;
     private static final int USER_ID = 0;
     private static final int USER_ID2 = 10;
+    private static final UserHandle USER_HANDLE_USER2 = new UserHandle(USER_ID2);
+    private static final int USER_ID3 = 11;
 
     private static final String PACKAGE_UNKNOWN = "com.example.unknown";
 
@@ -150,6 +154,8 @@
         boolean mDisplayOn;
         DisplayManager.DisplayListener mDisplayListener;
         String mBoundWidgetPackage = PACKAGE_EXEMPTED_1;
+        int[] mRunningUsers = new int[] {USER_ID};
+        List<UserHandle> mCrossProfileTargets = Collections.emptyList();
 
         MyInjector(Context context, Looper looper) {
             super(context, looper);
@@ -212,7 +218,7 @@
 
         @Override
         int[] getRunningUserIds() {
-            return new int[] {USER_ID};
+            return mRunningUsers;
         }
 
         @Override
@@ -248,6 +254,11 @@
             return false;
         }
 
+        @Override
+        public List<UserHandle> getValidCrossProfileTargets(String pkg, int userId) {
+            return mCrossProfileTargets;
+        }
+
         // Internal methods
 
         void setDisplayOn(boolean on) {
@@ -379,10 +390,15 @@
     }
 
     private void assertTimeout(AppStandbyController controller, long elapsedTime, int bucket) {
+        assertTimeout(controller, elapsedTime, bucket, USER_ID);
+    }
+
+    private void assertTimeout(AppStandbyController controller, long elapsedTime, int bucket,
+            int userId) {
         mInjector.mElapsedRealtime = elapsedTime;
-        controller.checkIdleStates(USER_ID);
+        controller.checkIdleStates(userId);
         assertEquals(bucket,
-                controller.getAppStandbyBucket(PACKAGE_1, USER_ID, mInjector.mElapsedRealtime,
+                controller.getAppStandbyBucket(PACKAGE_1, userId, mInjector.mElapsedRealtime,
                         false));
     }
 
@@ -397,7 +413,11 @@
     }
 
     private int getStandbyBucket(AppStandbyController controller, String packageName) {
-        return controller.getAppStandbyBucket(packageName, USER_ID, mInjector.mElapsedRealtime,
+        return getStandbyBucket(USER_ID, controller, packageName);
+    }
+
+    private int getStandbyBucket(int userId, AppStandbyController controller, String packageName) {
+        return controller.getAppStandbyBucket(packageName, userId, mInjector.mElapsedRealtime,
                 true);
     }
 
@@ -1012,6 +1032,29 @@
         assertIsNotActiveAdmin(ADMIN_PKG2, USER_ID);
     }
 
+    @Test
+    public void testUserInteraction_CrossProfile() throws Exception {
+        mInjector.mRunningUsers = new int[] {USER_ID, USER_ID2, USER_ID3};
+        mInjector.mCrossProfileTargets = Arrays.asList(USER_HANDLE_USER2);
+        reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1);
+        assertEquals("Cross profile connected package bucket should be elevated on usage",
+                STANDBY_BUCKET_ACTIVE, getStandbyBucket(USER_ID2, mController, PACKAGE_1));
+        assertEquals("Not Cross profile connected package bucket should not be elevated on usage",
+                STANDBY_BUCKET_NEVER, getStandbyBucket(USER_ID3, mController, PACKAGE_1));
+
+        assertTimeout(mController, WORKING_SET_THRESHOLD - 1, STANDBY_BUCKET_ACTIVE, USER_ID);
+        assertTimeout(mController, WORKING_SET_THRESHOLD - 1, STANDBY_BUCKET_ACTIVE, USER_ID2);
+
+        assertTimeout(mController, WORKING_SET_THRESHOLD + 1, STANDBY_BUCKET_WORKING_SET, USER_ID);
+        assertTimeout(mController, WORKING_SET_THRESHOLD + 1, STANDBY_BUCKET_WORKING_SET, USER_ID2);
+
+        mInjector.mCrossProfileTargets = Collections.emptyList();
+        reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1);
+        assertEquals("No longer cross profile connected package bucket should not be "
+                        + "elevated on usage",
+                STANDBY_BUCKET_WORKING_SET, getStandbyBucket(USER_ID2, mController, PACKAGE_1));
+    }
+
     private String getAdminAppsStr(int userId) {
         return getAdminAppsStr(userId, mController.getActiveAdminAppsForTest(userId));
     }
diff --git a/services/tests/uiservicestests/Android.bp b/services/tests/uiservicestests/Android.bp
index 3f0cda3..b7199f7 100644
--- a/services/tests/uiservicestests/Android.bp
+++ b/services/tests/uiservicestests/Android.bp
@@ -29,6 +29,7 @@
     libs: [
         "android.test.runner",
         "android.test.base",
+        "android.test.mock",
     ],
 
     dxflags: ["--multi-dex"],
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index ccce043..d0283f7 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -3246,7 +3246,7 @@
                 new BufferedInputStream(new ByteArrayInputStream(upgradeXml.getBytes())),
                 false,
                 UserHandle.USER_ALL);
-        verify(mSnoozeHelper, times(1)).readXml(any(XmlPullParser.class));
+        verify(mSnoozeHelper, times(1)).readXml(any(XmlPullParser.class), anyLong());
     }
 
     @Test
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
index 7f9732b..5829961 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -36,9 +36,10 @@
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Matchers.eq;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.reset;
@@ -67,6 +68,7 @@
 import android.provider.Settings.Global;
 import android.provider.Settings.Secure;
 import android.service.notification.ConversationChannelWrapper;
+import android.test.mock.MockIContentProvider;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.testing.TestableContentResolver;
 import android.util.ArrayMap;
@@ -87,6 +89,7 @@
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
+import org.mockito.Spy;
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlSerializer;
 
@@ -123,7 +126,7 @@
     @Mock NotificationUsageStats mUsageStats;
     @Mock RankingHandler mHandler;
     @Mock PackageManager mPm;
-    @Mock IContentProvider mTestIContentProvider;
+    @Spy IContentProvider mTestIContentProvider = new MockIContentProvider();
     @Mock Context mContext;
     @Mock ZenModeHelper mMockZenModeHelper;
 
@@ -170,12 +173,12 @@
         when(testContentProvider.getIContentProvider()).thenReturn(mTestIContentProvider);
         contentResolver.addProvider(TEST_AUTHORITY, testContentProvider);
 
-        when(mTestIContentProvider.canonicalize(any(), any(), eq(SOUND_URI)))
-                .thenReturn(CANONICAL_SOUND_URI);
-        when(mTestIContentProvider.canonicalize(any(), any(), eq(CANONICAL_SOUND_URI)))
-                .thenReturn(CANONICAL_SOUND_URI);
-        when(mTestIContentProvider.uncanonicalize(any(), any(), eq(CANONICAL_SOUND_URI)))
-                .thenReturn(SOUND_URI);
+        doReturn(CANONICAL_SOUND_URI)
+                .when(mTestIContentProvider).canonicalize(any(), any(), eq(SOUND_URI));
+        doReturn(CANONICAL_SOUND_URI)
+                .when(mTestIContentProvider).canonicalize(any(), any(), eq(CANONICAL_SOUND_URI));
+        doReturn(SOUND_URI)
+                .when(mTestIContentProvider).uncanonicalize(any(), any(), eq(CANONICAL_SOUND_URI));
 
         mTestNotificationPolicy = new NotificationManager.Policy(0, 0, 0, 0,
                 NotificationManager.Policy.STATE_CHANNELS_BYPASSING_DND, 0);
@@ -506,12 +509,13 @@
                 .appendQueryParameter("title", "Test")
                 .appendQueryParameter("canonical", "1")
                 .build();
-        when(mTestIContentProvider.canonicalize(any(), any(), eq(CANONICAL_SOUND_URI)))
-                .thenReturn(canonicalBasedOnLocal);
-        when(mTestIContentProvider.uncanonicalize(any(), any(), eq(CANONICAL_SOUND_URI)))
-                .thenReturn(localUri);
-        when(mTestIContentProvider.uncanonicalize(any(), any(), eq(canonicalBasedOnLocal)))
-                .thenReturn(localUri);
+        doReturn(canonicalBasedOnLocal)
+                .when(mTestIContentProvider).canonicalize(any(), any(), eq(CANONICAL_SOUND_URI));
+        doReturn(localUri)
+                .when(mTestIContentProvider).uncanonicalize(any(), any(), eq(CANONICAL_SOUND_URI));
+        doReturn(localUri)
+                .when(mTestIContentProvider).uncanonicalize(any(), any(),
+                eq(canonicalBasedOnLocal));
 
         NotificationChannel channel =
                 new NotificationChannel("id", "name", IMPORTANCE_LOW);
@@ -530,10 +534,10 @@
     @Test
     public void testRestoreXml_withNonExistentCanonicalizedSoundUri() throws Exception {
         Thread.sleep(3000);
-        when(mTestIContentProvider.canonicalize(any(), any(), eq(CANONICAL_SOUND_URI)))
-                .thenReturn(null);
-        when(mTestIContentProvider.uncanonicalize(any(), any(), eq(CANONICAL_SOUND_URI)))
-                .thenReturn(null);
+        doReturn(null)
+                .when(mTestIContentProvider).canonicalize(any(), any(), eq(CANONICAL_SOUND_URI));
+        doReturn(null)
+                .when(mTestIContentProvider).uncanonicalize(any(), any(), eq(CANONICAL_SOUND_URI));
 
         NotificationChannel channel =
                 new NotificationChannel("id", "name", IMPORTANCE_LOW);
@@ -557,7 +561,8 @@
     @Test
     public void testRestoreXml_withUncanonicalizedNonLocalSoundUri() throws Exception {
         // Not a local uncanonicalized uri, simulating that it fails to exist locally
-        when(mTestIContentProvider.canonicalize(any(), any(), eq(SOUND_URI))).thenReturn(null);
+        doReturn(null)
+                .when(mTestIContentProvider).canonicalize(any(), any(), eq(SOUND_URI));
         String id = "id";
         String backupWithUncanonicalizedSoundUri = "<ranking version=\"1\">\n"
                 + "<package name=\"" + PKG_N_MR1 + "\" show_badge=\"true\">\n"
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java
index 1dd0b1a..816e8e5 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java
@@ -22,6 +22,7 @@
 import static junit.framework.Assert.assertNull;
 import static junit.framework.Assert.assertTrue;
 
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyInt;
 import static org.mockito.Matchers.anyLong;
@@ -96,10 +97,33 @@
         XmlPullParser parser = Xml.newPullParser();
         parser.setInput(new BufferedInputStream(
                 new ByteArrayInputStream(xml_string.getBytes())), null);
-        mSnoozeHelper.readXml(parser);
-        assertTrue("Should read the notification time from xml and it should be more than zero",
-                0 < mSnoozeHelper.getSnoozeTimeForUnpostedNotification(
-                        0, "pkg", "key").doubleValue());
+        mSnoozeHelper.readXml(parser, 1);
+        assertEquals((long) Long.MAX_VALUE, (long) mSnoozeHelper
+                .getSnoozeTimeForUnpostedNotification(0, "pkg", "key"));
+        verify(mAm, never()).setExactAndAllowWhileIdle(anyInt(), anyLong(), any());
+    }
+
+    @Test
+    public void testWriteXML_afterReading_noNPE()
+            throws XmlPullParserException, IOException {
+        final String max_time_str = Long.toString(Long.MAX_VALUE);
+        final String xml_string = "<snoozed-notifications>"
+                + "<notification version=\"1\" user-id=\"0\" notification=\"notification\" "
+                + "pkg=\"pkg\" key=\"key\" time=\"" + max_time_str + "\"/>"
+                + "<notification version=\"1\" user-id=\"0\" notification=\"notification\" "
+                + "pkg=\"pkg\" key=\"key2\" time=\"" + max_time_str + "\"/>"
+                + "</snoozed-notifications>";
+        XmlPullParser parser = Xml.newPullParser();
+        parser.setInput(new BufferedInputStream(
+                new ByteArrayInputStream(xml_string.getBytes())), null);
+        mSnoozeHelper.readXml(parser, 1);
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        XmlSerializer serializer = new FastXmlSerializer();
+        serializer.setOutput(new BufferedOutputStream(baos), "utf-8");
+        serializer.startDocument(null, true);
+        mSnoozeHelper.writeXml(serializer);
+        serializer.endDocument();
+        serializer.flush();
     }
 
     @Test
@@ -115,7 +139,7 @@
         XmlPullParser parser = Xml.newPullParser();
         parser.setInput(new BufferedInputStream(
                 new ByteArrayInputStream(xml_string.getBytes())), null);
-        mSnoozeHelper.readXml(parser);
+        mSnoozeHelper.readXml(parser, 1);
         assertEquals("Should read the notification context from xml and it should be `uri",
                 "uri", mSnoozeHelper.getSnoozeContextForUnpostedNotification(
                         0, "pkg", "key"));
@@ -137,7 +161,7 @@
         XmlPullParser parser = Xml.newPullParser();
         parser.setInput(new BufferedInputStream(
                 new ByteArrayInputStream(baos.toByteArray())), "utf-8");
-        mSnoozeHelper.readXml(parser);
+        mSnoozeHelper.readXml(parser, 1);
         assertTrue("Should read the notification time from xml and it should be more than zero",
                 0 < mSnoozeHelper.getSnoozeTimeForUnpostedNotification(
                         0, "pkg", r.getKey()).doubleValue());
@@ -161,7 +185,7 @@
         XmlPullParser parser = Xml.newPullParser();
         parser.setInput(new BufferedInputStream(
                 new ByteArrayInputStream(baos.toByteArray())), "utf-8");
-        mSnoozeHelper.readXml(parser);
+        mSnoozeHelper.readXml(parser, 2);
         int systemUser = UserHandle.SYSTEM.getIdentifier();
         assertTrue("Should see a past time returned",
                 System.currentTimeMillis() >  mSnoozeHelper.getSnoozeTimeForUnpostedNotification(
@@ -195,6 +219,30 @@
     }
 
     @Test
+    public void testScheduleRepostsForPersistedNotifications() throws Exception {
+        final String xml_string = "<snoozed-notifications>"
+                + "<notification version=\"1\" user-id=\"0\" notification=\"notification\" "
+                + "pkg=\"pkg\" key=\"key\" time=\"" + 10 + "\"/>"
+                + "<notification version=\"1\" user-id=\"0\" notification=\"notification\" "
+                + "pkg=\"pkg\" key=\"key2\" time=\"" + 15+ "\"/>"
+                + "</snoozed-notifications>";
+        XmlPullParser parser = Xml.newPullParser();
+        parser.setInput(new BufferedInputStream(
+                new ByteArrayInputStream(xml_string.getBytes())), null);
+        mSnoozeHelper.readXml(parser, 4);
+
+        mSnoozeHelper.scheduleRepostsForPersistedNotifications(5);
+
+        ArgumentCaptor<PendingIntent> captor = ArgumentCaptor.forClass(PendingIntent.class);
+        verify(mAm).setExactAndAllowWhileIdle(anyInt(), eq((long) 10), captor.capture());
+        assertEquals("key", captor.getValue().getIntent().getStringExtra(EXTRA_KEY));
+
+        ArgumentCaptor<PendingIntent> captor2 = ArgumentCaptor.forClass(PendingIntent.class);
+        verify(mAm).setExactAndAllowWhileIdle(anyInt(), eq((long) 15), captor2.capture());
+        assertEquals("key2", captor2.getValue().getIntent().getStringExtra(EXTRA_KEY));
+    }
+
+    @Test
     public void testSnoozeForTime() throws Exception {
         NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM);
         mSnoozeHelper.snooze(r, 1000);
@@ -414,6 +462,23 @@
     }
 
     @Test
+    public void testGetSnoozedGroupNotifications_nonGrouped() throws Exception {
+        IntArray profileIds = new IntArray();
+        profileIds.add(UserHandle.USER_CURRENT);
+        when(mUserProfiles.getCurrentProfileIds()).thenReturn(profileIds);
+        NotificationRecord r = getNotificationRecord("pkg", 1, "tag",
+                UserHandle.CURRENT, "group", true);
+        NotificationRecord r2 = getNotificationRecord("pkg", 2, "tag",
+                UserHandle.CURRENT, null, true);
+        mSnoozeHelper.snooze(r, 1000);
+        mSnoozeHelper.snooze(r2, 1000);
+
+        assertEquals(1,
+                mSnoozeHelper.getNotifications("pkg", "group", UserHandle.USER_CURRENT).size());
+        // and no NPE
+    }
+
+    @Test
     public void testGetSnoozedNotificationByKey() throws Exception {
         IntArray profileIds = new IntArray();
         profileIds.add(UserHandle.USER_CURRENT);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
index bc2766c..cee486f 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
@@ -16,6 +16,19 @@
 
 package com.android.server.notification;
 
+import static android.app.NotificationManager.Policy.CONVERSATION_SENDERS_ANYONE;
+import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_ALARMS;
+import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_CALLS;
+import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_CONVERSATIONS;
+import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_EVENTS;
+import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_MEDIA;
+import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_MESSAGES;
+import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_REMINDERS;
+import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_REPEAT_CALLERS;
+import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_SYSTEM;
+import static android.app.NotificationManager.Policy.PRIORITY_SENDERS_ANY;
+import static android.app.NotificationManager.Policy.PRIORITY_SENDERS_CONTACTS;
+import static android.app.NotificationManager.Policy.PRIORITY_SENDERS_STARRED;
 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_BADGE;
 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS;
@@ -219,7 +232,7 @@
     public void testZenOff_NoMuteApplied() {
         mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_OFF;
         mZenModeHelperSpy.mConsolidatedPolicy = new Policy(Policy.PRIORITY_CATEGORY_ALARMS |
-                Policy.PRIORITY_CATEGORY_MEDIA, 0, 0, 0, 0, 0);
+                PRIORITY_CATEGORY_MEDIA, 0, 0, 0, 0, 0);
         mZenModeHelperSpy.applyRestrictions();
 
         doNothing().when(mZenModeHelperSpy).applyRestrictions(eq(false), anyBoolean(), anyInt());
@@ -230,10 +243,73 @@
     }
 
     @Test
+    public void testZenOn_NotificationApplied() {
+        mZenModeHelperSpy.mZenMode = Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+        // The most permissive policy
+        mZenModeHelperSpy.mConsolidatedPolicy = new Policy(Policy.PRIORITY_CATEGORY_ALARMS |
+                PRIORITY_CATEGORY_MEDIA | PRIORITY_CATEGORY_MESSAGES
+                | PRIORITY_CATEGORY_CONVERSATIONS | PRIORITY_CATEGORY_CALLS
+                | PRIORITY_CATEGORY_ALARMS | PRIORITY_CATEGORY_EVENTS | PRIORITY_CATEGORY_REMINDERS
+                | PRIORITY_CATEGORY_REPEAT_CALLERS | PRIORITY_CATEGORY_SYSTEM, PRIORITY_SENDERS_ANY,
+                PRIORITY_SENDERS_ANY, 0, CONVERSATION_SENDERS_ANYONE);
+        mZenModeHelperSpy.applyRestrictions();
+
+        doNothing().when(mZenModeHelperSpy).applyRestrictions(anyBoolean(), anyBoolean(), anyInt());
+        verify(mZenModeHelperSpy).applyRestrictions(true, true,
+                AudioAttributes.USAGE_NOTIFICATION);
+        verify(mZenModeHelperSpy).applyRestrictions(true, true,
+                AudioAttributes.USAGE_NOTIFICATION_EVENT);
+        verify(mZenModeHelperSpy).applyRestrictions(true, true,
+                AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_DELAYED);
+        verify(mZenModeHelperSpy).applyRestrictions(true, true,
+                AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_INSTANT);
+    }
+
+    @Test
+    public void testZenOn_StarredCallers_CallTypesBlocked() {
+        mZenModeHelperSpy.mZenMode = Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+        // The most permissive policy
+        mZenModeHelperSpy.mConsolidatedPolicy = new Policy(Policy.PRIORITY_CATEGORY_ALARMS |
+                PRIORITY_CATEGORY_MEDIA | PRIORITY_CATEGORY_MESSAGES
+                | PRIORITY_CATEGORY_CONVERSATIONS | PRIORITY_CATEGORY_CALLS
+                | PRIORITY_CATEGORY_ALARMS | PRIORITY_CATEGORY_EVENTS | PRIORITY_CATEGORY_REMINDERS
+                | PRIORITY_CATEGORY_SYSTEM,
+                PRIORITY_SENDERS_STARRED,
+                PRIORITY_SENDERS_ANY, 0, CONVERSATION_SENDERS_ANYONE);
+        mZenModeHelperSpy.applyRestrictions();
+
+        doNothing().when(mZenModeHelperSpy).applyRestrictions(anyBoolean(), anyBoolean(), anyInt());
+        verify(mZenModeHelperSpy).applyRestrictions(true, true,
+                AudioAttributes.USAGE_NOTIFICATION_RINGTONE);
+        verify(mZenModeHelperSpy).applyRestrictions(true, true,
+                AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST);
+    }
+
+    @Test
+    public void testZenOn_AllCallers_CallTypesAllowed() {
+        mZenModeHelperSpy.mZenMode = Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+        // The most permissive policy
+        mZenModeHelperSpy.mConsolidatedPolicy = new Policy(Policy.PRIORITY_CATEGORY_ALARMS |
+                PRIORITY_CATEGORY_MEDIA | PRIORITY_CATEGORY_MESSAGES
+                | PRIORITY_CATEGORY_CONVERSATIONS | PRIORITY_CATEGORY_CALLS
+                | PRIORITY_CATEGORY_ALARMS | PRIORITY_CATEGORY_EVENTS | PRIORITY_CATEGORY_REMINDERS
+                | PRIORITY_CATEGORY_REPEAT_CALLERS | PRIORITY_CATEGORY_SYSTEM,
+                PRIORITY_SENDERS_ANY,
+                PRIORITY_SENDERS_ANY, 0, CONVERSATION_SENDERS_ANYONE);
+        mZenModeHelperSpy.applyRestrictions();
+
+        doNothing().when(mZenModeHelperSpy).applyRestrictions(anyBoolean(), anyBoolean(), anyInt());
+        verify(mZenModeHelperSpy).applyRestrictions(true, false,
+                AudioAttributes.USAGE_NOTIFICATION_RINGTONE);
+        verify(mZenModeHelperSpy).applyRestrictions(true, false,
+                AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST);
+    }
+
+    @Test
     public void testZenOn_AllowAlarmsMedia_NoAlarmMediaMuteApplied() {
         mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
         mZenModeHelperSpy.mConsolidatedPolicy = new Policy(Policy.PRIORITY_CATEGORY_ALARMS |
-                Policy.PRIORITY_CATEGORY_MEDIA, 0, 0, 0, 0, 0);
+                PRIORITY_CATEGORY_MEDIA, 0, 0, 0, 0, 0);
 
         mZenModeHelperSpy.applyRestrictions();
         verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true, false,
@@ -261,7 +337,7 @@
     public void testTotalSilence() {
         mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_NO_INTERRUPTIONS;
         mZenModeHelperSpy.mConsolidatedPolicy = new Policy(Policy.PRIORITY_CATEGORY_ALARMS |
-                Policy.PRIORITY_CATEGORY_MEDIA, 0, 0, 0, 0, 0);
+                PRIORITY_CATEGORY_MEDIA, 0, 0, 0, 0, 0);
         mZenModeHelperSpy.applyRestrictions();
 
         // Total silence will silence alarms, media and system noises (but not vibrations)
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index a0ea729..c9c3649 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -1025,9 +1025,9 @@
     public void testDestroyIfPossible_lastActivityAboveEmptyHomeStack() {
         // Empty the home stack.
         final ActivityStack homeStack = mActivity.getDisplay().getRootHomeTask();
-        homeStack.forAllTasks((t) -> {
+        homeStack.forAllLeafTasks((t) -> {
             homeStack.removeChild(t, "test");
-        }, true /* traverseTopToBottom */, homeStack);
+        }, true /* traverseTopToBottom */);
         mActivity.finishing = true;
         doReturn(false).when(mRootWindowContainer).resumeFocusedStacksTopActivities();
         spyOn(mStack);
@@ -1051,9 +1051,9 @@
     public void testCompleteFinishing_lastActivityAboveEmptyHomeStack() {
         // Empty the home stack.
         final ActivityStack homeStack = mActivity.getDisplay().getRootHomeTask();
-        homeStack.forAllTasks((t) -> {
+        homeStack.forAllLeafTasks((t) -> {
             homeStack.removeChild(t, "test");
-        }, true /* traverseTopToBottom */, homeStack);
+        }, true /* traverseTopToBottom */);
         mActivity.finishing = true;
         spyOn(mStack);
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index 1a8f2a6..b3c6b22 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -27,6 +27,7 @@
 import static android.view.DisplayCutout.BOUNDS_POSITION_LEFT;
 import static android.view.DisplayCutout.BOUNDS_POSITION_TOP;
 import static android.view.DisplayCutout.fromBoundingRect;
+import static android.view.Surface.ROTATION_0;
 import static android.view.Surface.ROTATION_90;
 import static android.view.View.SYSTEM_UI_FLAG_FULLSCREEN;
 import static android.view.View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
@@ -998,12 +999,10 @@
     public void testApplyTopFixedRotationTransform() {
         mWm.mIsFixedRotationTransformEnabled = true;
         final Configuration config90 = new Configuration();
-        mDisplayContent.getDisplayRotation().setRotation(ROTATION_90);
-        mDisplayContent.computeScreenConfiguration(config90);
-        mDisplayContent.onRequestedOverrideConfigurationChanged(config90);
+        mDisplayContent.computeScreenConfiguration(config90, ROTATION_90);
 
         final Configuration config = new Configuration();
-        mDisplayContent.getDisplayRotation().setRotation(Surface.ROTATION_0);
+        mDisplayContent.getDisplayRotation().setRotation(ROTATION_0);
         mDisplayContent.computeScreenConfiguration(config);
         mDisplayContent.onRequestedOverrideConfigurationChanged(config);
 
@@ -1014,11 +1013,18 @@
         app.setRequestedOrientation(SCREEN_ORIENTATION_LANDSCAPE);
 
         assertTrue(app.isFixedRotationTransforming());
+        assertTrue(mDisplayContent.getDisplayRotation().shouldRotateSeamlessly(
+                ROTATION_0 /* oldRotation */, ROTATION_90 /* newRotation */,
+                false /* forceUpdate */));
+        // The display should keep current orientation and the rotated configuration should apply
+        // to the activity.
         assertEquals(config.orientation, mDisplayContent.getConfiguration().orientation);
         assertEquals(config90.orientation, app.getConfiguration().orientation);
+        assertEquals(config90.windowConfiguration.getBounds(), app.getBounds());
 
         mDisplayContent.mAppTransition.notifyAppTransitionFinishedLocked(app.token);
 
+        // The display should be rotated after the launch is finished.
         assertFalse(app.hasFixedRotationTransform());
         assertEquals(config90.orientation, mDisplayContent.getConfiguration().orientation);
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
index ba57745..2b0ad89 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
@@ -605,6 +605,7 @@
 
         mWindow.mAttrs.flags =
                 FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
+        mWindow.mAttrs.setFitInsetsTypes(0 /* types */);
         addWindow(mWindow);
 
         mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
@@ -625,6 +626,7 @@
 
         mWindow.mAttrs.flags =
                 FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
+        mWindow.mAttrs.setFitInsetsTypes(0 /* types */);
         mWindow.mAttrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER;
         addWindow(mWindow);
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
index dd46673..ec20262 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
@@ -313,8 +313,8 @@
      */
     @Test
     public void testResizeDockedStackForSplitScreenPrimary() {
-        final Rect taskSize = new Rect(0, 0, 1000, 1000);
-        final Rect stackSize = new Rect(0, 0, 300, 300);
+        final Rect configSize = new Rect(0, 0, 1000, 1000);
+        final Rect displayedSize = new Rect(0, 0, 300, 300);
 
         // Create primary split-screen stack with a task.
         final ActivityStack primaryStack = new StackBuilder(mRootWindowContainer)
@@ -325,11 +325,13 @@
         final Task task = primaryStack.getTopMostTask();
 
         // Resize dock stack.
-        mService.resizeDockedStack(stackSize, taskSize, null, null, null);
+        mService.resizeDockedStack(displayedSize, configSize, null, null, null);
 
         // Verify dock stack & its task bounds if is equal as resized result.
-        assertEquals(stackSize, primaryStack.getBounds());
-        assertEquals(taskSize, task.getBounds());
+        assertEquals(displayedSize, primaryStack.getDisplayedBounds());
+        assertEquals(displayedSize, primaryStack.getDisplayedBounds());
+        assertEquals(configSize, primaryStack.getBounds());
+        assertEquals(configSize, task.getBounds());
     }
 
     /**
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java
index cd53ece..45b51cf 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java
@@ -28,6 +28,7 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
 
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
@@ -300,6 +301,7 @@
         Rect newSize = new Rect(10, 10, 300, 300);
         Configuration c = new Configuration(tile1.getRequestedOverrideConfiguration());
         c.windowConfiguration.setBounds(newSize);
+        doNothing().when(stack).adjustForMinimalTaskDimensions(any(), any());
         tile1.onRequestedOverrideConfigurationChanged(c);
         assertEquals(newSize, stack.getBounds());
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java
index 6e4be88..6387a3b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java
@@ -16,9 +16,11 @@
 
 package com.android.server.wm;
 
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
 
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
@@ -33,6 +35,7 @@
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.clearInvocations;
 
+import android.app.WindowConfiguration;
 import android.graphics.Rect;
 import android.platform.test.annotations.Presubmit;
 
@@ -184,6 +187,16 @@
         doReturn(stackOutset).when(stack).getStackOutset();
         doReturn(true).when(stack).inMultiWindowMode();
 
+        // Mock the resolved override windowing mode to non-fullscreen
+        final WindowConfiguration windowConfiguration =
+                stack.getResolvedOverrideConfiguration().windowConfiguration;
+        spyOn(windowConfiguration);
+        doReturn(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY)
+                .when(windowConfiguration).getWindowingMode();
+
+        // Prevent adjust task dimensions
+        doNothing().when(stack).adjustForMinimalTaskDimensions(any(), any());
+
         final Rect stackBounds = new Rect(200, 200, 800, 1000);
         // Update surface position and size by the given bounds.
         stack.setBounds(stackBounds);
diff --git a/services/usage/java/com/android/server/usage/StorageStatsService.java b/services/usage/java/com/android/server/usage/StorageStatsService.java
index 18b640f..c3d3d83 100644
--- a/services/usage/java/com/android/server/usage/StorageStatsService.java
+++ b/services/usage/java/com/android/server/usage/StorageStatsService.java
@@ -86,6 +86,7 @@
 public class StorageStatsService extends IStorageStatsManager.Stub {
     private static final String TAG = "StorageStatsService";
 
+    private static final String PROP_STORAGE_CRATES = "fw.storage_crates";
     private static final String PROP_DISABLE_QUOTA = "fw.disable_quota";
     private static final String PROP_VERIFY_STORAGE = "fw.verify_storage";
 
@@ -595,6 +596,13 @@
                 Uri.parse("content://com.android.externalstorage.documents/"), null, false);
     }
 
+    private static void checkCratesEnable() {
+        final boolean enable = SystemProperties.getBoolean(PROP_STORAGE_CRATES, false);
+        if (!enable) {
+            throw new IllegalStateException("Storage Crate feature is disabled.");
+        }
+    }
+
     /**
      * To enforce the calling or self to have the {@link android.Manifest.permission#MANAGE_CRATES}
      * permission.
@@ -650,6 +658,7 @@
     @Override
     public ParceledListSlice<CrateInfo> queryCratesForPackage(String volumeUuid,
             @NonNull String packageName, @UserIdInt int userId, @NonNull String callingPackage) {
+        checkCratesEnable();
         if (userId != UserHandle.getCallingUserId()) {
             mContext.enforceCallingOrSelfPermission(
                     android.Manifest.permission.INTERACT_ACROSS_USERS, TAG);
@@ -677,6 +686,7 @@
     @Override
     public ParceledListSlice<CrateInfo> queryCratesForUid(String volumeUuid, int uid,
             @NonNull String callingPackage) {
+        checkCratesEnable();
         final int userId = UserHandle.getUserId(uid);
         if (userId != UserHandle.getCallingUserId()) {
             mContext.enforceCallingOrSelfPermission(
@@ -718,6 +728,7 @@
     @Override
     public ParceledListSlice<CrateInfo> queryCratesForUser(String volumeUuid, int userId,
             @NonNull String callingPackage) {
+        checkCratesEnable();
         if (userId != UserHandle.getCallingUserId()) {
             mContext.enforceCallingOrSelfPermission(
                     android.Manifest.permission.INTERACT_ACROSS_USERS, TAG);
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index 6407ec7..84f411f 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -41,6 +41,7 @@
 import android.content.pm.PackageManager;
 import android.content.res.Resources;
 import android.debug.AdbManagerInternal;
+import android.debug.AdbTransportType;
 import android.debug.IAdbTransport;
 import android.hardware.usb.ParcelableUsbPort;
 import android.hardware.usb.UsbAccessory;
@@ -775,8 +776,10 @@
             }
 
             @Override
-            public void onAdbEnabled(boolean enabled) {
-                mHandler.sendMessage(MSG_ENABLE_ADB, enabled);
+            public void onAdbEnabled(boolean enabled, byte transportType) {
+                if (transportType == AdbTransportType.USB) {
+                    mHandler.sendMessage(MSG_ENABLE_ADB, enabled);
+                }
             }
         }
 
@@ -1170,7 +1173,8 @@
         }
 
         protected boolean isAdbEnabled() {
-            return LocalServices.getService(AdbManagerInternal.class).isAdbEnabled();
+            return LocalServices.getService(AdbManagerInternal.class)
+                    .isAdbEnabled(AdbTransportType.USB);
         }
 
         protected void updateAdbNotification(boolean force) {
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
old mode 100644
new mode 100755
index 52213d8..c5fcf67
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -465,8 +465,27 @@
          * @hide
          */
         public static final int CAPABILITY_ADD_PARTICIPANT = 0x02000000;
+
+        /**
+         * When set for a call, indicates that this {@code Call} can be transferred to another
+         * number.
+         * Call supports the blind and assured call transfer feature.
+         *
+         * @hide
+         */
+        public static final int CAPABILITY_TRANSFER = 0x04000000;
+
+        /**
+         * When set for a call, indicates that this {@code Call} can be transferred to another
+         * ongoing call.
+         * Call supports the consultative call transfer feature.
+         *
+         * @hide
+         */
+        public static final int CAPABILITY_TRANSFER_CONSULTATIVE = 0x08000000;
+
         //******************************************************************************************
-        // Next CAPABILITY value: 0x04000000
+        // Next CAPABILITY value: 0x10000000
         //******************************************************************************************
 
         /**
@@ -699,6 +718,12 @@
             if (can(capabilities, CAPABILITY_ADD_PARTICIPANT)) {
                 builder.append(" CAPABILITY_ADD_PARTICIPANT");
             }
+            if (can(capabilities, CAPABILITY_TRANSFER)) {
+                builder.append(" CAPABILITY_TRANSFER");
+            }
+            if (can(capabilities, CAPABILITY_TRANSFER_CONSULTATIVE)) {
+                builder.append(" CAPABILITY_TRANSFER_CONSULTATIVE");
+            }
             builder.append("]");
             return builder.toString();
         }
@@ -1564,6 +1589,30 @@
     }
 
     /**
+     * Instructs this {@code Call} to be transferred to another number.
+     *
+     * @param targetNumber The address to which the call will be transferred.
+     * @param isConfirmationRequired if {@code true} it will initiate ASSURED transfer,
+     * if {@code false}, it will initiate BLIND transfer.
+     *
+     * @hide
+     */
+    public void transfer(@NonNull Uri targetNumber, boolean isConfirmationRequired) {
+        mInCallAdapter.transferCall(mTelecomCallId, targetNumber, isConfirmationRequired);
+    }
+
+    /**
+     * Instructs this {@code Call} to be transferred to another ongoing call.
+     * This will initiate CONSULTATIVE transfer.
+     * @param toCall The other ongoing {@code Call} to which this call will be transferred.
+     *
+     * @hide
+     */
+    public void transfer(@NonNull android.telecom.Call toCall) {
+        mInCallAdapter.transferCall(mTelecomCallId, toCall.mTelecomCallId);
+    }
+
+    /**
      * Instructs this {@code Call} to disconnect.
      */
     public void disconnect() {
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
old mode 100644
new mode 100755
index 3b0ba25..4604cd2
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -387,8 +387,25 @@
      * @hide
      */
     public static final int CAPABILITY_ADD_PARTICIPANT = 0x04000000;
+
+    /**
+     * Indicates that this {@code Connection} can be transferred to another
+     * number.
+     * Connection supports the blind and assured call transfer feature.
+     * @hide
+     */
+    public static final int CAPABILITY_TRANSFER = 0x08000000;
+
+    /**
+     * Indicates that this {@code Connection} can be transferred to another
+     * ongoing {@code Connection}.
+     * Connection supports the consultative call transfer feature.
+     * @hide
+     */
+    public static final int CAPABILITY_TRANSFER_CONSULTATIVE = 0x10000000;
+
     //**********************************************************************************************
-    // Next CAPABILITY value: 0x08000000
+    // Next CAPABILITY value: 0x20000000
     //**********************************************************************************************
 
     /**
@@ -967,6 +984,13 @@
         if ((capabilities & CAPABILITY_ADD_PARTICIPANT) == CAPABILITY_ADD_PARTICIPANT) {
             builder.append(isLong ? " CAPABILITY_ADD_PARTICIPANT" : " add_participant");
         }
+        if ((capabilities & CAPABILITY_TRANSFER) == CAPABILITY_TRANSFER) {
+            builder.append(isLong ? " CAPABILITY_TRANSFER" : " sup_trans");
+        }
+        if ((capabilities & CAPABILITY_TRANSFER_CONSULTATIVE)
+                == CAPABILITY_TRANSFER_CONSULTATIVE) {
+            builder.append(isLong ? " CAPABILITY_TRANSFER_CONSULTATIVE" : " sup_cTrans");
+        }
         builder.append("]");
         return builder.toString();
     }
@@ -3092,6 +3116,26 @@
     public void onReject(String replyMessage) {}
 
     /**
+     * Notifies this Connection, a request to transfer to a target number.
+     * @param number the number to transfer this {@link Connection} to.
+     * @param isConfirmationRequired when {@code true}, the {@link ConnectionService}
+     * should wait until the transfer has successfully completed before disconnecting
+     * the current {@link Connection}.
+     * When {@code false}, the {@link ConnectionService} should signal the network to
+     * perform the transfer, but should immediately disconnect the call regardless of
+     * the outcome of the transfer.
+     * @hide
+     */
+    public void onTransfer(@NonNull Uri number, boolean isConfirmationRequired) {}
+
+    /**
+     * Notifies this Connection, a request to transfer to another Connection.
+     * @param otherConnection the {@link Connection} to transfer this call to.
+     * @hide
+     */
+    public void onTransfer(@NonNull Connection otherConnection) {}
+
+    /**
      * Notifies this Connection of a request to silence the ringer.
      * <p>
      * The ringer may be silenced by any of the following methods:
@@ -3532,7 +3576,7 @@
      * ATIS-1000082.
      * @return the verification status.
      */
-    public @VerificationStatus int getCallerNumberVerificationStatus() {
+    public final @VerificationStatus int getCallerNumberVerificationStatus() {
         return mCallerNumberVerificationStatus;
     }
 
@@ -3544,7 +3588,7 @@
      * by
      * {@link ConnectionService#onCreateIncomingConnection(PhoneAccountHandle, ConnectionRequest)}.
      */
-    public void setCallerNumberVerificationStatus(
+    public final void setCallerNumberVerificationStatus(
             @VerificationStatus int callerNumberVerificationStatus) {
         mCallerNumberVerificationStatus = callerNumberVerificationStatus;
     }
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
old mode 100644
new mode 100755
index 2aea723..0dca006
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -128,6 +128,8 @@
     private static final String SESSION_ANSWER = "CS.an";
     private static final String SESSION_ANSWER_VIDEO = "CS.anV";
     private static final String SESSION_DEFLECT = "CS.def";
+    private static final String SESSION_TRANSFER = "CS.trans";
+    private static final String SESSION_CONSULTATIVE_TRANSFER = "CS.cTrans";
     private static final String SESSION_REJECT = "CS.r";
     private static final String SESSION_REJECT_MESSAGE = "CS.rWM";
     private static final String SESSION_SILENCE = "CS.s";
@@ -196,6 +198,8 @@
     private static final int MSG_CREATE_CONFERENCE_FAILED = 37;
     private static final int MSG_REJECT_WITH_REASON = 38;
     private static final int MSG_ADD_PARTICIPANT = 39;
+    private static final int MSG_EXPLICIT_CALL_TRANSFER = 40;
+    private static final int MSG_EXPLICIT_CALL_TRANSFER_CONSULTATIVE = 41;
 
     private static Connection sNullConnection;
 
@@ -481,6 +485,38 @@
         }
 
         @Override
+        public void transfer(@NonNull String callId, @NonNull Uri number,
+                boolean isConfirmationRequired, Session.Info sessionInfo) {
+            Log.startSession(sessionInfo, SESSION_TRANSFER);
+            try {
+                SomeArgs args = SomeArgs.obtain();
+                args.arg1 = callId;
+                args.arg2 = number;
+                args.argi1 = isConfirmationRequired ? 1 : 0;
+                args.arg3 = Log.createSubsession();
+                mHandler.obtainMessage(MSG_EXPLICIT_CALL_TRANSFER, args).sendToTarget();
+            } finally {
+                Log.endSession();
+            }
+        }
+
+        @Override
+        public void consultativeTransfer(@NonNull String callId, @NonNull String otherCallId,
+                Session.Info sessionInfo) {
+            Log.startSession(sessionInfo, SESSION_CONSULTATIVE_TRANSFER);
+            try {
+                SomeArgs args = SomeArgs.obtain();
+                args.arg1 = callId;
+                args.arg2 = otherCallId;
+                args.arg3 = Log.createSubsession();
+                mHandler.obtainMessage(
+                        MSG_EXPLICIT_CALL_TRANSFER_CONSULTATIVE, args).sendToTarget();
+            } finally {
+                Log.endSession();
+            }
+        }
+
+        @Override
         public void silence(String callId, Session.Info sessionInfo) {
             Log.startSession(sessionInfo, SESSION_SILENCE);
             try {
@@ -1108,6 +1144,30 @@
                     }
                     break;
                 }
+                case MSG_EXPLICIT_CALL_TRANSFER: {
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    Log.continueSession((Session) args.arg3, SESSION_HANDLER + SESSION_TRANSFER);
+                    try {
+                        final boolean isConfirmationRequired = args.argi1 == 1;
+                        transfer((String) args.arg1, (Uri) args.arg2, isConfirmationRequired);
+                    } finally {
+                        args.recycle();
+                        Log.endSession();
+                    }
+                    break;
+                }
+                case MSG_EXPLICIT_CALL_TRANSFER_CONSULTATIVE: {
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    Log.continueSession(
+                            (Session) args.arg3, SESSION_HANDLER + SESSION_CONSULTATIVE_TRANSFER);
+                    try {
+                        consultativeTransfer((String) args.arg1, (String) args.arg2);
+                    } finally {
+                        args.recycle();
+                        Log.endSession();
+                    }
+                    break;
+                }
                 case MSG_DISCONNECT: {
                     SomeArgs args = (SomeArgs) msg.obj;
                     Log.continueSession((Session) args.arg2, SESSION_HANDLER + SESSION_DISCONNECT);
@@ -2042,6 +2102,18 @@
         findConnectionForAction(callId, "reject").onReject(rejectReason);
     }
 
+    private void transfer(String callId, Uri number, boolean isConfirmationRequired) {
+        Log.d(this, "transfer %s", callId);
+        findConnectionForAction(callId, "transfer").onTransfer(number, isConfirmationRequired);
+    }
+
+    private void consultativeTransfer(String callId, String otherCallId) {
+        Log.d(this, "consultativeTransfer %s", callId);
+        Connection connection1 = findConnectionForAction(callId, "consultativeTransfer");
+        Connection connection2 = findConnectionForAction(otherCallId, " consultativeTransfer");
+        connection1.onTransfer(connection2);
+    }
+
     private void silence(String callId) {
         Log.d(this, "silence %s", callId);
         findConnectionForAction(callId, "silence").onSilence();
diff --git a/telecomm/java/android/telecom/InCallAdapter.java b/telecomm/java/android/telecom/InCallAdapter.java
old mode 100644
new mode 100755
index 9d291740..dd6c153
--- a/telecomm/java/android/telecom/InCallAdapter.java
+++ b/telecomm/java/android/telecom/InCallAdapter.java
@@ -16,6 +16,7 @@
 
 package android.telecom;
 
+import android.annotation.NonNull;
 import android.bluetooth.BluetoothDevice;
 import android.net.Uri;
 import android.os.Bundle;
@@ -102,6 +103,35 @@
     }
 
     /**
+     * Instructs Telecom to transfer the specified call.
+     *
+     * @param callId The identifier of the call to transfer.
+     * @param targetNumber The address to transfer to.
+     * @param isConfirmationRequired if {@code true} it will initiate ASSURED transfer,
+     * if {@code false}, it will initiate BLIND transfer.
+     */
+    public void transferCall(@NonNull String callId, @NonNull Uri targetNumber,
+            boolean isConfirmationRequired) {
+        try {
+            mAdapter.transferCall(callId, targetNumber, isConfirmationRequired);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
+     * Instructs Telecom to transfer the specified call to another ongoing call.
+     *
+     * @param callId The identifier of the call to transfer.
+     * @param otherCallId The identifier of the other call to which this will be transferred.
+     */
+    public void transferCall(@NonNull String callId, @NonNull String otherCallId) {
+        try {
+            mAdapter.consultativeTransfer(callId, otherCallId);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
      * Instructs Telecom to disconnect the specified call.
      *
      * @param callId The identifier of the call to disconnect.
diff --git a/telecomm/java/com/android/internal/telecom/IConnectionService.aidl b/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
index a397d77..fb54179 100644
--- a/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
+++ b/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
@@ -81,6 +81,11 @@
 
     void rejectWithMessage(String callId, String message, in Session.Info sessionInfo);
 
+    void transfer(String callId, in Uri number, boolean isConfirmationRequired,
+            in Session.Info sessionInfo);
+
+    void consultativeTransfer(String callId, String otherCallId, in Session.Info sessionInfo);
+
     void disconnect(String callId, in Session.Info sessionInfo);
 
     void silence(String callId, in Session.Info sessionInfo);
diff --git a/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl b/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl
old mode 100644
new mode 100755
index 9beff22..edf1cf4
--- a/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl
+++ b/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl
@@ -36,6 +36,10 @@
 
     void rejectCallWithReason(String callId, int rejectReason);
 
+    void transferCall(String callId, in Uri targetNumber, boolean isConfirmationRequired);
+
+    void consultativeTransfer(String callId, String otherCallId);
+
     void disconnectCall(String callId);
 
     void holdCall(String callId);
diff --git a/telephony/java/android/telephony/Annotation.java b/telephony/java/android/telephony/Annotation.java
index a27c480..9ae86c8 100644
--- a/telephony/java/android/telephony/Annotation.java
+++ b/telephony/java/android/telephony/Annotation.java
@@ -432,7 +432,7 @@
             DataFailCause.LIMITED_TO_IPV6,
             DataFailCause.VSNCP_TIMEOUT,
             DataFailCause.VSNCP_GEN_ERROR,
-            DataFailCause.VSNCP_APN_UNATHORIZED,
+            DataFailCause.VSNCP_APN_UNAUTHORIZED,
             DataFailCause.VSNCP_PDN_LIMIT_EXCEEDED,
             DataFailCause.VSNCP_NO_PDN_GATEWAY_ADDRESS,
             DataFailCause.VSNCP_PDN_GATEWAY_UNREACHABLE,
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 9924839c..a7e52ea 100755
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -36,6 +36,8 @@
 import com.android.internal.telephony.ICarrierConfigLoader;
 import com.android.telephony.Rlog;
 
+import java.util.concurrent.TimeUnit;
+
 /**
  * Provides access to telephony configuration values that are carrier-specific.
  */
@@ -838,7 +840,8 @@
     /**
      * The default flag specifying whether ETWS/CMAS test setting is forcibly disabled in
      * Settings->More->Emergency broadcasts menu even though developer options is turned on.
-     * @deprecated moved to cellbroadcastreceiver resource show_test_settings
+     * @deprecated Use {@code com.android.cellbroadcastreceiver.CellBroadcastReceiver} resource
+     * {@code show_test_settings} to control whether to show test alert settings or not.
      */
     @Deprecated
     public static final String KEY_CARRIER_FORCE_DISABLE_ETWS_CMAS_TEST_BOOL =
@@ -1987,6 +1990,13 @@
             "carrier_allow_deflect_ims_call_bool";
 
     /**
+     * Flag indicating whether the carrier supports explicit call transfer for an IMS call.
+     * @hide
+     */
+    public static final String KEY_CARRIER_ALLOW_TRANSFER_IMS_CALL_BOOL =
+            "carrier_allow_transfer_ims_call_bool";
+
+    /**
      * Flag indicating whether the carrier always wants to play an "on-hold" tone when a call has
      * been remotely held.
      * <p>
@@ -2016,10 +2026,15 @@
             "allow_add_call_during_video_call";
 
     /**
-     * When false, indicates that holding a video call is disabled
+     * When {@code true}, indicates that video calls can be put on hold in order to swap to another
+     * call (e.g. a new outgoing call).
+     * When {@code false}, indicates that video calls will be disconnected when swapping to another
+     * call.
+     * <p>
+     * This is {@code true} by default.
      */
-    public static final String KEY_ALLOW_HOLDING_VIDEO_CALL_BOOL =
-            "allow_holding_video_call";
+    public static final String KEY_ALLOW_HOLD_VIDEO_CALL_BOOL =
+            "allow_hold_video_call_bool";
 
     /**
      * When true, indicates that the HD audio icon in the in-call screen should not be shown for
@@ -2466,6 +2481,21 @@
             "parameters_use_for_5g_nr_signal_bar_int";
 
     /**
+     * String array of default bandwidth values per network type.
+     * The entries should be of form "network_name:downstream,upstream", with values in Kbps.
+     * @hide
+     */
+    public static final String KEY_BANDWIDTH_STRING_ARRAY = "bandwidth_string_array";
+
+    /**
+     * For NR (non-standalone), whether to use the LTE value instead of NR value as the default for
+     * upstream bandwidth. Downstream bandwidth will still use the NR value as the default.
+     * @hide
+     */
+    public static final String KEY_BANDWIDTH_NR_NSA_USE_LTE_VALUE_FOR_UPSTREAM_BOOL =
+            "bandwidth_nr_nsa_use_lte_value_for_upstream_bool";
+
+    /**
      * Key identifying if voice call barring notification is required to be shown to the user.
      * @hide
      */
@@ -2967,6 +2997,33 @@
             "5g_icon_display_grace_period_sec_int";
 
     /**
+     * Controls time in milliseconds until DcTracker reevaluates 5G connection state.
+     */
+    public static final String KEY_5G_WATCHDOG_TIME_MS_LONG = "5g_watchdog_time_long";
+
+    /**
+     * Whether NR (non-standalone) should be unmetered for all frequencies.
+     * If either {@link #KEY_UNMETERED_NR_NSA_MMWAVE_BOOL} or
+     * {@link #KEY_UNMETERED_NR_NSA_SUB6_BOOL} are true, then this value will be ignored.
+     * @hide
+     */
+    public static final String KEY_UNMETERED_NR_NSA_BOOL = "unmetered_nr_nsa_bool";
+
+    /**
+     * Whether NR (non-standalone) frequencies above 6GHz (millimeter wave) should be unmetered.
+     * If this is true, then the value for {@link #KEY_UNMETERED_NR_NSA_BOOL} will be ignored.
+     * @hide
+     */
+    public static final String KEY_UNMETERED_NR_NSA_MMWAVE_BOOL = "unmetered_nr_nsa_mmwave_bool";
+
+    /**
+     * Whether NR (non-standalone) frequencies below 6GHz (sub6) should be unmetered.
+     * If this is true, then the value for {@link #KEY_UNMETERED_NR_NSA_BOOL} will be ignored.
+     * @hide
+     */
+    public static final String KEY_UNMETERED_NR_NSA_SUB6_BOOL = "unmetered_nr_nsa_sub6_bool";
+
+    /**
      * Support ASCII 7-BIT encoding for long SMS. This carrier config is used to enable
      * this feature.
      * @hide
@@ -3038,11 +3095,6 @@
             "ping_test_before_data_switch_bool";
 
     /**
-     * Controls time in milliseconds until DcTracker reevaluates 5G connection state.
-     */
-    public static final String KEY_5G_WATCHDOG_TIME_MS_LONG =
-            "5g_watchdog_time_long";
-    /**
      * Controls whether to switch data to primary from opportunistic subscription
      * if primary is out of service. This control only affects system or 1st party app
      * initiated data switch, but will not override data switch initiated by privileged carrier apps
@@ -3505,6 +3557,7 @@
         sDefaults.putString(KEY_CARRIER_CONFIG_VERSION_STRING, "");
         sDefaults.putBoolean(KEY_ALLOW_HOLD_IN_IMS_CALL_BOOL, true);
         sDefaults.putBoolean(KEY_CARRIER_ALLOW_DEFLECT_IMS_CALL_BOOL, false);
+        sDefaults.putBoolean(KEY_CARRIER_ALLOW_TRANSFER_IMS_CALL_BOOL, false);
         sDefaults.putBoolean(KEY_ALWAYS_PLAY_REMOTE_HOLD_TONE_BOOL, false);
         sDefaults.putBoolean(KEY_AUTO_RETRY_FAILED_WIFI_EMERGENCY_CALL, false);
         sDefaults.putBoolean(KEY_ADDITIONAL_CALL_SETTING_BOOL, true);
@@ -3801,7 +3854,7 @@
         sDefaults.putBoolean(KEY_DROP_VIDEO_CALL_WHEN_ANSWERING_AUDIO_CALL_BOOL, false);
         sDefaults.putBoolean(KEY_ALLOW_MERGE_WIFI_CALLS_WHEN_VOWIFI_OFF_BOOL, true);
         sDefaults.putBoolean(KEY_ALLOW_ADD_CALL_DURING_VIDEO_CALL_BOOL, true);
-        sDefaults.putBoolean(KEY_ALLOW_HOLDING_VIDEO_CALL_BOOL, true);
+        sDefaults.putBoolean(KEY_ALLOW_HOLD_VIDEO_CALL_BOOL, true);
         sDefaults.putBoolean(KEY_WIFI_CALLS_CAN_BE_HD_AUDIO, true);
         sDefaults.putBoolean(KEY_VIDEO_CALLS_CAN_BE_HD_AUDIO, true);
         sDefaults.putBoolean(KEY_GSM_CDMA_CALLS_CAN_BE_HD_AUDIO, false);
@@ -3917,6 +3970,13 @@
                 });
         sDefaults.putInt(KEY_PARAMETERS_USE_FOR_5G_NR_SIGNAL_BAR_INT,
                 CellSignalStrengthNr.USE_SSRSRP);
+        sDefaults.putStringArray(KEY_BANDWIDTH_STRING_ARRAY, new String[]{
+                "GPRS:24,24", "EDGE:70,18", "UMTS:115,115", "CDMA-IS95A:14,14", "CDMA-IS95B:14,14",
+                "1xRTT:30,30", "EvDo-rev.0:750,48", "EvDo-rev.A:950,550", "HSDPA:4300,620",
+                "HSUPA:4300,1800", "HSPA:4300,1800", "EvDo-rev.B:1500,550:", "eHRPD:750,48",
+                "HSPAP:13000,3400", "TD-SCDMA:115,115", "LTE:30000,15000", "NR_NSA:47000,15000",
+                "NR_NSA_MMWAVE:145000,15000", "NR_SA:145000,15000"});
+        sDefaults.putBoolean(KEY_BANDWIDTH_NR_NSA_USE_LTE_VALUE_FOR_UPSTREAM_BOOL, false);
         sDefaults.putString(KEY_WCDMA_DEFAULT_SIGNAL_STRENGTH_MEASUREMENT_STRING, "rssi");
         sDefaults.putBoolean(KEY_CONFIG_SHOW_ORIG_DIAL_STRING_FOR_CDMA_BOOL, false);
         sDefaults.putBoolean(KEY_SHOW_CALL_BLOCKING_DISABLED_NOTIFICATION_ALWAYS_BOOL, false);
@@ -3932,6 +3992,11 @@
         sDefaults.putString(KEY_5G_ICON_CONFIGURATION_STRING,
                 "connected_mmwave:5G,connected:5G");
         sDefaults.putInt(KEY_5G_ICON_DISPLAY_GRACE_PERIOD_SEC_INT, 0);
+        /* Default value is 1 hour. */
+        sDefaults.putLong(KEY_5G_WATCHDOG_TIME_MS_LONG, 3600000);
+        sDefaults.putBoolean(KEY_UNMETERED_NR_NSA_BOOL, false);
+        sDefaults.putBoolean(KEY_UNMETERED_NR_NSA_MMWAVE_BOOL, false);
+        sDefaults.putBoolean(KEY_UNMETERED_NR_NSA_SUB6_BOOL, false);
         sDefaults.putBoolean(KEY_ASCII_7_BIT_SUPPORT_FOR_LONG_MESSAGE_BOOL, false);
         /* Default value is minimum RSRP level needed for SIGNAL_STRENGTH_GOOD */
         sDefaults.putInt(KEY_OPPORTUNISTIC_NETWORK_ENTRY_THRESHOLD_RSRP_INT, -108);
@@ -3950,8 +4015,6 @@
         /* Default value is 3 seconds. */
         sDefaults.putLong(KEY_OPPORTUNISTIC_NETWORK_DATA_SWITCH_EXIT_HYSTERESIS_TIME_LONG, 3000);
         sDefaults.putBoolean(KEY_PING_TEST_BEFORE_DATA_SWITCH_BOOL, true);
-        /* Default value is 1 hour. */
-        sDefaults.putLong(KEY_5G_WATCHDOG_TIME_MS_LONG, 3600000);
         sDefaults.putBoolean(KEY_SWITCH_DATA_TO_PRIMARY_IF_PRIMARY_IS_OOS_BOOL, true);
         /* Default value is 60 seconds. */
         sDefaults.putLong(KEY_OPPORTUNISTIC_NETWORK_PING_PONG_TIME_LONG, 60000);
@@ -3993,7 +4056,7 @@
         sDefaults.putAll(Wifi.getDefaults());
         sDefaults.putBoolean(ENABLE_EAP_METHOD_PREFIX_BOOL, false);
         sDefaults.putBoolean(KEY_SHOW_FORWARDED_NUMBER_BOOL, false);
-        sDefaults.putLong(KEY_DATA_SWITCH_VALIDATION_MIN_GAP_LONG, 0);
+        sDefaults.putLong(KEY_DATA_SWITCH_VALIDATION_MIN_GAP_LONG, TimeUnit.DAYS.toMillis(1));
     }
 
     /**
diff --git a/telephony/java/android/telephony/DataFailCause.java b/telephony/java/android/telephony/DataFailCause.java
index e1c4bef..8b7a243 100644
--- a/telephony/java/android/telephony/DataFailCause.java
+++ b/telephony/java/android/telephony/DataFailCause.java
@@ -30,10 +30,8 @@
 import java.util.Set;
 
 /**
- * Returned as the reason for a data connection failure as defined by modem and some local errors.
- * @hide
+ * DataFailCause collects data connection failure causes code from different sources.
  */
-@SystemApi
 public final class DataFailCause {
     /** There is no failure */
     public static final int NONE = 0;
@@ -841,8 +839,19 @@
     /**
      * Data call bring up fails in the VSNCP phase due to a network rejection of the VSNCP
      * configuration request because the requested APN is unauthorized.
+     *
+     * @deprecated Use {@link #VSNCP_APN_UNAUTHORIZED} instead.
+     *
+     * @hide
      */
-    public static final int VSNCP_APN_UNATHORIZED = 0x8BE;
+    @SystemApi
+    @Deprecated
+    public static final int VSNCP_APN_UNATHORIZED = 0x8BE; // NOTYPO
+    /**
+     * Data call bring up fails in the VSNCP phase due to a network rejection of the VSNCP
+     * configuration request because the requested APN is unauthorized.
+     */
+    public static final int VSNCP_APN_UNAUTHORIZED = 0x8BE;
     /**
      * Data call bring up fails in the VSNCP phase due to a network rejection of the VSNCP
      * configuration request because the PDN limit has been exceeded.
@@ -1318,6 +1327,7 @@
         sFailCauseMap.put(VSNCP_TIMEOUT, "VSNCP_TIMEOUT");
         sFailCauseMap.put(VSNCP_GEN_ERROR, "VSNCP_GEN_ERROR");
         sFailCauseMap.put(VSNCP_APN_UNATHORIZED, "VSNCP_APN_UNATHORIZED");
+        sFailCauseMap.put(VSNCP_APN_UNAUTHORIZED, "VSNCP_APN_UNAUTHORIZED");
         sFailCauseMap.put(VSNCP_PDN_LIMIT_EXCEEDED, "VSNCP_PDN_LIMIT_EXCEEDED");
         sFailCauseMap.put(VSNCP_NO_PDN_GATEWAY_ADDRESS, "VSNCP_NO_PDN_GATEWAY_ADDRESS");
         sFailCauseMap.put(VSNCP_PDN_GATEWAY_UNREACHABLE, "VSNCP_PDN_GATEWAY_UNREACHABLE");
@@ -1423,8 +1433,8 @@
                 if (configManager != null) {
                     PersistableBundle b = configManager.getConfigForSubId(subId);
                     if (b != null) {
-                        String[] permanentFailureStrings = b.getStringArray(CarrierConfigManager.
-                                KEY_CARRIER_DATA_CALL_PERMANENT_FAILURE_STRINGS);
+                        String[] permanentFailureStrings = b.getStringArray(CarrierConfigManager
+                                .KEY_CARRIER_DATA_CALL_PERMANENT_FAILURE_STRINGS);
                         if (permanentFailureStrings != null) {
                             permanentFailureSet = new HashSet<>();
                             for (Map.Entry<Integer, String> e : sFailCauseMap.entrySet()) {
diff --git a/telephony/java/android/telephony/ModemInfo.java b/telephony/java/android/telephony/ModemInfo.java
new file mode 100644
index 0000000..c0833af
--- /dev/null
+++ b/telephony/java/android/telephony/ModemInfo.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
+
+/**
+ * Information of a single logical modem indicating
+ * its id, supported rats and whether it supports voice or data, etc.
+ * @hide
+ */
+public class ModemInfo implements Parcelable {
+    public final int modemId;
+    public final int rat; /* bitset */
+    public final boolean isVoiceSupported;
+    public final boolean isDataSupported;
+
+    // TODO b/121394331: Clean up this class after V1_1.PhoneCapability cleanup.
+    public ModemInfo(int modemId) {
+        this(modemId, 0, true, true);
+    }
+
+    public ModemInfo(int modemId, int rat, boolean isVoiceSupported, boolean isDataSupported) {
+        this.modemId = modemId;
+        this.rat = rat;
+        this.isVoiceSupported = isVoiceSupported;
+        this.isDataSupported = isDataSupported;
+    }
+
+    public ModemInfo(Parcel in) {
+        modemId = in.readInt();
+        rat = in.readInt();
+        isVoiceSupported = in.readBoolean();
+        isDataSupported = in.readBoolean();
+    }
+
+    @Override
+    public String toString() {
+        return "modemId=" + modemId + " rat=" + rat + " isVoiceSupported:" + isVoiceSupported
+                + " isDataSupported:" + isDataSupported;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(modemId, rat, isVoiceSupported, isDataSupported);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (o == null || !(o instanceof ModemInfo) || hashCode() != o.hashCode()) {
+            return false;
+        }
+
+        if (this == o) {
+            return true;
+        }
+
+        ModemInfo s = (ModemInfo) o;
+
+        return (modemId == s.modemId
+                && rat == s.rat
+                && isVoiceSupported == s.isVoiceSupported
+                && isDataSupported == s.isDataSupported);
+    }
+
+    /**
+     * {@link Parcelable#describeContents}
+     */
+    public @ContentsFlags int describeContents() {
+        return 0;
+    }
+
+    /**
+     * {@link Parcelable#writeToParcel}
+     */
+    public void writeToParcel(Parcel dest, @WriteFlags int flags) {
+        dest.writeInt(modemId);
+        dest.writeInt(rat);
+        dest.writeBoolean(isVoiceSupported);
+        dest.writeBoolean(isDataSupported);
+    }
+
+    public static final @android.annotation.NonNull Parcelable.Creator<ModemInfo> CREATOR = new Parcelable.Creator() {
+        public ModemInfo createFromParcel(Parcel in) {
+            return new ModemInfo(in);
+        }
+
+        public ModemInfo[] newArray(int size) {
+            return new ModemInfo[size];
+        }
+    };
+}
diff --git a/telephony/java/android/telephony/PhoneCapability.java b/telephony/java/android/telephony/PhoneCapability.java
index a537928..6571858 100644
--- a/telephony/java/android/telephony/PhoneCapability.java
+++ b/telephony/java/android/telephony/PhoneCapability.java
@@ -16,20 +16,12 @@
 
 package android.telephony;
 
-import android.annotation.LongDef;
 import android.annotation.NonNull;
-import android.annotation.Nullable;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.telephony.AccessNetworkConstants.AccessNetworkType;
-import android.telephony.AccessNetworkConstants.RadioAccessNetworkType;
-import android.telephony.TelephonyManager.NetworkTypeBitMask;
 
-import com.android.internal.telephony.util.TelephonyUtils;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 import java.util.Objects;
 
@@ -38,365 +30,69 @@
  * are shared between those modems defined by list of modem IDs.
  */
 public final class PhoneCapability implements Parcelable {
-    /** Modem feature indicating 3GPP2 capability. */
-    public static final long MODEM_FEATURE_3GPP2_REG = 1 << 0;
-    /** Modem feature indicating 3GPP capability. */
-    public static final long MODEM_FEATURE_3GPP_REG = 1 << 1;
-    /** Modem feature indicating CDMA 2000 with EHRPD capability. */
-    public static final long MODEM_FEATURE_CDMA2000_EHRPD_REG = 1 << 2;
-    /** Modem feature indicating GSM capability. */
-    public static final long MODEM_FEATURE_GERAN_REG = 1 << 3;
-    /** Modem feature indicating UMTS capability. */
-    public static final long MODEM_FEATURE_UTRAN_REG = 1 << 4;
-    /** Modem feature indicating LTE capability. */
-    public static final long MODEM_FEATURE_EUTRAN_REG = 1 << 5;
-    /** Modem feature indicating 5G capability.*/
-    public static final long MODEM_FEATURE_NGRAN_REG = 1 << 6;
-    /** Modem feature indicating EN-DC capability. */
-    public static final long MODEM_FEATURE_EUTRA_NR_DUAL_CONNECTIVITY_REG = 1 << 7;
-    /** Modem feature indicating VoLTE capability (IMS registered). */
-    public static final long MODEM_FEATURE_PS_VOICE_REG = 1 << 8;
-    /** Modem feature indicating CS voice call capability. */
-    public static final long MODEM_FEATURE_CS_VOICE_SESSION = 1 << 9;
-    /** Modem feature indicating Internet connection capability. */
-    public static final long MODEM_FEATURE_INTERACTIVE_DATA_SESSION = 1 << 10;
-    /**
-     * Modem feature indicating dedicated bearer capability.
-     * For services that require a high level QoS (eg. VoLTE), the network can create
-     * a dedicated bearer with the required QoS on top of an established default bearer.
-     * This will provide a dedicated tunnel for one or more specific traffic types.
-     */
-    public static final long MODEM_FEATURE_DEDICATED_BEARER = 1 << 11;
-    /** Modem feature indicating network scan capability. */
-    public static final long MODEM_FEATURE_NETWORK_SCAN = 1 << 12;
-    /** Modem feature indicating corresponding SIM has CDMA capability. */
-    public static final long MODEM_FEATURE_CSIM = 1 << 13;
-
+    // Hardcoded default DSDS capability.
     /** @hide */
-    @LongDef(flag = true, prefix = {"MODEM_FEATURE_" }, value = {
-            MODEM_FEATURE_3GPP2_REG,
-            MODEM_FEATURE_3GPP_REG,
-            MODEM_FEATURE_CDMA2000_EHRPD_REG,
-            MODEM_FEATURE_GERAN_REG,
-            MODEM_FEATURE_UTRAN_REG,
-            MODEM_FEATURE_EUTRAN_REG,
-            MODEM_FEATURE_NGRAN_REG,
-            MODEM_FEATURE_EUTRA_NR_DUAL_CONNECTIVITY_REG,
-            MODEM_FEATURE_PS_VOICE_REG,
-            MODEM_FEATURE_CS_VOICE_SESSION,
-            MODEM_FEATURE_INTERACTIVE_DATA_SESSION,
-            MODEM_FEATURE_DEDICATED_BEARER,
-            MODEM_FEATURE_NETWORK_SCAN,
-            MODEM_FEATURE_CSIM,
-    })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface ModemFeature {
-    }
-
-    /**
-     * Hardcoded default DSDS capability.
-     * @hide
-     */
     public static final PhoneCapability DEFAULT_DSDS_CAPABILITY;
-    /**
-     * Hardcoded default Single SIM single standby capability.
-     * @hide
-     */
+    // Hardcoded default Single SIM single standby capability.
+    /** @hide */
     public static final PhoneCapability DEFAULT_SSSS_CAPABILITY;
 
     static {
-        List<List<Long>> capabilities = new ArrayList<>();
-        List<Long> modem1 = new ArrayList<>();
-        List<Long> modem2 = new ArrayList<>();
-        modem1.add(MODEM_FEATURE_GERAN_REG | MODEM_FEATURE_UTRAN_REG | MODEM_FEATURE_EUTRAN_REG
-                | MODEM_FEATURE_PS_VOICE_REG | MODEM_FEATURE_CS_VOICE_SESSION
-                | MODEM_FEATURE_INTERACTIVE_DATA_SESSION | MODEM_FEATURE_DEDICATED_BEARER);
-        modem2.add(MODEM_FEATURE_GERAN_REG | MODEM_FEATURE_UTRAN_REG | MODEM_FEATURE_EUTRAN_REG
-                | MODEM_FEATURE_PS_VOICE_REG | MODEM_FEATURE_INTERACTIVE_DATA_SESSION
-                | MODEM_FEATURE_DEDICATED_BEARER);
-        capabilities.add(modem1);
-        capabilities.add(modem2);
-        List<String> uuids = new ArrayList<>();
-        uuids.add("com.xxxx.lm0");
-        uuids.add("com.xxxx.lm1");
-        long rats = TelephonyManager.NETWORK_TYPE_BITMASK_GSM
-                | TelephonyManager.NETWORK_TYPE_BITMASK_GPRS
-                | TelephonyManager.NETWORK_TYPE_BITMASK_EDGE
-                | TelephonyManager.NETWORK_TYPE_BITMASK_UMTS
-                | TelephonyManager.NETWORK_TYPE_BITMASK_LTE;
-        DEFAULT_DSDS_CAPABILITY = new PhoneCapability(0, 0, 0, 0, 0, rats, null, null, null, null,
-                uuids, null, capabilities);
+        ModemInfo modemInfo1 = new ModemInfo(0, 0, true, true);
+        ModemInfo modemInfo2 = new ModemInfo(1, 0, true, true);
 
-        capabilities = new ArrayList<>();
-        capabilities.add(modem1);
-        uuids = new ArrayList<>();
-        uuids.add("com.xxxx.lm0");
-        DEFAULT_SSSS_CAPABILITY = new PhoneCapability(0, 0, 0, 0, 0, rats, null, null, null, null,
-                uuids, null, capabilities);
+        List<ModemInfo> logicalModemList = new ArrayList<>();
+        logicalModemList.add(modemInfo1);
+        logicalModemList.add(modemInfo2);
+        DEFAULT_DSDS_CAPABILITY = new PhoneCapability(1, 1, 0, logicalModemList, false);
+
+        logicalModemList = new ArrayList<>();
+        logicalModemList.add(modemInfo1);
+        DEFAULT_SSSS_CAPABILITY = new PhoneCapability(1, 1, 0, logicalModemList, false);
     }
 
-    private final int mUtranUeCategoryDl;
-    private final int mUtranUeCategoryUl;
-    private final int mEutranUeCategoryDl;
-    private final int mEutranUeCategoryUl;
-    private final long mPsDataConnectionLingerTimeMillis;
-    private final @NetworkTypeBitMask long mSupportedRats;
-    private final List<Integer> mGeranBands;
-    private final List<Integer> mUtranBands;
-    private final List<Integer> mEutranBands;
-    private final List<Integer> mNgranBands;
-    private final List<String> mLogicalModemUuids;
-    private final List<SimSlotCapability> mSimSlotCapabilities;
-    private final @ModemFeature List<List<Long>> mConcurrentFeaturesSupport;
+    /** @hide */
+    public final int maxActiveVoiceCalls;
+    /** @hide */
+    public final int maxActiveData;
+    /** @hide */
+    public final int max5G;
+    /** @hide */
+    public final boolean validationBeforeSwitchSupported;
+    /** @hide */
+    public final List<ModemInfo> logicalModemList;
 
-    /**
-     * Default constructor to create a PhoneCapability object.
-     * @param utranUeCategoryDl 3GPP UE category for UTRAN downlink.
-     * @param utranUeCategoryUl 3GPP UE category for UTRAN uplink.
-     * @param eutranUeCategoryDl 3GPP UE category for EUTRAN downlink.
-     * @param eutranUeCategoryUl 3GPP UE category for EUTRAN uplink.
-     * @param psDataConnectionLingerTimeMillis length of the grace period to allow a smooth
-     *                                         "handover" between data connections.
-     * @param supportedRats all radio access technologies this phone is capable of supporting.
-     * @param geranBands list of supported {@link AccessNetworkConstants.GeranBand}.
-     * @param utranBands list of supported {@link AccessNetworkConstants.UtranBand}.
-     * @param eutranBands list of supported {@link AccessNetworkConstants.EutranBand}.
-     * @param ngranBands list of supported {@link AccessNetworkConstants.NgranBands}.
-     * @param logicalModemUuids list of logical modem UUIDs, typically of the form
-     *                          "com.xxxx.lmX", where X is the logical modem ID.
-     * @param simSlotCapabilities list of {@link SimSlotCapability} for the device
-     * @param concurrentFeaturesSupport list of list of concurrently supportable modem feature sets.
-     * @hide
-     */
-    public PhoneCapability(int utranUeCategoryDl, int utranUeCategoryUl, int eutranUeCategoryDl,
-            int eutranUeCategoryUl, long psDataConnectionLingerTimeMillis,
-            @NetworkTypeBitMask long supportedRats, @Nullable List<Integer> geranBands,
-            @Nullable List<Integer> utranBands, @Nullable List<Integer> eutranBands,
-            @Nullable List<Integer> ngranBands, @Nullable List<String> logicalModemUuids,
-            @Nullable List<SimSlotCapability> simSlotCapabilities,
-            @Nullable @ModemFeature List<List<Long>> concurrentFeaturesSupport) {
-        this.mUtranUeCategoryDl = utranUeCategoryDl;
-        this.mUtranUeCategoryUl = utranUeCategoryUl;
-        this.mEutranUeCategoryDl = eutranUeCategoryDl;
-        this.mEutranUeCategoryUl = eutranUeCategoryUl;
-        this.mPsDataConnectionLingerTimeMillis = psDataConnectionLingerTimeMillis;
-        this.mSupportedRats = supportedRats;
-        this.mGeranBands = TelephonyUtils.emptyIfNull(geranBands);
-        this.mUtranBands = TelephonyUtils.emptyIfNull(utranBands);
-        this.mEutranBands = TelephonyUtils.emptyIfNull(eutranBands);
-        this.mNgranBands = TelephonyUtils.emptyIfNull(ngranBands);
-        this.mLogicalModemUuids = TelephonyUtils.emptyIfNull(logicalModemUuids);
-        this.mSimSlotCapabilities = TelephonyUtils.emptyIfNull(simSlotCapabilities);
-        this.mConcurrentFeaturesSupport = TelephonyUtils.emptyIfNull(concurrentFeaturesSupport);
-    }
-
-    private PhoneCapability(Parcel in) {
-        mUtranUeCategoryDl = in.readInt();
-        mUtranUeCategoryUl = in.readInt();
-        mEutranUeCategoryDl = in.readInt();
-        mEutranUeCategoryUl = in.readInt();
-        mPsDataConnectionLingerTimeMillis = in.readLong();
-        mSupportedRats = in.readLong();
-        mGeranBands = new ArrayList<>();
-        in.readList(mGeranBands, Integer.class.getClassLoader());
-        mUtranBands = new ArrayList<>();
-        in.readList(mUtranBands, Integer.class.getClassLoader());
-        mEutranBands = new ArrayList<>();
-        in.readList(mEutranBands, Integer.class.getClassLoader());
-        mNgranBands = new ArrayList<>();
-        in.readList(mNgranBands, Integer.class.getClassLoader());
-        mLogicalModemUuids = in.createStringArrayList();
-        mSimSlotCapabilities = in.createTypedArrayList(SimSlotCapability.CREATOR);
-        int length = in.readInt();
-        mConcurrentFeaturesSupport = new ArrayList<>();
-        for (int i = 0; i < length; i++) {
-            ArrayList<Long> feature = new ArrayList<>();
-            in.readList(feature, Long.class.getClassLoader());
-            mConcurrentFeaturesSupport.add(feature);
-        }
-    }
-
-    /**
-     * 3GPP UE category for a given Radio Access Network and direction.
-     *
-     * References are:
-     * TS 25.306 Table 4.1a     EUTRAN downlink
-     * TS 25.306 Table 5.1a-2   EUTRAN uplink
-     * TS 25.306 Table 5.1a     UTRAN downlink
-     * TS 25.306 Table 5.1g     UTRAN uplink
-     *
-     * @param uplink true for uplink direction and false for downlink direction.
-     * @param accessNetworkType accessNetworkType, defined in {@link AccessNetworkType}.
-     * @return the UE category, or -1 if it is not supported.
-     */
-    public int getUeCategory(boolean uplink, @RadioAccessNetworkType int accessNetworkType) {
-        if (uplink) {
-            switch (accessNetworkType) {
-                case AccessNetworkType.UTRAN: return mUtranUeCategoryUl;
-                case AccessNetworkType.EUTRAN: return mEutranUeCategoryUl;
-                default: return -1;
-            }
-        } else {
-            switch (accessNetworkType) {
-                case AccessNetworkType.UTRAN: return mUtranUeCategoryDl;
-                case AccessNetworkType.EUTRAN: return mEutranUeCategoryDl;
-                default: return -1;
-            }
-        }
-    }
-
-    /**
-     * In cellular devices that support a greater number of logical modems than
-     * Internet connections, some devices support a grace period to allow a smooth "handover"
-     * between those connections. If that feature is supported, then this API will provide
-     * the length of that grace period in milliseconds. If it is not supported, the default value
-     * for the grace period is 0.
-     * @return handover linger time in milliseconds, or 0 if it is not supported.
-     */
-    public long getPsDataConnectionLingerTimeMillis() {
-        return mPsDataConnectionLingerTimeMillis;
-    }
-
-    /**
-     * The radio access technologies this device is capable of supporting.
-     * @return a bitfield of all supported network types, defined in {@link TelephonyManager}
-     */
-    public @NetworkTypeBitMask long getSupportedRats() {
-        return mSupportedRats;
-    }
-
-    /**
-     * List of supported cellular bands for the given accessNetworkType.
-     * @param accessNetworkType accessNetworkType, defined in {@link AccessNetworkType}.
-     * @return a list of bands, or an empty list if the access network type is unsupported.
-     */
-    public @NonNull List<Integer> getBands(@RadioAccessNetworkType int accessNetworkType) {
-        switch (accessNetworkType) {
-            case AccessNetworkType.GERAN: return mGeranBands;
-            case AccessNetworkType.UTRAN: return mUtranBands;
-            case AccessNetworkType.EUTRAN: return mEutranBands;
-            case AccessNetworkType.NGRAN: return mNgranBands;
-            default: return new ArrayList<>();
-        }
-    }
-
-    /**
-     * List of logical modem UUIDs, each typically "com.xxxx.lmX", where X is the logical modem ID.
-     * @return a list of modem UUIDs, one for every logical modem the device has.
-     */
-    public @NonNull List<String> getLogicalModemUuids() {
-        return mLogicalModemUuids;
-    }
-
-    /**
-     * List of {@link SimSlotCapability} for the device. The order of SIMs corresponds to the
-     * order of modems in {@link #getLogicalModemUuids}.
-     * @return a list of SIM slot capabilities, one for every SIM slot the device has.
-     */
-    public @NonNull List<SimSlotCapability> getSimSlotCapabilities() {
-        return mSimSlotCapabilities;
-    }
-
-    /**
-     * A List of Lists of concurrently supportable modem feature sets.
-     *
-     * Each entry in the top-level list is an independent configuration across all modems
-     * that describes the capabilities of the device as a whole.
-     *
-     * Each entry in the second-level list is a bitfield of ModemFeatures that describes
-     * the capabilities for a single modem. In the second-level list, the order of the modems
-     * corresponds to order of the UUIDs in {@link #getLogicalModemUuids}.
-     *
-     * For symmetric capabilities that can only be active on one modem at a time, there will be
-     * multiple configurations (equal to the number of modems) that shows it active on each modem.
-     * For asymmetric capabilities that are only available on one of the modems, all configurations
-     * will have that capability on just that one modem.
-     *
-     * The example below shows the concurrentFeaturesSupport for a 3-modem device with
-     * theoretical capabilities SYMMETRIC (available on all modems, but only one at a time) and
-     * ASYMMETRIC (only available on the first modem):
-     * {
-     *      Configuration 1: ASYMMETRIC and SYMMETRIC on modem 1, modem 2 empty, modem 3 empty
-     *      {(ASYMMETRIC | SYMMETRIC), (), ()},
-     *
-     *      Configuration 2: ASYMMETRIC on modem 1, SYMMETRIC on modem 2, modem 3 empty
-     *      {(ASYMMETRIC), (SYMMETRIC), ()},
-     *
-     *      Configuration 3: ASYMMETRIC on modem 1, modem 2 empty, SYMMETRIC on modem 3
-     *      {(ASYMMETRIC), (), (SYMMETRIC)}
-     * }
-     *
-     * @return List of all concurrently supportable modem features.
-     */
-    public @NonNull @ModemFeature List<List<Long>> getConcurrentFeaturesSupport() {
-        return mConcurrentFeaturesSupport;
-    }
-
-    /**
-     * How many modems can simultaneously have PS attached.
-     * @return maximum number of active PS voice connections.
-     */
-    public int getMaxActivePsVoice() {
-        return countFeature(MODEM_FEATURE_PS_VOICE_REG);
-    }
-
-    /**
-     * How many modems can simultaneously support active data connections.
-     * For DSDS, this will be 1, and for DSDA this will be 2.
-     * @return maximum number of active Internet data sessions.
-     */
-    public int getMaxActiveInternetData() {
-        return countFeature(MODEM_FEATURE_INTERACTIVE_DATA_SESSION);
-    }
-
-    /**
-     * How many modems can simultaneously have dedicated bearer capability.
-     * @return maximum number of active dedicated bearers.
-     */
-    public int getMaxActiveDedicatedBearers() {
-        return countFeature(MODEM_FEATURE_DEDICATED_BEARER);
-    }
-
-    /**
-     * Whether the CBRS band 48 is supported or not.
-     * @return true if any RadioAccessNetwork supports CBRS and false if none do.
-     * @hide
-     */
-    public boolean isCbrsSupported() {
-        return mEutranBands.contains(AccessNetworkConstants.EutranBand.BAND_48)
-                || mNgranBands.contains(AccessNetworkConstants.NgranBands.BAND_48);
-    }
-
-    private int countFeature(@ModemFeature long feature) {
-        int count = 0;
-        for (long featureSet : mConcurrentFeaturesSupport.get(0)) {
-            if ((featureSet & feature) != 0) {
-                count++;
-            }
-        }
-        return count;
+    /** @hide */
+    public PhoneCapability(int maxActiveVoiceCalls, int maxActiveData, int max5G,
+            List<ModemInfo> logicalModemList, boolean validationBeforeSwitchSupported) {
+        this.maxActiveVoiceCalls = maxActiveVoiceCalls;
+        this.maxActiveData = maxActiveData;
+        this.max5G = max5G;
+        // Make sure it's not null.
+        this.logicalModemList = logicalModemList == null ? new ArrayList<>() : logicalModemList;
+        this.validationBeforeSwitchSupported = validationBeforeSwitchSupported;
     }
 
     @Override
     public String toString() {
-        return "utranUeCategoryDl=" + mUtranUeCategoryDl
-                + " utranUeCategoryUl=" + mUtranUeCategoryUl
-                + " eutranUeCategoryDl=" + mEutranUeCategoryDl
-                + " eutranUeCategoryUl=" + mEutranUeCategoryUl
-                + " psDataConnectionLingerTimeMillis=" + mPsDataConnectionLingerTimeMillis
-                + " supportedRats=" + mSupportedRats + " geranBands=" + mGeranBands
-                + " utranBands=" + mUtranBands + " eutranBands=" + mEutranBands
-                + " ngranBands=" + mNgranBands + " logicalModemUuids=" + mLogicalModemUuids
-                + " simSlotCapabilities=" + mSimSlotCapabilities
-                + " concurrentFeaturesSupport=" + mConcurrentFeaturesSupport;
+        return "maxActiveVoiceCalls=" + maxActiveVoiceCalls + " maxActiveData=" + maxActiveData
+                + " max5G=" + max5G + "logicalModemList:"
+                + Arrays.toString(logicalModemList.toArray());
+    }
+
+    private PhoneCapability(Parcel in) {
+        maxActiveVoiceCalls = in.readInt();
+        maxActiveData = in.readInt();
+        max5G = in.readInt();
+        validationBeforeSwitchSupported = in.readBoolean();
+        logicalModemList = new ArrayList<>();
+        in.readList(logicalModemList, ModemInfo.class.getClassLoader());
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(mUtranUeCategoryDl, mUtranUeCategoryUl, mEutranUeCategoryDl,
-                mEutranUeCategoryUl, mPsDataConnectionLingerTimeMillis, mSupportedRats, mGeranBands,
-                mUtranBands, mEutranBands, mNgranBands, mLogicalModemUuids, mSimSlotCapabilities,
-                mConcurrentFeaturesSupport);
+        return Objects.hash(maxActiveVoiceCalls, maxActiveData, max5G, logicalModemList,
+                validationBeforeSwitchSupported);
     }
 
     @Override
@@ -411,19 +107,11 @@
 
         PhoneCapability s = (PhoneCapability) o;
 
-        return (mUtranUeCategoryDl == s.mUtranUeCategoryDl
-                && mUtranUeCategoryUl == s.mUtranUeCategoryUl
-                && mEutranUeCategoryDl == s.mEutranUeCategoryDl
-                && mEutranUeCategoryUl == s.mEutranUeCategoryUl
-                && mPsDataConnectionLingerTimeMillis == s.mPsDataConnectionLingerTimeMillis
-                && mSupportedRats == s.mSupportedRats
-                && mGeranBands.equals(s.mGeranBands)
-                && mUtranBands.equals(s.mUtranBands)
-                && mEutranBands.equals(s.mEutranBands)
-                && mNgranBands.equals(s.mNgranBands)
-                && mLogicalModemUuids.equals(s.mLogicalModemUuids)
-                && mSimSlotCapabilities.equals(s.mSimSlotCapabilities)
-                && mConcurrentFeaturesSupport.equals(s.mConcurrentFeaturesSupport));
+        return (maxActiveVoiceCalls == s.maxActiveVoiceCalls
+                && maxActiveData == s.maxActiveData
+                && max5G == s.max5G
+                && validationBeforeSwitchSupported == s.validationBeforeSwitchSupported
+                && logicalModemList.equals(s.logicalModemList));
     }
 
     /**
@@ -436,33 +124,21 @@
     /**
      * {@link Parcelable#writeToParcel}
      */
-    public void writeToParcel(@NonNull Parcel dest, int flags) {
-        dest.writeInt(mUtranUeCategoryDl);
-        dest.writeInt(mUtranUeCategoryUl);
-        dest.writeInt(mEutranUeCategoryDl);
-        dest.writeInt(mEutranUeCategoryUl);
-        dest.writeLong(mPsDataConnectionLingerTimeMillis);
-        dest.writeLong(mSupportedRats);
-        dest.writeList(mGeranBands);
-        dest.writeList(mUtranBands);
-        dest.writeList(mEutranBands);
-        dest.writeList(mNgranBands);
-        dest.writeStringList(mLogicalModemUuids);
-        dest.writeTypedList(mSimSlotCapabilities);
-        dest.writeInt(mConcurrentFeaturesSupport.size());
-        for (List<Long> feature : mConcurrentFeaturesSupport) {
-            dest.writeList(feature);
-        }
+    public void writeToParcel(@NonNull Parcel dest, @Parcelable.WriteFlags int flags) {
+        dest.writeInt(maxActiveVoiceCalls);
+        dest.writeInt(maxActiveData);
+        dest.writeInt(max5G);
+        dest.writeBoolean(validationBeforeSwitchSupported);
+        dest.writeList(logicalModemList);
     }
 
-    public static final @NonNull Parcelable.Creator<PhoneCapability> CREATOR =
-            new Parcelable.Creator() {
-                public PhoneCapability createFromParcel(Parcel in) {
-                    return new PhoneCapability(in);
-                }
+    public static final @android.annotation.NonNull Parcelable.Creator<PhoneCapability> CREATOR = new Parcelable.Creator() {
+        public PhoneCapability createFromParcel(Parcel in) {
+            return new PhoneCapability(in);
+        }
 
-                public PhoneCapability[] newArray(int size) {
-                    return new PhoneCapability[size];
-                }
-            };
+        public PhoneCapability[] newArray(int size) {
+            return new PhoneCapability[size];
+        }
+    };
 }
diff --git a/telephony/java/android/telephony/PreciseDataConnectionState.java b/telephony/java/android/telephony/PreciseDataConnectionState.java
index 708adeb..e37a9b9 100644
--- a/telephony/java/android/telephony/PreciseDataConnectionState.java
+++ b/telephony/java/android/telephony/PreciseDataConnectionState.java
@@ -257,8 +257,7 @@
      * Return the cause code for the most recent change in {@link #getState}. In the event of an
      * error, this cause code will be non-zero.
      */
-    // FIXME(b144774287): some of these cause codes should have a prescribed meaning.
-    public int getLastCauseCode() {
+    public @DataFailureCause int getLastCauseCode() {
         return mFailCause;
     }
 
diff --git a/telephony/java/android/telephony/SimSlotCapability.java b/telephony/java/android/telephony/SimSlotCapability.java
deleted file mode 100644
index b4fef46..0000000
--- a/telephony/java/android/telephony/SimSlotCapability.java
+++ /dev/null
@@ -1,130 +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.telephony;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.Objects;
-
-/**
- * Capabilities for a SIM Slot.
- */
-public final class SimSlotCapability implements Parcelable {
-    /** Slot type for UICC (removable SIM). */
-    public static final int SLOT_TYPE_UICC = 1;
-    /** Slot type for iUICC/iSIM (integrated SIM). */
-    public static final int SLOT_TYPE_IUICC = 2;
-    /** Slot type for eUICC/eSIM (embedded SIM). */
-    public static final int SLOT_TYPE_EUICC = 3;
-    /** Slot type for soft SIM (no physical SIM). */
-    public static final int SLOT_TYPE_SOFT_SIM = 4;
-
-    /** @hide */
-    @IntDef(prefix = {"SLOT_TYPE_" }, value = {
-            SLOT_TYPE_UICC,
-            SLOT_TYPE_IUICC,
-            SLOT_TYPE_EUICC,
-            SLOT_TYPE_SOFT_SIM,
-    })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface SlotType {
-    }
-
-    private final int mPhysicalSlotIndex;
-    private final int mSlotType;
-
-    /** @hide */
-    public SimSlotCapability(int physicalSlotId, int slotType) {
-        this.mPhysicalSlotIndex = physicalSlotId;
-        this.mSlotType = slotType;
-    }
-
-    private SimSlotCapability(Parcel in) {
-        mPhysicalSlotIndex = in.readInt();
-        mSlotType = in.readInt();
-    }
-
-    /**
-     * @return physical SIM slot index
-     */
-    public int getPhysicalSlotIndex() {
-        return mPhysicalSlotIndex;
-    }
-
-    /**
-     * @return type of SIM {@link SlotType}
-     */
-    public @SlotType int getSlotType() {
-        return mSlotType;
-    }
-
-    @Override
-    public String toString() {
-        return "mPhysicalSlotIndex=" + mPhysicalSlotIndex + " slotType=" + mSlotType;
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(mPhysicalSlotIndex, mSlotType);
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (o == null || !(o instanceof SimSlotCapability) || hashCode() != o.hashCode()) {
-            return false;
-        }
-
-        if (this == o) {
-            return true;
-        }
-
-        SimSlotCapability s = (SimSlotCapability) o;
-
-        return (mPhysicalSlotIndex == s.mPhysicalSlotIndex && mSlotType == s.mSlotType);
-    }
-
-    /**
-     * {@link Parcelable#describeContents}
-     */
-    public int describeContents() {
-        return 0;
-    }
-
-    /**
-     * {@link Parcelable#writeToParcel}
-     */
-    public void writeToParcel(@NonNull Parcel dest, int flags) {
-        dest.writeInt(mPhysicalSlotIndex);
-        dest.writeInt(mSlotType);
-    }
-
-    public static final @NonNull Parcelable.Creator<SimSlotCapability> CREATOR =
-            new Parcelable.Creator() {
-                public SimSlotCapability createFromParcel(Parcel in) {
-                    return new SimSlotCapability(in);
-                }
-
-                public SimSlotCapability[] newArray(int size) {
-                    return new SimSlotCapability[size];
-                }
-            };
-}
diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java
index 6c920f1..8479db6 100644
--- a/telephony/java/android/telephony/SmsManager.java
+++ b/telephony/java/android/telephony/SmsManager.java
@@ -2094,8 +2094,12 @@
 
     /**
      * Gets the total capacity of SMS storage on RUIM and SIM cards
+     * <p>
+     * This is the number of 176 byte EF-SMS records which can be stored on the RUIM or SIM card.
+     * <p>
+     * See 3GPP TS 31.102 - 4.2.25 - EF-SMS for more information
      *
-     * @return the total capacity count of SMS on RUIM and SIM cards
+     * @return the total number of SMS records which can be stored on the RUIM or SIM cards.
      * @hide
      */
     @SystemApi
diff --git a/telephony/java/android/telephony/SubscriptionInfo.java b/telephony/java/android/telephony/SubscriptionInfo.java
index 832771d..336aa0e 100644
--- a/telephony/java/android/telephony/SubscriptionInfo.java
+++ b/telephony/java/android/telephony/SubscriptionInfo.java
@@ -217,6 +217,20 @@
     private boolean mAreUiccApplicationsEnabled = true;
 
     /**
+     * Public copy constructor.
+     * @hide
+     */
+    public SubscriptionInfo(SubscriptionInfo info) {
+        this(info.mId, info.mIccId, info.mSimSlotIndex, info.mDisplayName, info.mCarrierName,
+                info.mNameSource, info.mIconTint, info.mNumber, info.mDataRoaming, info.mIconBitmap,
+                info.mMcc, info.mMnc, info.mCountryIso, info.mIsEmbedded, info.mNativeAccessRules,
+                info.mCardString, info.mCardId, info.mIsOpportunistic,
+                info.mGroupUUID == null ? null : info.mGroupUUID.toString(), info.mIsGroupDisabled,
+                info.mCarrierId, info.mProfileClass, info.mSubscriptionType, info.mGroupOwner,
+                info.mCarrierConfigAccessRules, info.mAreUiccApplicationsEnabled);
+    }
+
+    /**
      * @hide
      */
     public SubscriptionInfo(int id, String iccId, int simSlotIndex, CharSequence displayName,
@@ -291,13 +305,27 @@
     }
 
     /**
-     * @return the ICC ID.
+     * Returns the ICC ID if the calling app has been granted the READ_PRIVILEGED_PHONE_STATE
+     * permission, has carrier privileges (see {@link TelephonyManager#hasCarrierPrivileges}), or
+     * is a device owner or profile owner that has been granted the READ_PHONE_STATE permission.
+     * The profile owner is an app that owns a managed profile on the device; for more details see
+     * <a href="https://developer.android.com/work/managed-profiles">Work profiles</a>. Profile
+     * owner access is deprecated and will be removed in a future release.
+     *
+     * @return the ICC ID, or an empty string if one of these requirements is not met
      */
     public String getIccId() {
         return this.mIccId;
     }
 
     /**
+     * @hide
+     */
+    public void clearIccId() {
+        this.mIccId = "";
+    }
+
+    /**
      * @return the slot index of this Subscription's SIM card.
      */
     public int getSimSlotIndex() {
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 68b6683..0660776 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -47,7 +47,6 @@
 import android.content.Intent;
 import android.database.Cursor;
 import android.net.ConnectivityManager;
-import android.net.NetworkStats;
 import android.net.Uri;
 import android.os.AsyncTask;
 import android.os.Binder;
@@ -1877,24 +1876,6 @@
     //
 
     /**
-     * Returns the {@link PhoneCapability} for the device or null if it is not available.
-     * <p>
-     * Requires Permission: READ_PHONE_STATE or that the calling app has
-     * carrier privileges (see {@link #hasCarrierPrivileges}).
-     */
-    @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
-    @Nullable
-    public PhoneCapability getPhoneCapability() {
-        try {
-            ITelephony telephony = getITelephony();
-            return telephony == null ? null :
-                    telephony.getPhoneCapability(getSubId(), getOpPackageName(), getFeatureId());
-        } catch (RemoteException ex) {
-            return null;
-        }
-    }
-
-    /**
      * Returns the software version number for the device, for example,
      * the IMEI/SV for GSM phones. Return null if the software version is
      * not available.
@@ -6180,9 +6161,11 @@
      * @param AID Application id. See ETSI 102.221 and 101.220.
      * @param p2 P2 parameter (described in ISO 7816-4).
      * @return an IccOpenLogicalChannelResponse object.
-     * @deprecated Use {@link android.se.omapi.SEService} APIs instead.
+     * @deprecated Use {@link android.se.omapi.SEService} APIs instead. See
+     *             {@link android.se.omapi.SEService#getUiccReader(int)},
+     *             {@link android.se.omapi.Reader#openSession()},
+     *             {@link android.se.omapi.Session#openLogicalChannel(byte[], byte)}.
      */
-    // TODO(b/147153909): Update Javadoc to link to specific SEService API once integrated.
     @Deprecated
     public IccOpenLogicalChannelResponse iccOpenLogicalChannel(String AID, int p2) {
         return iccOpenLogicalChannel(getSubId(), AID, p2);
@@ -6214,9 +6197,11 @@
      * @param p2 P2 parameter (described in ISO 7816-4).
      * @return an IccOpenLogicalChannelResponse object.
      * @hide
-     * @deprecated Use {@link android.se.omapi.SEService} APIs instead.
+     * @deprecated Use {@link android.se.omapi.SEService} APIs instead. See
+     *             {@link android.se.omapi.SEService#getUiccReader(int)},
+     *             {@link android.se.omapi.Reader#openSession()},
+     *             {@link android.se.omapi.Session#openLogicalChannel(byte[], byte)}.
      */
-    // TODO(b/147153909): Update Javadoc to link to specific SEService API once integrated.
     @Deprecated
     public IccOpenLogicalChannelResponse iccOpenLogicalChannel(int subId, String AID, int p2) {
         try {
@@ -6245,9 +6230,9 @@
      *            iccOpenLogicalChannel.
      * @return true if the channel was closed successfully.
      * @hide
-     * @deprecated Use {@link android.se.omapi.SEService} APIs instead.
+     * @deprecated Use {@link android.se.omapi.SEService} APIs instead. See
+     *             {@link android.se.omapi.Channel#close()}.
      */
-    // TODO(b/147153909): Update Javadoc to link to specific SEService API once integrated.
     @Deprecated
     @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
     @SystemApi
@@ -6275,9 +6260,9 @@
      * @param channel is the channel id to be closed as returned by a successful
      *            iccOpenLogicalChannel.
      * @return true if the channel was closed successfully.
-     * @deprecated Use {@link android.se.omapi.SEService} APIs instead.
+     * @deprecated Use {@link android.se.omapi.SEService} APIs instead. See
+     *             {@link android.se.omapi.Channel#close()}.
      */
-    // TODO(b/147153909): Update Javadoc to link to specific SEService API once integrated.
     @Deprecated
     public boolean iccCloseLogicalChannel(int channel) {
         return iccCloseLogicalChannel(getSubId(), channel);
@@ -6297,9 +6282,9 @@
      *            iccOpenLogicalChannel.
      * @return true if the channel was closed successfully.
      * @hide
-     * @deprecated Use {@link android.se.omapi.SEService} APIs instead.
+     * @deprecated Use {@link android.se.omapi.SEService} APIs instead. See
+     *             {@link android.se.omapi.Channel#close()}.
      */
-    // TODO(b/147153909): Update Javadoc to link to specific SEService API once integrated.
     @Deprecated
     public boolean iccCloseLogicalChannel(int subId, int channel) {
         try {
@@ -6336,9 +6321,9 @@
      * @return The APDU response from the ICC card with the status appended at the end, or null if
      * there is an issue connecting to the Telephony service.
      * @hide
-     * @deprecated Use {@link android.se.omapi.SEService} APIs instead.
+     * @deprecated Use {@link android.se.omapi.SEService} APIs instead. See
+     *             {@link android.se.omapi.Channel#transmit(byte[])}.
      */
-    // TODO(b/147153909): Update Javadoc to link to specific SEService API once integrated.
     @Deprecated
     @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
     @SystemApi
@@ -6377,9 +6362,9 @@
      * @param data Data to be sent with the APDU.
      * @return The APDU response from the ICC card with the status appended at
      *            the end.
-     * @deprecated Use {@link android.se.omapi.SEService} APIs instead.
+     * @deprecated Use {@link android.se.omapi.SEService} APIs instead. See
+     *             {@link android.se.omapi.Channel#transmit(byte[])}.
      */
-    // TODO(b/147153909): Update Javadoc to link to specific SEService API once integrated.
     @Deprecated
     public String iccTransmitApduLogicalChannel(int channel, int cla,
             int instruction, int p1, int p2, int p3, String data) {
@@ -6409,9 +6394,9 @@
      * @return The APDU response from the ICC card with the status appended at
      *            the end.
      * @hide
-     * @deprecated Use {@link android.se.omapi.SEService} APIs instead.
+     * @deprecated Use {@link android.se.omapi.SEService} APIs instead. See
+     *             {@link android.se.omapi.Channel#transmit(byte[])}.
      */
-    // TODO(b/147153909): Update Javadoc to link to specific SEService API once integrated.
     @Deprecated
     public String iccTransmitApduLogicalChannel(int subId, int channel, int cla,
             int instruction, int p1, int p2, int p3, String data) {
@@ -6448,9 +6433,12 @@
      * @return The APDU response from the ICC card with the status appended at
      *            the end.
      * @hide
-     * @deprecated Use {@link android.se.omapi.SEService} APIs instead.
+     * @deprecated Use {@link android.se.omapi.SEService} APIs instead. See
+     *             {@link android.se.omapi.SEService#getUiccReader(int)},
+     *             {@link android.se.omapi.Reader#openSession()},
+     *             {@link android.se.omapi.Session#openBasicChannel(byte[], byte)},
+     *             {@link android.se.omapi.Channel#transmit(byte[])}.
      */
-    // TODO(b/147153909): Update Javadoc to link to specific SEService API once integrated.
     @Deprecated
     @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
     @SystemApi
@@ -6487,9 +6475,12 @@
      * @param data Data to be sent with the APDU.
      * @return The APDU response from the ICC card with the status appended at
      *            the end.
-     * @deprecated Use {@link android.se.omapi.SEService} APIs instead.
+     * @deprecated Use {@link android.se.omapi.SEService} APIs instead. See
+     *             {@link android.se.omapi.SEService#getUiccReader(int)},
+     *             {@link android.se.omapi.Reader#openSession()},
+     *             {@link android.se.omapi.Session#openBasicChannel(byte[], byte)},
+     *             {@link android.se.omapi.Channel#transmit(byte[])}.
      */
-    // TODO(b/147153909): Update Javadoc to link to specific SEService API once integrated.
     @Deprecated
     public String iccTransmitApduBasicChannel(int cla,
             int instruction, int p1, int p2, int p3, String data) {
@@ -6517,9 +6508,12 @@
      * @return The APDU response from the ICC card with the status appended at
      *            the end.
      * @hide
-     * @deprecated Use {@link android.se.omapi.SEService} APIs instead.
+     * @deprecated Use {@link android.se.omapi.SEService} APIs instead. See
+     *             {@link android.se.omapi.SEService#getUiccReader(int)},
+     *             {@link android.se.omapi.Reader#openSession()},
+     *             {@link android.se.omapi.Session#openBasicChannel(byte[], byte)},
+     *             {@link android.se.omapi.Channel#transmit(byte[])}.
      */
-    // TODO(b/147153909): Update Javadoc to link to specific SEService API once integrated.
     @Deprecated
     public String iccTransmitApduBasicChannel(int subId, int cla,
             int instruction, int p1, int p2, int p3, String data) {
@@ -6548,9 +6542,12 @@
      * @param p3 P3 value of the APDU command.
      * @param filePath
      * @return The APDU response.
-     * @deprecated Use {@link android.se.omapi.SEService} APIs instead.
+     * @deprecated Use {@link android.se.omapi.SEService} APIs instead. See
+     *             {@link android.se.omapi.SEService#getUiccReader(int)},
+     *             {@link android.se.omapi.Reader#openSession()},
+     *             {@link android.se.omapi.Session#openBasicChannel(byte[], byte)},
+     *             {@link android.se.omapi.Channel#transmit(byte[])}.
      */
-    // TODO(b/147153909): Update Javadoc to link to specific SEService API once integrated.
     @Deprecated
     public byte[] iccExchangeSimIO(int fileID, int command, int p1, int p2, int p3,
             String filePath) {
@@ -6573,9 +6570,12 @@
      * @param filePath
      * @return The APDU response.
      * @hide
-     * @deprecated Use {@link android.se.omapi.SEService} APIs instead.
+     * @deprecated Use {@link android.se.omapi.SEService} APIs instead. See
+     *             {@link android.se.omapi.SEService#getUiccReader(int)},
+     *             {@link android.se.omapi.Reader#openSession()},
+     *             {@link android.se.omapi.Session#openBasicChannel(byte[], byte)},
+     *             {@link android.se.omapi.Channel#transmit(byte[])}.
      */
-    // TODO(b/147153909): Update Javadoc to link to specific SEService API once integrated.
     @Deprecated
     public byte[] iccExchangeSimIO(int subId, int fileID, int command, int p1, int p2,
             int p3, String filePath) {
@@ -6602,9 +6602,12 @@
      * @return The APDU response from the ICC card in hexadecimal format
      *         with the last 4 bytes being the status word. If the command fails,
      *         returns an empty string.
-     * @deprecated Use {@link android.se.omapi.SEService} APIs instead.
+     * @deprecated Use {@link android.se.omapi.SEService} APIs instead. See
+     *             {@link android.se.omapi.SEService#getUiccReader(int)},
+     *             {@link android.se.omapi.Reader#openSession()},
+     *             {@link android.se.omapi.Session#openBasicChannel(byte[], byte)},
+     *             {@link android.se.omapi.Channel#transmit(byte[])}.
      */
-    // TODO(b/147153909): Update Javadoc to link to specific SEService API once integrated.
     @Deprecated
     public String sendEnvelopeWithStatus(String content) {
         return sendEnvelopeWithStatus(getSubId(), content);
@@ -6625,9 +6628,12 @@
      *         with the last 4 bytes being the status word. If the command fails,
      *         returns an empty string.
      * @hide
-     * @deprecated Use {@link android.se.omapi.SEService} APIs instead.
+     * @deprecated Use {@link android.se.omapi.SEService} APIs instead. See
+     *             {@link android.se.omapi.SEService#getUiccReader(int)},
+     *             {@link android.se.omapi.Reader#openSession()},
+     *             {@link android.se.omapi.Session#openBasicChannel(byte[], byte)},
+     *             {@link android.se.omapi.Channel#transmit(byte[])}.
      */
-    // TODO(b/147153909): Update Javadoc to link to specific SEService API once integrated.
     @Deprecated
     public String sendEnvelopeWithStatus(int subId, String content) {
         try {
@@ -11082,28 +11088,6 @@
     }
 
     /**
-     * Get aggregated video call data usage since boot.
-     * Permissions android.Manifest.permission.READ_NETWORK_USAGE_HISTORY is required.
-     *
-     * @param how one of the NetworkStats.STATS_PER_* constants depending on whether the request is
-     * for data usage per uid or overall usage.
-     * @return Snapshot of video call data usage
-     * @hide
-     */
-    public NetworkStats getVtDataUsage(int how) {
-        boolean perUidStats = (how == NetworkStats.STATS_PER_UID);
-        try {
-            ITelephony service = getITelephony();
-            if (service != null) {
-                return service.getVtDataUsage(getSubId(), perUidStats);
-            }
-        } catch (RemoteException e) {
-            Log.e(TAG, "Error calling ITelephony#getVtDataUsage", e);
-        }
-        return null;
-    }
-
-    /**
      * Policy control of data connection. Usually used when data limit is passed.
      * @param enabled True if enabling the data, otherwise disabling.
      * @hide
diff --git a/telephony/java/android/telephony/ims/ImsCallSession.java b/telephony/java/android/telephony/ims/ImsCallSession.java
old mode 100644
new mode 100755
index 1b583fd..80c38cb
--- a/telephony/java/android/telephony/ims/ImsCallSession.java
+++ b/telephony/java/android/telephony/ims/ImsCallSession.java
@@ -16,6 +16,8 @@
 
 package android.telephony.ims;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.os.Message;
 import android.os.RemoteException;
 import android.telephony.CallQuality;
@@ -451,6 +453,21 @@
         }
 
         /**
+         * Received success response for call transfer request.
+         */
+        public void callSessionTransferred(@NonNull ImsCallSession session) {
+            // no-op
+        }
+
+        /**
+         * Received failure response for call transfer request.
+         */
+        public void callSessionTransferFailed(@NonNull ImsCallSession session,
+                @Nullable ImsReasonInfo reasonInfo) {
+            // no-op
+        }
+
+        /**
          * Called when the IMS service reports a change to the call quality.
          */
         public void callQualityChanged(CallQuality callQuality) {
@@ -795,6 +812,41 @@
     }
 
     /**
+     * Transfers an ongoing call.
+     *
+     * @param number number to be transferred to.
+     * @param isConfirmationRequired indicates blind or assured transfer.
+     */
+    public void transfer(@NonNull String number, boolean isConfirmationRequired) {
+        if (mClosed) {
+            return;
+        }
+
+        try {
+            miSession.transfer(number, isConfirmationRequired);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
+     * Transfers a call to another ongoing call.
+     *
+     * @param transferToSession the other ImsCallSession to which this session will be transferred.
+     */
+    public void transfer(@NonNull ImsCallSession transferToSession) {
+        if (mClosed) {
+            return;
+        }
+
+        try {
+            if (transferToSession != null) {
+                miSession.consultativeTransfer(transferToSession.getSession());
+            }
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
      * Terminates a call.
      *
      * @see Listener#callSessionTerminated
@@ -1410,6 +1462,20 @@
             }
         }
 
+        @Override
+        public void callSessionTransferred() {
+            if (mListener != null) {
+                mListener.callSessionTransferred(ImsCallSession.this);
+            }
+        }
+
+        @Override
+        public void callSessionTransferFailed(@Nullable ImsReasonInfo reasonInfo) {
+            if (mListener != null) {
+                mListener.callSessionTransferFailed(ImsCallSession.this, reasonInfo);
+            }
+        }
+
         /**
          * Call quality updated
          */
diff --git a/telephony/java/android/telephony/ims/aidl/IImsCallSessionListener.aidl b/telephony/java/android/telephony/ims/aidl/IImsCallSessionListener.aidl
index cc2ebb9..36d2067 100644
--- a/telephony/java/android/telephony/ims/aidl/IImsCallSessionListener.aidl
+++ b/telephony/java/android/telephony/ims/aidl/IImsCallSessionListener.aidl
@@ -148,6 +148,12 @@
     void callSessionRttAudioIndicatorChanged(in ImsStreamMediaProfile profile);
 
     /**
+     * Notifies the result of transfer request.
+     */
+    void callSessionTransferred();
+    void callSessionTransferFailed(in ImsReasonInfo reasonInfo);
+
+    /**
      * Notifies of a change to the call quality.
      * @param callQuality then updated call quality
      */
diff --git a/telephony/java/android/telephony/ims/compat/stub/ImsCallSessionImplBase.java b/telephony/java/android/telephony/ims/compat/stub/ImsCallSessionImplBase.java
old mode 100644
new mode 100755
index 75bd6a7..06aa642
--- a/telephony/java/android/telephony/ims/compat/stub/ImsCallSessionImplBase.java
+++ b/telephony/java/android/telephony/ims/compat/stub/ImsCallSessionImplBase.java
@@ -16,6 +16,8 @@
 
 package android.telephony.ims.compat.stub;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Message;
 import android.os.RemoteException;
@@ -197,6 +199,29 @@
     }
 
     /**
+     * Transfer an established call to given number, disconnecting the ongoing call
+     * when the transfer is complete.
+     *
+     * @param number number to transfer the call
+     * @param isConfirmationRequired when {@code true}, then the {@link ImsCallSessionImplBase}
+     * should wait until the transfer has successfully completed before disconnecting the current
+     * {@link ImsCallSessionImplBase}. When {@code false}, the {@link ImsCallSessionImplBase}
+     * should signal the network to perform the transfer, but should immediately disconnect the
+     * call regardless of the outcome of the transfer.
+     */
+    @Override
+    public void transfer(@NonNull String number, boolean isConfirmationRequired) {
+    }
+
+    /**
+     * Transfer an established call to an existing ongoing session.
+     * When the transfer is complete, the current call gets disconnected locally.
+     */
+    @Override
+    public void consultativeTransfer(@NonNull IImsCallSession transferToSession) {
+    }
+
+    /**
      * Rejects an incoming call or session update.
      *
      * @param reason reason code to reject an incoming call, defined in {@link ImsReasonInfo}.
@@ -610,6 +635,17 @@
         }
 
         @Override
+        public void callSessionTransferred() throws RemoteException {
+            mNewListener.callSessionTransferred();
+        }
+
+        @Override
+        public void callSessionTransferFailed(@Nullable ImsReasonInfo reasonInfo)
+                throws RemoteException {
+            mNewListener.callSessionTransferFailed(reasonInfo);
+        }
+
+        @Override
         public void callQualityChanged(CallQuality callQuality) throws RemoteException {
             mNewListener.callQualityChanged(callQuality);
         }
diff --git a/telephony/java/android/telephony/ims/stub/ImsCallSessionImplBase.java b/telephony/java/android/telephony/ims/stub/ImsCallSessionImplBase.java
index e8f69ea..73ba0e3 100644
--- a/telephony/java/android/telephony/ims/stub/ImsCallSessionImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsCallSessionImplBase.java
@@ -16,6 +16,7 @@
 
 package android.telephony.ims.stub;
 
+import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
 import android.os.Message;
@@ -183,6 +184,18 @@
         }
 
         @Override
+        public void transfer(@NonNull String number, boolean isConfirmationRequired) {
+            ImsCallSessionImplBase.this.transfer(number, isConfirmationRequired);
+        }
+
+        @Override
+        public void consultativeTransfer(@NonNull IImsCallSession transferToSession) {
+            ImsCallSessionImplBase otherSession = new ImsCallSessionImplBase();
+            otherSession.setServiceImpl(transferToSession);
+            ImsCallSessionImplBase.this.transfer(otherSession);
+        }
+
+        @Override
         public void terminate(int reason) {
             ImsCallSessionImplBase.this.terminate(reason);
         }
@@ -423,6 +436,26 @@
     }
 
     /**
+     * Transfer an established call to given number
+     *
+     * @param number number to transfer the call
+     * @param isConfirmationRequired if {@code True}, indicates Assured transfer,
+     * if {@code False} it indicates Blind transfer.
+     * @hide
+     */
+    public void transfer(@NonNull String number, boolean isConfirmationRequired) {
+    }
+
+    /**
+     * Transfer an established call to another call session
+     *
+     * @param otherSession The other ImsCallSession to transfer the ongoing session to.
+     * @hide
+     */
+    public void transfer(@NonNull ImsCallSessionImplBase otherSession) {
+    }
+
+    /**
      * Terminates a call.
      *
      * @param reason reason code to terminate a call, defined in {@link ImsReasonInfo}.
diff --git a/telephony/java/com/android/ims/internal/IImsCallSession.aidl b/telephony/java/com/android/ims/internal/IImsCallSession.aidl
index 15234e5..0466efc 100644
--- a/telephony/java/com/android/ims/internal/IImsCallSession.aidl
+++ b/telephony/java/com/android/ims/internal/IImsCallSession.aidl
@@ -18,7 +18,6 @@
 
 import android.os.Message;
 import android.telephony.ims.aidl.IImsCallSessionListener;
-
 import android.telephony.ims.ImsCallProfile;
 import android.telephony.ims.ImsStreamMediaProfile;
 import com.android.ims.internal.IImsVideoCallProvider;
@@ -151,6 +150,22 @@
     void reject(int reason);
 
     /**
+     * Transfer an established call to given number
+     *
+     * @param number number to transfer the call
+     * @param isConfirmationRequired if {@code True}, indicates Assured transfer,
+     * if {@code False} it indicates Blind transfer.
+     */
+    void transfer(String number, boolean isConfirmationRequired);
+
+    /**
+     * Transfer an established call to another call session
+     *
+     * @param transferToSession The other ImsCallSession to transfer the ongoing session to.
+     */
+    void consultativeTransfer(in IImsCallSession transferToSession);
+
+    /**
      * Terminates a call.
      *
      * @see Listener#callSessionTerminated
diff --git a/telephony/java/com/android/ims/internal/IImsCallSessionListener.aidl b/telephony/java/com/android/ims/internal/IImsCallSessionListener.aidl
index b33a9f1..1c62cc4 100644
--- a/telephony/java/com/android/ims/internal/IImsCallSessionListener.aidl
+++ b/telephony/java/com/android/ims/internal/IImsCallSessionListener.aidl
@@ -184,6 +184,12 @@
     void callSessionRttAudioIndicatorChanged(in ImsStreamMediaProfile profile);
 
     /**
+     * Notifies about the response for call transfer request.
+     */
+    void callSessionTransferred();
+
+    void callSessionTransferFailed(in ImsReasonInfo reasonInfo);
+    /**
      * Notifies of a change to the call quality.
      * @param callQuality then updated call quality
      */
diff --git a/telephony/java/com/android/internal/telephony/DctConstants.java b/telephony/java/com/android/internal/telephony/DctConstants.java
index 1449a62..f61d4e1 100644
--- a/telephony/java/com/android/internal/telephony/DctConstants.java
+++ b/telephony/java/com/android/internal/telephony/DctConstants.java
@@ -114,6 +114,7 @@
     public static final int EVENT_SERVICE_STATE_CHANGED = BASE + 52;
     public static final int EVENT_5G_TIMER_HYSTERESIS = BASE + 53;
     public static final int EVENT_5G_TIMER_WATCHDOG = BASE + 54;
+    public static final int EVENT_UPDATE_CARRIER_CONFIGS = BASE + 55;
 
     /***** Constants *****/
 
@@ -123,4 +124,6 @@
 
     public static final String APN_TYPE_KEY = "apnType";
     public static final String PROVISIONING_URL_KEY = "provisioningUrl";
+    public static final String BANDWIDTH_SOURCE_MODEM_KEY = "modem";
+    public static final String BANDWIDTH_SOURCE_CARRIER_CONFIG_KEY = "carrier_config";
 }
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 168c8b6..861925f 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -39,7 +39,6 @@
 import android.telephony.ModemActivityInfo;
 import android.telephony.NeighboringCellInfo;
 import android.telephony.NetworkScanRequest;
-import android.telephony.PhoneCapability;
 import android.telephony.PhoneNumberRange;
 import android.telephony.RadioAccessFamily;
 import android.telephony.RadioAccessSpecifier;
@@ -1624,16 +1623,6 @@
     void carrierActionResetAll(int subId);
 
     /**
-     * Get aggregated video call data usage since boot.
-     * Permissions android.Manifest.permission.READ_NETWORK_USAGE_HISTORY is required.
-     *
-     * @param perUidStats True if requesting data usage per uid, otherwise overall usage.
-     * @return Snapshot of video call data usage
-     * @hide
-     */
-    NetworkStats getVtDataUsage(int subId, boolean perUidStats);
-
-    /**
      * Gets the voice call forwarding info {@link CallForwardingInfo}, given the call forward
      * reason.
      *
@@ -1899,17 +1888,12 @@
     /**
      * Return the network selection mode on the subscription with id {@code subId}.
      */
-    int getNetworkSelectionMode(int subId);
+     int getNetworkSelectionMode(int subId);
 
-    /**
-     * Return the PhoneCapability for the device.
-     */
-    PhoneCapability getPhoneCapability(int subId, String callingPackage, String callingFeatureId);
-
-    /**
+     /**
      * Return true if the device is in emergency sms mode, false otherwise.
      */
-    boolean isInEmergencySmsMode();
+     boolean isInEmergencySmsMode();
 
     /**
      * Return the modem radio power state for slot index.
diff --git a/test-mock/src/android/test/mock/MockContentProvider.java b/test-mock/src/android/test/mock/MockContentProvider.java
index f7ec11c..d1d64d3 100644
--- a/test-mock/src/android/test/mock/MockContentProvider.java
+++ b/test-mock/src/android/test/mock/MockContentProvider.java
@@ -156,6 +156,12 @@
         }
 
         @Override
+        public void canonicalizeAsync(String callingPkg, String featureId, Uri uri,
+                RemoteCallback callback) {
+            MockContentProvider.this.canonicalizeAsync(uri, callback);
+        }
+
+        @Override
         public Uri uncanonicalize(String callingPkg, @Nullable String featureId, Uri uri)
                 throws RemoteException {
             return MockContentProvider.this.uncanonicalize(uri);
@@ -292,6 +298,18 @@
     /**
      * @hide
      */
+    @SuppressWarnings("deprecation")
+    public void canonicalizeAsync(Uri uri, RemoteCallback callback) {
+        AsyncTask.SERIAL_EXECUTOR.execute(() -> {
+            final Bundle bundle = new Bundle();
+            bundle.putParcelable(ContentResolver.REMOTE_CALLBACK_RESULT, canonicalize(uri));
+            callback.sendResult(bundle);
+        });
+    }
+
+    /**
+     * @hide
+     */
     public boolean refresh(Uri url, Bundle args) {
         throw new UnsupportedOperationException("unimplemented mock method call");
     }
diff --git a/test-mock/src/android/test/mock/MockContext.java b/test-mock/src/android/test/mock/MockContext.java
index 359c448..2c66047 100644
--- a/test-mock/src/android/test/mock/MockContext.java
+++ b/test-mock/src/android/test/mock/MockContext.java
@@ -834,6 +834,12 @@
 
     /** @hide */
     @Override
+    public Display getDisplayNoVerify() {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
     public int getDisplayId() {
         throw new UnsupportedOperationException();
     }
diff --git a/test-mock/src/android/test/mock/MockIContentProvider.java b/test-mock/src/android/test/mock/MockIContentProvider.java
index 1831bcd..223bcc5 100644
--- a/test-mock/src/android/test/mock/MockIContentProvider.java
+++ b/test-mock/src/android/test/mock/MockIContentProvider.java
@@ -145,12 +145,23 @@
     }
 
     @Override
-    public Uri canonicalize(String callingPkg, @Nullable String featureId, Uri uri)
-            throws RemoteException {
+    public Uri canonicalize(String callingPkg, @Nullable String featureId, Uri uri) {
         throw new UnsupportedOperationException("unimplemented mock method");
     }
 
     @Override
+    @SuppressWarnings("deprecation")
+    public void canonicalizeAsync(String callingPkg, String featureId, Uri uri,
+            RemoteCallback remoteCallback) {
+        AsyncTask.SERIAL_EXECUTOR.execute(() -> {
+            final Bundle bundle = new Bundle();
+            bundle.putParcelable(ContentResolver.REMOTE_CALLBACK_RESULT,
+                    canonicalize(callingPkg, featureId, uri));
+            remoteCallback.sendResult(bundle);
+        });
+    }
+
+    @Override
     public Uri uncanonicalize(String callingPkg, @Nullable String featureId, Uri uri)
             throws RemoteException {
         throw new UnsupportedOperationException("unimplemented mock method");
diff --git a/tests/BootImageProfileTest/TEST_MAPPING b/tests/BootImageProfileTest/DISABLED_TEST_MAPPING
similarity index 100%
rename from tests/BootImageProfileTest/TEST_MAPPING
rename to tests/BootImageProfileTest/DISABLED_TEST_MAPPING
diff --git a/tests/RollbackTest/MultiUserRollbackTest/src/com/android/tests/rollback/host/MultiUserRollbackTest.java b/tests/RollbackTest/MultiUserRollbackTest/src/com/android/tests/rollback/host/MultiUserRollbackTest.java
index 52f6eba..e616ac4 100644
--- a/tests/RollbackTest/MultiUserRollbackTest/src/com/android/tests/rollback/host/MultiUserRollbackTest.java
+++ b/tests/RollbackTest/MultiUserRollbackTest/src/com/android/tests/rollback/host/MultiUserRollbackTest.java
@@ -27,6 +27,8 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.concurrent.TimeUnit;
+
 /**
  * Runs rollback tests for multiple users.
  */
@@ -41,7 +43,6 @@
 
     @After
     public void tearDown() throws Exception {
-        getDevice().switchUser(mOriginalUserId);
         getDevice().executeShellCommand("pm uninstall com.android.cts.install.lib.testapp.A");
         removeSecondaryUserIfNecessary();
     }
@@ -49,9 +50,9 @@
     @Before
     public void setup() throws Exception {
         mOriginalUserId = getDevice().getCurrentUser();
-        installPackageAsUser("RollbackTest.apk", true, mOriginalUserId);
-        createAndSwitchToSecondaryUserIfNecessary();
-        installPackageAsUser("RollbackTest.apk", true, mSecondaryUserId);
+        createAndStartSecondaryUser();
+        // TODO(b/149733368): Remove the '-g' workaround when the bug is fixed.
+        installPackage("RollbackTest.apk", "-g --user all");
     }
 
     @Test
@@ -64,7 +65,6 @@
         runPhaseForUsers("testMultipleUsersInstallV1", mOriginalUserId, mSecondaryUserId);
         runPhaseForUsers("testMultipleUsersUpgradeToV2", mOriginalUserId);
         runPhaseForUsers("testMultipleUsersUpdateUserData", mOriginalUserId, mSecondaryUserId);
-        switchToUser(mOriginalUserId);
         getDevice().executeShellCommand("pm rollback-app com.android.cts.install.lib.testapp.A");
         runPhaseForUsers("testMultipleUsersVerifyUserdataRollback", mOriginalUserId,
                 mSecondaryUserId);
@@ -74,11 +74,11 @@
      * Run the phase for the given user ids, in the order they are given.
      */
     private void runPhaseForUsers(String phase, int... userIds) throws Exception {
+        final long timeout = TimeUnit.MINUTES.toMillis(10);
         for (int userId: userIds) {
-            switchToUser(userId);
-            assertTrue(runDeviceTests("com.android.tests.rollback",
+            assertTrue(runDeviceTests(getDevice(), "com.android.tests.rollback",
                     "com.android.tests.rollback.MultiUserRollbackTest",
-                    phase));
+                    phase, userId, timeout));
         }
     }
 
@@ -89,21 +89,7 @@
         }
     }
 
-    private void createAndSwitchToSecondaryUserIfNecessary() throws Exception {
-        if (mSecondaryUserId == -1) {
-            mOriginalUserId = getDevice().getCurrentUser();
-            mSecondaryUserId = getDevice().createUser("MultiUserRollbackTest_User"
-                    + System.currentTimeMillis());
-            switchToUser(mSecondaryUserId);
-        }
-    }
-
-    private void switchToUser(int userId) throws Exception {
-        if (getDevice().getCurrentUser() == userId) {
-            return;
-        }
-
-        assertTrue(getDevice().switchUser(userId));
+    private void awaitUserUnlocked(int userId) throws Exception {
         for (int i = 0; i < SWITCH_USER_COMPLETED_NUMBER_OF_POLLS; ++i) {
             String userState = getDevice().executeShellCommand("am get-started-user-state "
                     + userId);
@@ -112,6 +98,14 @@
             }
             Thread.sleep(SWITCH_USER_COMPLETED_POLL_INTERVAL_IN_MILLIS);
         }
-        fail("User switch to user " + userId + " timed out");
+        fail("Timed out in unlocking user: " + userId);
+    }
+
+    private void createAndStartSecondaryUser() throws Exception {
+        String name = "MultiUserRollbackTest_User" + System.currentTimeMillis();
+        mSecondaryUserId = getDevice().createUser(name);
+        getDevice().startUser(mSecondaryUserId);
+        // Note we can't install apps on a locked user
+        awaitUserUnlocked(mSecondaryUserId);
     }
 }
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/MultiUserRollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/MultiUserRollbackTest.java
index 0ffe041..400bb04 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/MultiUserRollbackTest.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/MultiUserRollbackTest.java
@@ -17,13 +17,11 @@
 package com.android.tests.rollback;
 
 import static com.android.cts.rollback.lib.RollbackInfoSubject.assertThat;
-import static com.android.cts.rollback.lib.RollbackUtils.getUniqueRollbackInfoForPackage;
 
 import static com.google.common.truth.Truth.assertThat;
 
 import android.Manifest;
 import android.content.rollback.RollbackInfo;
-import android.content.rollback.RollbackManager;
 
 import com.android.cts.install.lib.Install;
 import com.android.cts.install.lib.InstallUtils;
@@ -77,13 +75,10 @@
      */
     @Test
     public void testMultipleUsersUpgradeToV2() throws Exception {
-        RollbackManager rm = RollbackUtils.getRollbackManager();
         assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
         Install.single(TestApp.A2).setEnableRollback().commit();
         assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
-        RollbackInfo rollback = getUniqueRollbackInfoForPackage(
-                rm.getAvailableRollbacks(), TestApp.A);
-        assertThat(rollback).isNotNull();
+        RollbackInfo rollback = RollbackUtils.waitForAvailableRollback(TestApp.A);
         assertThat(rollback).packagesContainsExactly(
                 Rollback.from(TestApp.A2).to(TestApp.A1));
     }
diff --git a/tests/net/AndroidManifest.xml b/tests/net/AndroidManifest.xml
index 638b6d1..480b12b 100644
--- a/tests/net/AndroidManifest.xml
+++ b/tests/net/AndroidManifest.xml
@@ -50,6 +50,7 @@
 
     <application>
         <uses-library android:name="android.test.runner" />
+        <uses-library android:name="android.net.ipsec.ike" />
     </application>
 
     <instrumentation
diff --git a/tests/net/integration/src/com/android/server/net/integrationtests/TestNetworkStackService.kt b/tests/net/integration/src/com/android/server/net/integrationtests/TestNetworkStackService.kt
index 490c467..23caf49 100644
--- a/tests/net/integration/src/com/android/server/net/integrationtests/TestNetworkStackService.kt
+++ b/tests/net/integration/src/com/android/server/net/integrationtests/TestNetworkStackService.kt
@@ -26,6 +26,7 @@
 import android.os.IBinder
 import com.android.networkstack.metrics.DataStallStatsUtils
 import com.android.networkstack.netlink.TcpSocketTracker
+import com.android.server.NetworkStackService
 import com.android.server.NetworkStackService.NetworkMonitorConnector
 import com.android.server.NetworkStackService.NetworkStackConnector
 import com.android.server.connectivity.NetworkMonitor
@@ -88,6 +89,7 @@
             val nm = NetworkMonitor(this@TestNetworkStackService, cb,
                     this.network,
                     mock(IpConnectivityLog::class.java), mock(SharedLog::class.java),
+                    mock(NetworkStackService.NetworkStackServiceManager::class.java),
                     NetworkMonitorDeps(privateDnsBypassNetwork),
                     mock(DataStallStatsUtils::class.java),
                     mock(TcpSocketTracker::class.java))
diff --git a/tests/net/java/android/net/Ikev2VpnProfileTest.java b/tests/net/java/android/net/Ikev2VpnProfileTest.java
index d6a2176..2273bc6 100644
--- a/tests/net/java/android/net/Ikev2VpnProfileTest.java
+++ b/tests/net/java/android/net/Ikev2VpnProfileTest.java
@@ -22,7 +22,6 @@
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
-import static org.mockito.Mockito.mock;
 
 import android.test.mock.MockContext;
 
@@ -232,10 +231,12 @@
         builder.setAuthDigitalSignature(mUserCert, mPrivateKey, mServerRootCa);
         final VpnProfile profile = builder.build().toVpnProfile();
 
+        final String expectedSecret = Ikev2VpnProfile.PREFIX_INLINE
+                + Ikev2VpnProfile.encodeForIpsecSecret(mPrivateKey.getEncoded());
         verifyVpnProfileCommon(profile);
         assertEquals(Ikev2VpnProfile.certificateToPemString(mUserCert), profile.ipsecUserCert);
         assertEquals(
-                Ikev2VpnProfile.encodeForIpsecSecret(mPrivateKey.getEncoded()),
+                expectedSecret,
                 profile.ipsecSecret);
         assertEquals(Ikev2VpnProfile.certificateToPemString(mServerRootCa), profile.ipsecCaCert);
 
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 220cdce..6d4a1b2 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -1180,6 +1180,10 @@
                 Arrays.asList(new UserInfo[] {
                         new UserInfo(VPN_USER, "", 0),
                 }));
+        final ApplicationInfo applicationInfo = new ApplicationInfo();
+        applicationInfo.targetSdkVersion = Build.VERSION_CODES.Q;
+        when(mPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), any()))
+                .thenReturn(applicationInfo);
 
         // InstrumentationTestRunner prepares a looper, but AndroidJUnitRunner does not.
         // http://b/25897652 .
@@ -3042,7 +3046,7 @@
             networkCapabilities.addTransportType(TRANSPORT_WIFI)
                     .setNetworkSpecifier(new MatchAllNetworkSpecifier());
             mService.requestNetwork(networkCapabilities, null, 0, null,
-                    ConnectivityManager.TYPE_WIFI, TEST_PACKAGE_NAME);
+                    ConnectivityManager.TYPE_WIFI, mContext.getPackageName());
         });
 
         class NonParcelableSpecifier extends NetworkSpecifier {
@@ -6439,17 +6443,89 @@
         assertEquals(wifiLp, mService.getActiveLinkProperties());
     }
 
+    private void setupLocationPermissions(
+            int targetSdk, boolean locationToggle, String op, String perm) throws Exception {
+        final ApplicationInfo applicationInfo = new ApplicationInfo();
+        applicationInfo.targetSdkVersion = targetSdk;
+        when(mPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), any()))
+                .thenReturn(applicationInfo);
+
+        when(mLocationManager.isLocationEnabledForUser(any())).thenReturn(locationToggle);
+
+        if (op != null) {
+            when(mAppOpsManager.noteOp(eq(op), eq(Process.myUid()), eq(mContext.getPackageName())))
+                .thenReturn(AppOpsManager.MODE_ALLOWED);
+        }
+
+        if (perm != null) {
+            mServiceContext.setPermission(perm, PERMISSION_GRANTED);
+        }
+    }
+
+    private int getOwnerUidNetCapsForCallerPermission(int ownerUid, int callerUid) {
+        final NetworkCapabilities netCap = new NetworkCapabilities().setOwnerUid(ownerUid);
+
+        return mService
+                .maybeSanitizeLocationInfoForCaller(netCap, callerUid, mContext.getPackageName())
+                .getOwnerUid();
+    }
+
     @Test
-    public void testNetworkCapabilitiesRestrictedForCallerPermissions() {
-        int callerUid = Process.myUid();
-        final NetworkCapabilities originalNc = new NetworkCapabilities();
-        originalNc.setOwnerUid(callerUid);
+    public void testMaybeSanitizeLocationInfoForCallerWithFineLocationAfterQ() throws Exception {
+        setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
+                Manifest.permission.ACCESS_FINE_LOCATION);
 
-        final NetworkCapabilities newNc =
-                mService.networkCapabilitiesRestrictedForCallerPermissions(
-                        originalNc, Process.myPid(), callerUid);
+        final int myUid = Process.myUid();
+        assertEquals(myUid, getOwnerUidNetCapsForCallerPermission(myUid, myUid));
+    }
 
-        assertEquals(Process.INVALID_UID, newNc.getOwnerUid());
+    @Test
+    public void testMaybeSanitizeLocationInfoForCallerWithCoarseLocationPreQ() throws Exception {
+        setupLocationPermissions(Build.VERSION_CODES.P, true, AppOpsManager.OPSTR_COARSE_LOCATION,
+                Manifest.permission.ACCESS_COARSE_LOCATION);
+
+        final int myUid = Process.myUid();
+        assertEquals(myUid, getOwnerUidNetCapsForCallerPermission(myUid, myUid));
+    }
+
+    @Test
+    public void testMaybeSanitizeLocationInfoForCallerLocationOff() throws Exception {
+        // Test that even with fine location permission, and UIDs matching, the UID is sanitized.
+        setupLocationPermissions(Build.VERSION_CODES.Q, false, AppOpsManager.OPSTR_FINE_LOCATION,
+                Manifest.permission.ACCESS_FINE_LOCATION);
+
+        final int myUid = Process.myUid();
+        assertEquals(Process.INVALID_UID, getOwnerUidNetCapsForCallerPermission(myUid, myUid));
+    }
+
+    @Test
+    public void testMaybeSanitizeLocationInfoForCallerWrongUid() throws Exception {
+        // Test that even with fine location permission, not being the owner leads to sanitization.
+        setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
+                Manifest.permission.ACCESS_FINE_LOCATION);
+
+        final int myUid = Process.myUid();
+        assertEquals(Process.INVALID_UID, getOwnerUidNetCapsForCallerPermission(myUid + 1, myUid));
+    }
+
+    @Test
+    public void testMaybeSanitizeLocationInfoForCallerWithCoarseLocationAfterQ() throws Exception {
+        // Test that not having fine location permission leads to sanitization.
+        setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_COARSE_LOCATION,
+                Manifest.permission.ACCESS_COARSE_LOCATION);
+
+        // Test that without the location permission, the owner field is sanitized.
+        final int myUid = Process.myUid();
+        assertEquals(Process.INVALID_UID, getOwnerUidNetCapsForCallerPermission(myUid, myUid));
+    }
+
+    @Test
+    public void testMaybeSanitizeLocationInfoForCallerWithoutLocationPermission() throws Exception {
+        setupLocationPermissions(Build.VERSION_CODES.Q, true, null /* op */, null /* perm */);
+
+        // Test that without the location permission, the owner field is sanitized.
+        final int myUid = Process.myUid();
+        assertEquals(Process.INVALID_UID, getOwnerUidNetCapsForCallerPermission(myUid, myUid));
     }
 
     private void setupConnectionOwnerUid(int vpnOwnerUid, @VpnManager.VpnType int vpnType)
@@ -6735,21 +6811,6 @@
                         mContext.getOpPackageName()));
     }
 
-    private void setupLocationPermissions(
-            int targetSdk, boolean locationToggle, String op, String perm) throws Exception {
-        final ApplicationInfo applicationInfo = new ApplicationInfo();
-        applicationInfo.targetSdkVersion = targetSdk;
-        when(mPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), any()))
-                .thenReturn(applicationInfo);
-
-        when(mLocationManager.isLocationEnabledForUser(any())).thenReturn(locationToggle);
-
-        when(mAppOpsManager.noteOp(eq(op), eq(Process.myUid()), eq(mContext.getPackageName())))
-                .thenReturn(AppOpsManager.MODE_ALLOWED);
-
-        mServiceContext.setPermission(perm, PERMISSION_GRANTED);
-    }
-
     private void setUpConnectivityDiagnosticsCallback() throws Exception {
         final NetworkRequest request = new NetworkRequest.Builder().build();
         when(mConnectivityDiagnosticsCallback.asBinder()).thenReturn(mIBinder);
diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java
index 0e3b797..1994d1f 100644
--- a/tests/net/java/com/android/server/connectivity/VpnTest.java
+++ b/tests/net/java/com/android/server/connectivity/VpnTest.java
@@ -59,9 +59,15 @@
 import android.content.pm.UserInfo;
 import android.content.res.Resources;
 import android.net.ConnectivityManager;
+import android.net.Ikev2VpnProfile;
+import android.net.InetAddresses;
+import android.net.IpPrefix;
+import android.net.IpSecManager;
+import android.net.LinkProperties;
 import android.net.Network;
 import android.net.NetworkCapabilities;
 import android.net.NetworkInfo.DetailedState;
+import android.net.RouteInfo;
 import android.net.UidRange;
 import android.net.VpnManager;
 import android.net.VpnService;
@@ -84,6 +90,7 @@
 import com.android.internal.R;
 import com.android.internal.net.VpnConfig;
 import com.android.internal.net.VpnProfile;
+import com.android.server.IpSecService;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -93,6 +100,7 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import java.net.Inet4Address;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
@@ -125,6 +133,9 @@
     }
 
     static final String TEST_VPN_PKG = "com.dummy.vpn";
+    private static final String TEST_VPN_SERVER = "1.2.3.4";
+    private static final String TEST_VPN_IDENTITY = "identity";
+    private static final byte[] TEST_VPN_PSK = "psk".getBytes();
 
     /**
      * Names and UIDs for some fake packages. Important points:
@@ -151,23 +162,39 @@
     @Mock private Vpn.SystemServices mSystemServices;
     @Mock private Vpn.Ikev2SessionCreator mIkev2SessionCreator;
     @Mock private ConnectivityManager mConnectivityManager;
+    @Mock private IpSecService mIpSecService;
     @Mock private KeyStore mKeyStore;
-    private final VpnProfile mVpnProfile = new VpnProfile("key");
+    private final VpnProfile mVpnProfile;
+
+    private IpSecManager mIpSecManager;
+
+    public VpnTest() throws Exception {
+        // Build an actual VPN profile that is capable of being converted to and from an
+        // Ikev2VpnProfile
+        final Ikev2VpnProfile.Builder builder =
+                new Ikev2VpnProfile.Builder(TEST_VPN_SERVER, TEST_VPN_IDENTITY);
+        builder.setAuthPsk(TEST_VPN_PSK);
+        mVpnProfile = builder.build().toVpnProfile();
+    }
 
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
 
+        mIpSecManager = new IpSecManager(mContext, mIpSecService);
+
         when(mContext.getPackageManager()).thenReturn(mPackageManager);
         setMockedPackages(mPackages);
 
-        when(mContext.getPackageName()).thenReturn(Vpn.class.getPackage().getName());
+        when(mContext.getPackageName()).thenReturn(TEST_VPN_PKG);
+        when(mContext.getOpPackageName()).thenReturn(TEST_VPN_PKG);
         when(mContext.getSystemService(eq(Context.USER_SERVICE))).thenReturn(mUserManager);
         when(mContext.getSystemService(eq(Context.APP_OPS_SERVICE))).thenReturn(mAppOps);
         when(mContext.getSystemService(eq(Context.NOTIFICATION_SERVICE)))
                 .thenReturn(mNotificationManager);
         when(mContext.getSystemService(eq(Context.CONNECTIVITY_SERVICE)))
                 .thenReturn(mConnectivityManager);
+        when(mContext.getSystemService(eq(Context.IPSEC_SERVICE))).thenReturn(mIpSecManager);
         when(mContext.getString(R.string.config_customVpnAlwaysOnDisconnectedDialogComponent))
                 .thenReturn(Resources.getSystem().getString(
                         R.string.config_customVpnAlwaysOnDisconnectedDialogComponent));
@@ -962,6 +989,26 @@
         // a subsequent CL.
     }
 
+    @Test
+    public void testStartLegacyVpn() throws Exception {
+        final Vpn vpn = createVpn(primaryUser.id);
+        setMockedUsers(primaryUser);
+
+        // Dummy egress interface
+        final String egressIface = "DUMMY0";
+        final LinkProperties lp = new LinkProperties();
+        lp.setInterfaceName(egressIface);
+
+        final RouteInfo defaultRoute = new RouteInfo(new IpPrefix(Inet4Address.ANY, 0),
+                        InetAddresses.parseNumericAddress("192.0.2.0"), egressIface);
+        lp.addRoute(defaultRoute);
+
+        vpn.startLegacyVpn(mVpnProfile, mKeyStore, lp);
+
+        // TODO: Test the Ikev2VpnRunner started up properly. Relies on utility methods added in
+        // a subsequent CL.
+    }
+
     /**
      * Mock some methods of vpn object.
      */
diff --git a/tests/utils/testutils/java/com/android/server/wm/test/filters/FrameworksTestsFilter.java b/tests/utils/testutils/java/com/android/server/wm/test/filters/FrameworksTestsFilter.java
index 957216e..26916bc 100644
--- a/tests/utils/testutils/java/com/android/server/wm/test/filters/FrameworksTestsFilter.java
+++ b/tests/utils/testutils/java/com/android/server/wm/test/filters/FrameworksTestsFilter.java
@@ -38,6 +38,7 @@
             "android.app.activity.ActivityThreadClientTest",
             // Test specifications for FrameworksCoreTests.
             "android.app.servertransaction.", // all tests under the package.
+            "android.view.CutoutSpecificationTest",
             "android.view.DisplayCutoutTest",
             "android.view.InsetsAnimationControlImplTest",
             "android.view.InsetsControllerTest",
diff --git a/tools/hiddenapi/merge_csv.py b/tools/hiddenapi/merge_csv.py
index 9661927..6a5b0e1 100755
--- a/tools/hiddenapi/merge_csv.py
+++ b/tools/hiddenapi/merge_csv.py
@@ -14,26 +14,56 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 """
-Merge mutliple CSV files, possibly with different columns, writing to stdout.
+Merge multiple CSV files, possibly with different columns.
 """
 
+import argparse
 import csv
-import sys
+import io
 
-csv_readers = [
-    csv.DictReader(open(csv_file, 'r'), delimiter=',', quotechar='|')
-    for csv_file in sys.argv[1:]
-]
+from zipfile import ZipFile
 
-# Build union of all columns from source files:
+args_parser = argparse.ArgumentParser(description='Merge given CSV files into a single one.')
+args_parser.add_argument('--header', help='Comma separated field names; '
+                                          'if missing determines the header from input files.')
+args_parser.add_argument('--zip_input', help='ZIP archive with all CSV files to merge.')
+args_parser.add_argument('--output', help='Output file for merged CSV.',
+                         default='-', type=argparse.FileType('w'))
+args_parser.add_argument('files', nargs=argparse.REMAINDER)
+args = args_parser.parse_args()
+
+
+def dict_reader(input):
+    return csv.DictReader(input, delimiter=',', quotechar='|')
+
+
+if args.zip_input and len(args.files) > 0:
+    raise ValueError('Expecting either a single ZIP with CSV files'
+                     ' or a list of CSV files as input; not both.')
+
+csv_readers = []
+if len(args.files) > 0:
+    for file in args.files:
+        csv_readers.append(dict_reader(open(file, 'r')))
+elif args.zip_input:
+    with ZipFile(args.zip_input) as zip:
+        for entry in zip.namelist():
+            if entry.endswith('.uau'):
+                csv_readers.append(dict_reader(io.TextIOWrapper(zip.open(entry, 'r'))))
+
 headers = set()
-for reader in csv_readers:
-    headers = headers.union(reader.fieldnames)
+if args.header:
+    fieldnames = args.header.split(',')
+else:
+    # Build union of all columns from source files:
+    for reader in csv_readers:
+        headers = headers.union(reader.fieldnames)
+    fieldnames = sorted(headers)
 
 # Concatenate all files to output:
-out = csv.DictWriter(sys.stdout, delimiter=',', quotechar='|', quoting=csv.QUOTE_MINIMAL,
-                     dialect='unix', fieldnames=sorted(headers))
-out.writeheader()
+writer = csv.DictWriter(args.output, delimiter=',', quotechar='|', quoting=csv.QUOTE_MINIMAL,
+                        dialect='unix', fieldnames=fieldnames)
+writer.writeheader()
 for reader in csv_readers:
     for row in reader:
-        out.writerow(row)
+        writer.writerow(row)
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index e1450cb..1a12af3 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -2167,6 +2167,7 @@
         sbuf.append("ID: ").append(this.networkId).append(" SSID: ").append(this.SSID).
                 append(" PROVIDER-NAME: ").append(this.providerFriendlyName).
                 append(" BSSID: ").append(this.BSSID).append(" FQDN: ").append(this.FQDN)
+                .append(" HOME-PROVIDER-NETWORK: ").append(this.isHomeProviderNetwork)
                 .append(" PRIO: ").append(this.priority)
                 .append(" HIDDEN: ").append(this.hiddenSSID)
                 .append(" PMF: ").append(this.requirePmf)
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index af2f246..bab9a9e 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -46,6 +46,7 @@
 import android.net.wifi.hotspot2.PasspointConfiguration;
 import android.net.wifi.hotspot2.ProvisioningCallback;
 import android.os.Binder;
+import android.os.Build;
 import android.os.Handler;
 import android.os.HandlerExecutor;
 import android.os.IBinder;
@@ -4920,7 +4921,10 @@
     }
 
     /** @hide */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(
+            maxTargetSdk = Build.VERSION_CODES.Q,
+            publicAlternatives = "Use {@code #setVerboseLoggingEnabled(boolean)} instead."
+    )
     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
     public void enableVerboseLogging (int verbose) {
         try {
@@ -4948,7 +4952,10 @@
 
     /** @hide */
     // TODO(b/145484145): remove once SUW stops calling this via reflection
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(
+            maxTargetSdk = Build.VERSION_CODES.Q,
+            publicAlternatives = "Use {@code #isVerboseLoggingEnabled()} instead."
+    )
     public int getVerboseLoggingLevel() {
         try {
             return mService.getVerboseLoggingLevel();
diff --git a/wifi/java/android/net/wifi/WifiOemMigrationHook.java b/wifi/java/android/net/wifi/WifiOemMigrationHook.java
index 44dbb98..5301dd0 100755
--- a/wifi/java/android/net/wifi/WifiOemMigrationHook.java
+++ b/wifi/java/android/net/wifi/WifiOemMigrationHook.java
@@ -437,7 +437,7 @@
                                 Settings.Global.WIFI_SCAN_THROTTLE_ENABLED, 1) == 1)
                 .setVerboseLoggingEnabled(
                         Settings.Global.getInt(context.getContentResolver(),
-                                Settings.Global.WIFI_VERBOSE_LOGGING_ENABLED, 1) == 1)
+                                Settings.Global.WIFI_VERBOSE_LOGGING_ENABLED, 0) == 1)
                 .build();
     }
 }