Merge "Fix inconsistent OomAdjuster computation result"
diff --git a/.gitignore b/.gitignore
index 481c592..c47cc8b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
 .idea
 *.iml
 *.sw*
+gen/
\ No newline at end of file
diff --git a/Android.bp b/Android.bp
index 7687270..4ef6c5e 100644
--- a/Android.bp
+++ b/Android.bp
@@ -798,7 +798,10 @@
         "--multi-dex",
     ],
 
-    plugins: ["view-inspector-annotation-processor"],
+    plugins: [
+        "view-inspector-annotation-processor",
+        "staledataclass-annotation-processor",
+    ],
 }
 
 filegroup {
@@ -838,14 +841,26 @@
     name: "framework",
     defaults: ["framework-defaults"],
     javac_shard_size: 150,
+    required: [
+        "framework-platform-compat-config",
+        "libcore-platform-compat-config",
+    ],
 }
 
 java_library {
     name: "framework-annotation-proc",
     defaults: ["framework-defaults"],
     installable: false,
-    // Use UsedByApps annotation processor
-    plugins: ["unsupportedappusage-annotation-processor"],
+    plugins: [
+        "unsupportedappusage-annotation-processor",
+        "compat-changeid-annotation-processor",
+    ],
+}
+
+platform_compat_config {
+    name: "framework-platform-compat-config",
+    prefix: "framework",
+    src: ":framework-annotation-proc",
 }
 
 // A library including just UnsupportedAppUsage.java classes.
diff --git a/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java b/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java
index 2fe0ee7..4b7a7f6 100644
--- a/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java
+++ b/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java
@@ -15,6 +15,8 @@
  */
 package android.multiuser;
 
+import static org.junit.Assume.assumeTrue;
+
 import android.app.ActivityManager;
 import android.app.ActivityTaskManager;
 import android.app.AppGlobals;
@@ -86,7 +88,9 @@
     private UserManager mUm;
     private ActivityManager mAm;
     private IActivityManager mIam;
+    private PackageManager mPm;
     private ArrayList<Integer> mUsersToRemove;
+    private boolean mHasManagedUserFeature;
 
     private final BenchmarkRunner mRunner = new BenchmarkRunner();
     @Rule
@@ -99,6 +103,8 @@
         mAm = context.getSystemService(ActivityManager.class);
         mIam = ActivityManager.getService();
         mUsersToRemove = new ArrayList<>();
+        mPm = context.getPackageManager();
+        mHasManagedUserFeature = mPm.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS);
     }
 
     @After
@@ -260,6 +266,8 @@
     /** Tests creating a new profile. */
     @Test
     public void managedProfileCreate() throws Exception {
+        assumeTrue(mHasManagedUserFeature);
+
         while (mRunner.keepRunning()) {
             final int userId = createManagedProfile();
 
@@ -273,6 +281,8 @@
     /** Tests starting (unlocking) a newly-created profile. */
     @Test
     public void managedProfileUnlock() throws Exception {
+        assumeTrue(mHasManagedUserFeature);
+
         while (mRunner.keepRunning()) {
             mRunner.pauseTiming();
             final int userId = createManagedProfile();
@@ -289,6 +299,8 @@
     /** Tests starting (unlocking) an already-created, but no-longer-running, profile. */
     @Test
     public void managedProfileUnlock_stopped() throws Exception {
+        assumeTrue(mHasManagedUserFeature);
+
         while (mRunner.keepRunning()) {
             mRunner.pauseTiming();
             final int userId = createManagedProfile();
@@ -310,6 +322,8 @@
      */
     @Test
     public void managedProfileUnlockAndLaunchApp() throws Exception {
+        assumeTrue(mHasManagedUserFeature);
+
         while (mRunner.keepRunning()) {
             mRunner.pauseTiming();
             final int userId = createManagedProfile();
@@ -334,6 +348,8 @@
      */
     @Test
     public void managedProfileUnlockAndLaunchApp_stopped() throws Exception {
+        assumeTrue(mHasManagedUserFeature);
+
         while (mRunner.keepRunning()) {
             mRunner.pauseTiming();
             final int userId = createManagedProfile();
@@ -357,6 +373,8 @@
     /** Tests installing a pre-existing app in a newly-created profile. */
     @Test
     public void managedProfileInstall() throws Exception {
+        assumeTrue(mHasManagedUserFeature);
+
         while (mRunner.keepRunning()) {
             mRunner.pauseTiming();
             final int userId = createManagedProfile();
@@ -376,6 +394,8 @@
      */
     @Test
     public void managedProfileCreateUnlockInstallAndLaunchApp() throws Exception {
+        assumeTrue(mHasManagedUserFeature);
+
         final String packageName = "perftests.multiuser.apps.dummyapp";
         while (mRunner.keepRunning()) {
             mRunner.pauseTiming();
@@ -396,6 +416,8 @@
     /** Tests stopping a profile. */
     @Test
     public void managedProfileStopped() throws Exception {
+        assumeTrue(mHasManagedUserFeature);
+
         while (mRunner.keepRunning()) {
             mRunner.pauseTiming();
             final int userId = createManagedProfile();
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java b/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
index bec1947..525fbae 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
@@ -480,7 +480,7 @@
             pw.print(mEffectiveInteractiveState ? "ON" : "OFF");
             pw.println();
 
-            pw.print("Last screen ON : ");
+            pw.print("Last screen ON: ");
             TimeUtils.dumpTimeWithDelta(pw, now - nowRealtime + mLastScreenOnRealtime, now);
             pw.println();
 
@@ -509,9 +509,8 @@
     public void dumpProtoLocked(ProtoOutputStream proto, long tag, long now, long nowRealtime) {
         final long token = proto.start(tag);
 
-        proto.write(JobConcurrencyManagerProto.CURRENT_INTERACTIVE,
-                mCurrentInteractiveState);
-        proto.write(JobConcurrencyManagerProto.EFFECTIVE_INTERACTIVE,
+        proto.write(JobConcurrencyManagerProto.CURRENT_INTERACTIVE_STATE, mCurrentInteractiveState);
+        proto.write(JobConcurrencyManagerProto.EFFECTIVE_INTERACTIVE_STATE,
                 mEffectiveInteractiveState);
 
         proto.write(JobConcurrencyManagerProto.TIME_SINCE_LAST_SCREEN_ON_MS,
@@ -521,8 +520,9 @@
 
         mJobCountTracker.dumpProto(proto, JobConcurrencyManagerProto.JOB_COUNT_TRACKER);
 
-        proto.write(JobConcurrencyManagerProto.MEMORY_TRIM_LEVEL,
-                mLastMemoryTrimLevel);
+        proto.write(JobConcurrencyManagerProto.MEMORY_TRIM_LEVEL, mLastMemoryTrimLevel);
+
+        mStatLogger.dumpProto(proto, JobConcurrencyManagerProto.STATS);
 
         proto.end(token);
     }
@@ -676,19 +676,14 @@
                             + " Res BG: %d"
                             + " Starting: %d / %d (%d)"
                             + " Total: %d%s / %d%s (%d%s)",
-                    mConfigNumMaxTotalJobs,
-                    mConfigNumMinBgJobs,
-                    mConfigNumMaxBgJobs,
+                    mConfigNumMaxTotalJobs, mConfigNumMinBgJobs, mConfigNumMaxBgJobs,
 
-                    mNumRunningFgJobs, mNumRunningBgJobs,
-                    mNumRunningFgJobs + mNumRunningBgJobs,
+                    mNumRunningFgJobs, mNumRunningBgJobs, mNumRunningFgJobs + mNumRunningBgJobs,
 
-                    mNumPendingFgJobs, mNumPendingBgJobs,
-                    mNumPendingFgJobs + mNumPendingBgJobs,
+                    mNumPendingFgJobs, mNumPendingBgJobs, mNumPendingFgJobs + mNumPendingBgJobs,
 
                     mNumActualMaxFgJobs, (totalFg <= mConfigNumMaxTotalJobs) ? "" : "*",
                     mNumActualMaxBgJobs, (totalBg <= mConfigNumMaxBgJobs) ? "" : "*",
-
                     mNumActualMaxFgJobs + mNumActualMaxBgJobs,
                     (mNumActualMaxFgJobs + mNumActualMaxBgJobs <= mConfigNumMaxTotalJobs)
                             ? "" : "*",
@@ -716,6 +711,14 @@
             proto.write(JobCountTrackerProto.NUM_PENDING_FG_JOBS, mNumPendingFgJobs);
             proto.write(JobCountTrackerProto.NUM_PENDING_BG_JOBS, mNumPendingBgJobs);
 
+            proto.write(JobCountTrackerProto.NUM_ACTUAL_MAX_FG_JOBS, mNumActualMaxFgJobs);
+            proto.write(JobCountTrackerProto.NUM_ACTUAL_MAX_BG_JOBS, mNumActualMaxBgJobs);
+
+            proto.write(JobCountTrackerProto.NUM_RESERVED_FOR_BG, mNumReservedForBg);
+
+            proto.write(JobCountTrackerProto.NUM_STARTING_FG_JOBS, mNumStartingFgJobs);
+            proto.write(JobCountTrackerProto.NUM_STARTING_BG_JOBS, mNumStartingBgJobs);
+
             proto.end(token);
         }
     }
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 38bb75f..5ba563c 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -1943,7 +1943,7 @@
                 } catch (RemoteException e) {
                 }
                 if (mConstants.MIN_READY_NON_ACTIVE_JOBS_COUNT > 1
-                        && job.getStandbyBucket() != ACTIVE_INDEX
+                        && job.getEffectiveStandbyBucket() != ACTIVE_INDEX
                         && (job.getFirstForceBatchedTimeElapsed() == 0
                         || sElapsedRealtimeClock.millis() - job.getFirstForceBatchedTimeElapsed()
                                 < mConstants.MAX_NON_ACTIVE_JOB_BATCH_DELAY_MS)) {
@@ -3011,6 +3011,8 @@
                     pw.print(job.isReady());
                     pw.print(" user=");
                     pw.print(areUsersStartedLocked(job));
+                    pw.print(" !thermal=");
+                    pw.print(!isJobThermalConstrainedLocked(job));
                     pw.print(" !pending=");
                     pw.print(!mPendingJobs.contains(job));
                     pw.print(" !active=");
@@ -3018,15 +3020,7 @@
                     pw.print(" !backingup=");
                     pw.print(!(mBackingUpUids.indexOfKey(job.getSourceUid()) >= 0));
                     pw.print(" comp=");
-                    boolean componentPresent = false;
-                    try {
-                        componentPresent = (AppGlobals.getPackageManager().getServiceInfo(
-                                job.getServiceComponent(),
-                                PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
-                                job.getUserId()) != null);
-                    } catch (RemoteException e) {
-                    }
-                    pw.print(componentPresent);
+                    pw.print(isComponentUsable(job));
                     pw.println(")");
                 }
             } else {
@@ -3177,27 +3171,24 @@
 
                     job.dump(proto, JobSchedulerServiceDumpProto.RegisteredJob.DUMP, true, nowElapsed);
 
-                    // isReadyToBeExecuted
+                    proto.write(
+                            JobSchedulerServiceDumpProto.RegisteredJob.IS_JOB_READY_TO_BE_EXECUTED,
+                            isReadyToBeExecutedLocked(job));
                     proto.write(JobSchedulerServiceDumpProto.RegisteredJob.IS_JOB_READY,
                             job.isReady());
-                    proto.write(JobSchedulerServiceDumpProto.RegisteredJob.IS_USER_STARTED,
+                    proto.write(JobSchedulerServiceDumpProto.RegisteredJob.ARE_USERS_STARTED,
                             areUsersStartedLocked(job));
+                    proto.write(
+                            JobSchedulerServiceDumpProto.RegisteredJob.IS_JOB_THERMAL_CONSTRAINED,
+                            isJobThermalConstrainedLocked(job));
                     proto.write(JobSchedulerServiceDumpProto.RegisteredJob.IS_JOB_PENDING,
                             mPendingJobs.contains(job));
                     proto.write(JobSchedulerServiceDumpProto.RegisteredJob.IS_JOB_CURRENTLY_ACTIVE,
                             isCurrentlyActiveLocked(job));
                     proto.write(JobSchedulerServiceDumpProto.RegisteredJob.IS_UID_BACKING_UP,
                             mBackingUpUids.indexOfKey(job.getSourceUid()) >= 0);
-                    boolean componentPresent = false;
-                    try {
-                        componentPresent = (AppGlobals.getPackageManager().getServiceInfo(
-                                job.getServiceComponent(),
-                                PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
-                                job.getUserId()) != null);
-                    } catch (RemoteException e) {
-                    }
-                    proto.write(JobSchedulerServiceDumpProto.RegisteredJob.IS_COMPONENT_PRESENT,
-                            componentPresent);
+                    proto.write(JobSchedulerServiceDumpProto.RegisteredJob.IS_COMPONENT_USABLE,
+                            isComponentUsable(job));
 
                     proto.end(rjToken);
                 }
@@ -3234,7 +3225,7 @@
                 job.writeToShortProto(proto, PendingJob.INFO);
                 job.dump(proto, PendingJob.DUMP, false, nowElapsed);
                 proto.write(PendingJob.EVALUATED_PRIORITY, evaluateJobPriorityLocked(job));
-                proto.write(PendingJob.ENQUEUED_DURATION_MS, nowUptime - job.madePending);
+                proto.write(PendingJob.PENDING_DURATION_MS, nowUptime - job.madePending);
 
                 proto.end(pjToken);
             }
@@ -3283,6 +3274,8 @@
             }
             mConcurrencyManager.dumpProtoLocked(proto,
                     JobSchedulerServiceDumpProto.CONCURRENCY_MANAGER, now, nowElapsed);
+
+            mJobs.getPersistStats().writeToProto(proto, JobSchedulerServiceDumpProto.PERSIST_STATS);
         }
 
         proto.flush();
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java
index b698e5b..8b61006 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java
@@ -115,32 +115,27 @@
         final long mToken = proto.start(StateControllerProto.BACKGROUND);
 
         mAppStateTracker.dumpProto(proto,
-                StateControllerProto.BackgroundJobsController.FORCE_APP_STANDBY_TRACKER);
+                StateControllerProto.BackgroundJobsController.APP_STATE_TRACKER);
 
         mService.getJobStore().forEachJob(predicate, (jobStatus) -> {
             final long jsToken =
                     proto.start(StateControllerProto.BackgroundJobsController.TRACKED_JOBS);
 
-            jobStatus.writeToShortProto(proto,
-                    TrackedJob.INFO);
+            jobStatus.writeToShortProto(proto, TrackedJob.INFO);
             final int sourceUid = jobStatus.getSourceUid();
             proto.write(TrackedJob.SOURCE_UID, sourceUid);
             final String sourcePkg = jobStatus.getSourcePackageName();
             proto.write(TrackedJob.SOURCE_PACKAGE_NAME, sourcePkg);
 
-            proto.write(TrackedJob.IS_IN_FOREGROUND,
-                    mAppStateTracker.isUidActive(sourceUid));
+            proto.write(TrackedJob.IS_IN_FOREGROUND, mAppStateTracker.isUidActive(sourceUid));
             proto.write(TrackedJob.IS_WHITELISTED,
                     mAppStateTracker.isUidPowerSaveWhitelisted(sourceUid) ||
                     mAppStateTracker.isUidTempPowerSaveWhitelisted(sourceUid));
 
-            proto.write(
-                    TrackedJob.CAN_RUN_ANY_IN_BACKGROUND,
-                    mAppStateTracker.isRunAnyInBackgroundAppOpsAllowed(
-                            sourceUid, sourcePkg));
+            proto.write(TrackedJob.CAN_RUN_ANY_IN_BACKGROUND,
+                    mAppStateTracker.isRunAnyInBackgroundAppOpsAllowed(sourceUid, sourcePkg));
 
-            proto.write(
-                    TrackedJob.ARE_CONSTRAINTS_SATISFIED,
+            proto.write(TrackedJob.ARE_CONSTRAINTS_SATISFIED,
                     (jobStatus.satisfiedConstraints &
                             JobStatus.CONSTRAINT_BACKGROUND_NOT_RESTRICTED) != 0);
 
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
index a67aadf..43e8dfb 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
@@ -631,6 +631,18 @@
         final long token = proto.start(fieldId);
         final long mToken = proto.start(StateControllerProto.CONNECTIVITY);
 
+        for (int i = 0; i < mRequestedWhitelistJobs.size(); i++) {
+            proto.write(
+                    StateControllerProto.ConnectivityController.REQUESTED_STANDBY_EXCEPTION_UIDS,
+                    mRequestedWhitelistJobs.keyAt(i));
+        }
+        for (int i = 0; i < mAvailableNetworks.size(); i++) {
+            Network network = mAvailableNetworks.valueAt(i);
+            if (network != null) {
+                network.writeToProto(proto,
+                        StateControllerProto.ConnectivityController.AVAILABLE_NETWORKS);
+            }
+        }
         for (int i = 0; i < mTrackedJobs.size(); i++) {
             final ArraySet<JobStatus> jobs = mTrackedJobs.valueAt(i);
             for (int j = 0; j < jobs.size(); j++) {
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/DeviceIdleJobsController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/DeviceIdleJobsController.java
index 127a5c8..0b67971 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/DeviceIdleJobsController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/DeviceIdleJobsController.java
@@ -269,8 +269,7 @@
             proto.write(TrackedJob.SOURCE_UID, jobStatus.getSourceUid());
             proto.write(TrackedJob.SOURCE_PACKAGE_NAME, jobStatus.getSourcePackageName());
             proto.write(TrackedJob.ARE_CONSTRAINTS_SATISFIED,
-                    (jobStatus.satisfiedConstraints &
-                        JobStatus.CONSTRAINT_DEVICE_NOT_DOZING) != 0);
+                    (jobStatus.satisfiedConstraints & JobStatus.CONSTRAINT_DEVICE_NOT_DOZING) != 0);
             proto.write(TrackedJob.IS_DOZE_WHITELISTED, jobStatus.dozeWhitelisted);
             proto.write(TrackedJob.IS_ALLOWED_IN_DOZE, mAllowInIdleJobs.contains(jobStatus));
 
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/IdleController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/IdleController.java
index e3c311f..d355715 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/IdleController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/IdleController.java
@@ -20,7 +20,6 @@
 import android.content.pm.PackageManager;
 import android.os.UserHandle;
 import android.util.ArraySet;
-import android.util.Slog;
 import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.util.IndentingPrintWriter;
@@ -120,6 +119,7 @@
         final long mToken = proto.start(StateControllerProto.IDLE);
 
         proto.write(StateControllerProto.IdleController.IS_IDLE, mIdleTracker.isIdle());
+        mIdleTracker.dump(proto, StateControllerProto.IdleController.IDLENESS_TRACKER);
 
         for (int i = 0; i < mTrackedTasks.size(); i++) {
             final JobStatus js = mTrackedTasks.valueAt(i);
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 ae4abd6..1133f7b 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
@@ -16,6 +16,7 @@
 
 package com.android.server.job.controllers;
 
+import static com.android.server.job.JobSchedulerService.ACTIVE_INDEX;
 import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;
 
 import android.app.AppGlobals;
@@ -698,6 +699,20 @@
         return UserHandle.getUserId(callingUid);
     }
 
+    /**
+     * Returns an appropriate standby bucket for the job, taking into account any standby
+     * exemptions.
+     */
+    public int getEffectiveStandbyBucket() {
+        if (uidActive || getJob().isExemptedFromAppStandby()) {
+            // Treat these cases as if they're in the ACTIVE bucket so that they get throttled
+            // like other ACTIVE apps.
+            return ACTIVE_INDEX;
+        }
+        return getStandbyBucket();
+    }
+
+    /** Returns the real standby bucket of the job. */
     public int getStandbyBucket() {
         return standbyBucket;
     }
@@ -1591,11 +1606,14 @@
             for (int i=0; i<changedAuthorities.size(); i++) {
                 pw.print(prefix); pw.print("  "); pw.println(changedAuthorities.valueAt(i));
             }
-            if (changedUris != null) {
-                pw.print(prefix); pw.println("Changed URIs:");
-                for (int i=0; i<changedUris.size(); i++) {
-                    pw.print(prefix); pw.print("  "); pw.println(changedUris.valueAt(i));
-                }
+        }
+        if (changedUris != null) {
+            pw.print(prefix);
+            pw.println("Changed URIs:");
+            for (int i = 0; i < changedUris.size(); i++) {
+                pw.print(prefix);
+                pw.print("  ");
+                pw.println(changedUris.valueAt(i));
             }
         }
         if (network != null) {
@@ -1658,7 +1676,6 @@
         proto.write(JobStatusDumpProto.SOURCE_UID, getSourceUid());
         proto.write(JobStatusDumpProto.SOURCE_USER_ID, getSourceUserId());
         proto.write(JobStatusDumpProto.SOURCE_PACKAGE_NAME, getSourcePackageName());
-        proto.write(JobStatusDumpProto.INTERNAL_FLAGS, getInternalFlags());
 
         if (full) {
             final long jiToken = proto.start(JobStatusDumpProto.JOB_INFO);
@@ -1672,6 +1689,8 @@
             proto.write(JobStatusDumpProto.JobInfo.IS_PERSISTED, job.isPersisted());
             proto.write(JobStatusDumpProto.JobInfo.PRIORITY, job.getPriority());
             proto.write(JobStatusDumpProto.JobInfo.FLAGS, job.getFlags());
+            proto.write(JobStatusDumpProto.INTERNAL_FLAGS, getInternalFlags());
+            // Foreground exemption can be determined from internal flags value.
 
             proto.write(JobStatusDumpProto.JobInfo.REQUIRES_CHARGING, job.isRequireCharging());
             proto.write(JobStatusDumpProto.JobInfo.REQUIRES_BATTERY_NOT_LOW, job.isRequireBatteryNotLow());
@@ -1783,6 +1802,8 @@
         proto.write(JobStatusDumpProto.ImplicitConstraints.IS_NOT_DOZING, mReadyNotDozing);
         proto.write(JobStatusDumpProto.ImplicitConstraints.IS_NOT_RESTRICTED_IN_BG,
                 mReadyNotRestrictedInBg);
+        // mReadyDeadlineSatisfied isn't an implicit constraint...and can be determined from other
+        // field values.
         proto.end(icToken);
 
         if (changedAuthorities != null) {
@@ -1801,12 +1822,12 @@
             network.writeToProto(proto, JobStatusDumpProto.NETWORK);
         }
 
-        if (pendingWork != null && pendingWork.size() > 0) {
+        if (pendingWork != null) {
             for (int i = 0; i < pendingWork.size(); i++) {
                 dumpJobWorkItem(proto, JobStatusDumpProto.PENDING_WORK, pendingWork.get(i));
             }
         }
-        if (executingWork != null && executingWork.size() > 0) {
+        if (executingWork != null) {
             for (int i = 0; i < executingWork.size(); i++) {
                 dumpJobWorkItem(proto, JobStatusDumpProto.EXECUTING_WORK, executingWork.get(i));
             }
@@ -1831,6 +1852,8 @@
             proto.write(JobStatusDumpProto.TIME_UNTIL_LATEST_RUNTIME_MS,
                     latestRunTimeElapsedMillis - elapsedRealtimeMillis);
         }
+        proto.write(JobStatusDumpProto.ORIGINAL_LATEST_RUNTIME_ELAPSED,
+                mOriginalLatestRunTimeElapsedMillis);
 
         proto.write(JobStatusDumpProto.NUM_FAILURES, numFailures);
         proto.write(JobStatusDumpProto.LAST_SUCCESSFUL_RUN_TIME, mLastSuccessfulRunTime);
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
index 043cda4..831be0b 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
@@ -608,7 +608,7 @@
         final boolean isWithinQuota = isWithinQuotaLocked(jobStatus);
         setConstraintSatisfied(jobStatus, isWithinQuota);
         if (!isWithinQuota) {
-            maybeScheduleStartAlarmLocked(userId, pkgName, getEffectiveStandbyBucket(jobStatus));
+            maybeScheduleStartAlarmLocked(userId, pkgName, jobStatus.getEffectiveStandbyBucket());
         }
     }
 
@@ -719,22 +719,9 @@
         return getRemainingExecutionTimeLocked(jobStatus);
     }
 
-    /**
-     * Returns an appropriate standby bucket for the job, taking into account any standby
-     * exemptions.
-     */
-    private int getEffectiveStandbyBucket(@NonNull final JobStatus jobStatus) {
-        if (jobStatus.uidActive || jobStatus.getJob().isExemptedFromAppStandby()) {
-            // Treat these cases as if they're in the ACTIVE bucket so that they get throttled
-            // like other ACTIVE apps.
-            return ACTIVE_INDEX;
-        }
-        return jobStatus.getStandbyBucket();
-    }
-
     @VisibleForTesting
     boolean isWithinQuotaLocked(@NonNull final JobStatus jobStatus) {
-        final int standbyBucket = getEffectiveStandbyBucket(jobStatus);
+        final int standbyBucket = jobStatus.getEffectiveStandbyBucket();
         // A job is within quota if one of the following is true:
         //   1. it was started while the app was in the TOP state
         //   2. the app is currently in the foreground
@@ -784,7 +771,7 @@
     long getRemainingExecutionTimeLocked(@NonNull final JobStatus jobStatus) {
         return getRemainingExecutionTimeLocked(jobStatus.getSourceUserId(),
                 jobStatus.getSourcePackageName(),
-                getEffectiveStandbyBucket(jobStatus));
+                jobStatus.getEffectiveStandbyBucket());
     }
 
     @VisibleForTesting
@@ -1258,7 +1245,7 @@
                 // finish.
                 changed |= js.setQuotaConstraintSatisfied(true);
             } else if (realStandbyBucket != ACTIVE_INDEX
-                    && realStandbyBucket == getEffectiveStandbyBucket(js)) {
+                    && realStandbyBucket == js.getEffectiveStandbyBucket()) {
                 // An app in the ACTIVE bucket may be out of quota while the job could be in quota
                 // for some reason. Therefore, avoid setting the real value here and check each job
                 // individually.
@@ -2563,7 +2550,7 @@
                 pw.println();
 
                 pw.increaseIndent();
-                pw.print(JobStatus.bucketName(getEffectiveStandbyBucket(js)));
+                pw.print(JobStatus.bucketName(js.getEffectiveStandbyBucket()));
                 pw.print(", ");
                 if (js.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA)) {
                     pw.print("within quota");
@@ -2661,21 +2648,35 @@
                     mForegroundUids.keyAt(i));
         }
 
+        for (int i = 0; i < mUidToPackageCache.size(); ++i) {
+            final long upToken = proto.start(
+                    StateControllerProto.QuotaController.UID_TO_PACKAGE_CACHE);
+
+            final int uid = mUidToPackageCache.keyAt(i);
+            ArraySet<String> packages = mUidToPackageCache.get(uid);
+
+            proto.write(StateControllerProto.QuotaController.UidPackageMapping.UID, uid);
+            for (int j = 0; j < packages.size(); ++j) {
+                proto.write(StateControllerProto.QuotaController.UidPackageMapping.PACKAGE_NAMES,
+                        packages.valueAt(j));
+            }
+
+            proto.end(upToken);
+        }
+
         mTrackedJobs.forEach((jobs) -> {
             for (int j = 0; j < jobs.size(); j++) {
                 final JobStatus js = jobs.valueAt(j);
                 if (!predicate.test(js)) {
                     continue;
                 }
-                final long jsToken = proto.start(
-                        StateControllerProto.QuotaController.TRACKED_JOBS);
-                js.writeToShortProto(proto,
-                        StateControllerProto.QuotaController.TrackedJob.INFO);
+                final long jsToken = proto.start(StateControllerProto.QuotaController.TRACKED_JOBS);
+                js.writeToShortProto(proto, StateControllerProto.QuotaController.TrackedJob.INFO);
                 proto.write(StateControllerProto.QuotaController.TrackedJob.SOURCE_UID,
                         js.getSourceUid());
                 proto.write(
                         StateControllerProto.QuotaController.TrackedJob.EFFECTIVE_STANDBY_BUCKET,
-                        getEffectiveStandbyBucket(js));
+                        js.getEffectiveStandbyBucket());
                 proto.write(StateControllerProto.QuotaController.TrackedJob.IS_TOP_STARTED_JOB,
                         mTopStartedJobs.contains(js));
                 proto.write(StateControllerProto.QuotaController.TrackedJob.HAS_QUOTA,
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/idle/CarIdlenessTracker.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/idle/CarIdlenessTracker.java
index 82c33f5..1e5b84d 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/idle/CarIdlenessTracker.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/idle/CarIdlenessTracker.java
@@ -22,9 +22,11 @@
 import android.content.IntentFilter;
 import android.util.Log;
 import android.util.Slog;
+import android.util.proto.ProtoOutputStream;
 
 import com.android.server.am.ActivityManagerService;
 import com.android.server.job.JobSchedulerService;
+import com.android.server.job.StateControllerProto;
 
 import java.io.PrintWriter;
 
@@ -89,6 +91,22 @@
     }
 
     @Override
+    public void dump(ProtoOutputStream proto, long fieldId) {
+        final long token = proto.start(fieldId);
+        final long ciToken = proto.start(
+                StateControllerProto.IdleController.IdlenessTracker.CAR_IDLENESS_TRACKER);
+
+        proto.write(StateControllerProto.IdleController.IdlenessTracker.CarIdlenessTracker.IS_IDLE,
+                mIdle);
+        proto.write(
+                StateControllerProto.IdleController.IdlenessTracker.CarIdlenessTracker.IS_GARAGE_MODE_ON,
+                mGarageModeOn);
+
+        proto.end(ciToken);
+        proto.end(token);
+    }
+
+    @Override
     public void onReceive(Context context, Intent intent) {
         final String action = intent.getAction();
         logIfDebug("Received action: " + action);
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/idle/DeviceIdlenessTracker.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/idle/DeviceIdlenessTracker.java
index a85bd40..f74eb3b 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/idle/DeviceIdlenessTracker.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/idle/DeviceIdlenessTracker.java
@@ -23,11 +23,13 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-
 import android.util.Log;
 import android.util.Slog;
+import android.util.proto.ProtoOutputStream;
+
 import com.android.server.am.ActivityManagerService;
 import com.android.server.job.JobSchedulerService;
+import com.android.server.job.StateControllerProto;
 
 import java.io.PrintWriter;
 
@@ -101,6 +103,25 @@
     }
 
     @Override
+    public void dump(ProtoOutputStream proto, long fieldId) {
+        final long token = proto.start(fieldId);
+        final long diToken = proto.start(
+                StateControllerProto.IdleController.IdlenessTracker.DEVICE_IDLENESS_TRACKER);
+
+        proto.write(StateControllerProto.IdleController.IdlenessTracker.DeviceIdlenessTracker.IS_IDLE,
+                mIdle);
+        proto.write(
+                StateControllerProto.IdleController.IdlenessTracker.DeviceIdlenessTracker.IS_SCREEN_ON,
+                mScreenOn);
+        proto.write(
+                StateControllerProto.IdleController.IdlenessTracker.DeviceIdlenessTracker.IS_DOCK_IDLE,
+                mDockIdle);
+
+        proto.end(diToken);
+        proto.end(token);
+    }
+
+    @Override
     public void onReceive(Context context, Intent intent) {
         final String action = intent.getAction();
         if (action.equals(Intent.ACTION_SCREEN_ON)
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/idle/IdlenessTracker.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/idle/IdlenessTracker.java
index 09f01c2..cdab7e5 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/idle/IdlenessTracker.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/idle/IdlenessTracker.java
@@ -17,6 +17,7 @@
 package com.android.server.job.controllers.idle;
 
 import android.content.Context;
+import android.util.proto.ProtoOutputStream;
 
 import java.io.PrintWriter;
 
@@ -43,4 +44,9 @@
      * Dump useful information about tracked idleness-related state in plaintext.
      */
     void dump(PrintWriter pw);
+
+    /**
+     * Dump useful information about tracked idleness-related state to proto.
+     */
+    void dump(ProtoOutputStream proto, long fieldId);
 }
diff --git a/api/current.txt b/api/current.txt
index afacaa8..e11fca8 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -641,6 +641,7 @@
     field public static final int footerDividersEnabled = 16843311; // 0x101022f
     field public static final int forceDarkAllowed = 16844172; // 0x101058c
     field public static final int forceHasOverlappingRendering = 16844065; // 0x1010521
+    field public static final int forceQueryable = 16844296; // 0x1010608
     field public static final int forceUriPermissions = 16844191; // 0x101059f
     field public static final int foreground = 16843017; // 0x1010109
     field public static final int foregroundGravity = 16843264; // 0x1010200
@@ -6794,6 +6795,7 @@
     method @WorkerThread public int setGlobalPrivateDnsModeSpecifiedHost(@NonNull android.content.ComponentName, @NonNull String);
     method public void setGlobalSetting(@NonNull android.content.ComponentName, String, String);
     method public void setKeepUninstalledPackages(@Nullable android.content.ComponentName, @NonNull java.util.List<java.lang.String>);
+    method public boolean setKeyGrantForApp(@Nullable android.content.ComponentName, @NonNull String, @NonNull String, boolean);
     method public boolean setKeyPairCertificate(@Nullable android.content.ComponentName, @NonNull String, @NonNull java.util.List<java.security.cert.Certificate>, boolean);
     method public boolean setKeyguardDisabled(@NonNull android.content.ComponentName, boolean);
     method public void setKeyguardDisabledFeatures(@NonNull android.content.ComponentName, int);
@@ -9478,47 +9480,62 @@
   }
 
   public class ContentProviderOperation implements android.os.Parcelable {
-    method public android.content.ContentProviderResult apply(android.content.ContentProvider, android.content.ContentProviderResult[], int) throws android.content.OperationApplicationException;
+    method @NonNull public android.content.ContentProviderResult apply(@NonNull android.content.ContentProvider, @NonNull android.content.ContentProviderResult[], int) throws android.content.OperationApplicationException;
     method public int describeContents();
-    method public android.net.Uri getUri();
+    method @NonNull public android.net.Uri getUri();
     method public boolean isAssertQuery();
+    method public boolean isCall();
     method public boolean isDelete();
+    method public boolean isExceptionAllowed();
     method public boolean isInsert();
     method public boolean isReadOperation();
     method public boolean isUpdate();
     method public boolean isWriteOperation();
     method public boolean isYieldAllowed();
-    method public static android.content.ContentProviderOperation.Builder newAssertQuery(android.net.Uri);
-    method public static android.content.ContentProviderOperation.Builder newDelete(android.net.Uri);
-    method public static android.content.ContentProviderOperation.Builder newInsert(android.net.Uri);
-    method public static android.content.ContentProviderOperation.Builder newUpdate(android.net.Uri);
-    method public String[] resolveSelectionArgsBackReferences(android.content.ContentProviderResult[], int);
-    method public android.content.ContentValues resolveValueBackReferences(android.content.ContentProviderResult[], int);
+    method @NonNull public static android.content.ContentProviderOperation.Builder newAssertQuery(@NonNull android.net.Uri);
+    method @NonNull public static android.content.ContentProviderOperation.Builder newCall(@NonNull android.net.Uri, @Nullable String, @Nullable String);
+    method @NonNull public static android.content.ContentProviderOperation.Builder newDelete(@NonNull android.net.Uri);
+    method @NonNull public static android.content.ContentProviderOperation.Builder newInsert(@NonNull android.net.Uri);
+    method @NonNull public static android.content.ContentProviderOperation.Builder newUpdate(@NonNull android.net.Uri);
+    method @Nullable public android.os.Bundle resolveExtrasBackReferences(@NonNull android.content.ContentProviderResult[], int);
+    method @Nullable public String[] resolveSelectionArgsBackReferences(@NonNull android.content.ContentProviderResult[], int);
+    method @Nullable public android.content.ContentValues resolveValueBackReferences(@NonNull android.content.ContentProviderResult[], int);
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.content.ContentProviderOperation> CREATOR;
   }
 
   public static class ContentProviderOperation.Builder {
-    method public android.content.ContentProviderOperation build();
-    method public android.content.ContentProviderOperation.Builder withExpectedCount(int);
-    method public android.content.ContentProviderOperation.Builder withSelection(String, String[]);
-    method public android.content.ContentProviderOperation.Builder withSelectionBackReference(int, int);
-    method public android.content.ContentProviderOperation.Builder withValue(String, Object);
-    method public android.content.ContentProviderOperation.Builder withValueBackReference(String, int);
-    method public android.content.ContentProviderOperation.Builder withValueBackReferences(android.content.ContentValues);
-    method public android.content.ContentProviderOperation.Builder withValues(android.content.ContentValues);
-    method public android.content.ContentProviderOperation.Builder withYieldAllowed(boolean);
+    method @NonNull public android.content.ContentProviderOperation build();
+    method @NonNull public android.content.ContentProviderOperation.Builder withExceptionAllowed(boolean);
+    method @NonNull public android.content.ContentProviderOperation.Builder withExpectedCount(int);
+    method @NonNull public android.content.ContentProviderOperation.Builder withExtra(@NonNull String, @Nullable Object);
+    method @NonNull public android.content.ContentProviderOperation.Builder withExtraBackReference(@NonNull String, int);
+    method @NonNull public android.content.ContentProviderOperation.Builder withExtraBackReference(@NonNull String, int, @NonNull String);
+    method @NonNull public android.content.ContentProviderOperation.Builder withExtras(@NonNull android.os.Bundle);
+    method @NonNull public android.content.ContentProviderOperation.Builder withSelection(@Nullable String, @Nullable String[]);
+    method @NonNull public android.content.ContentProviderOperation.Builder withSelectionBackReference(int, int);
+    method @NonNull public android.content.ContentProviderOperation.Builder withSelectionBackReference(int, int, @NonNull String);
+    method @NonNull public android.content.ContentProviderOperation.Builder withValue(@NonNull String, @Nullable Object);
+    method @NonNull public android.content.ContentProviderOperation.Builder withValueBackReference(@NonNull String, int);
+    method @NonNull public android.content.ContentProviderOperation.Builder withValueBackReference(@NonNull String, int, @NonNull String);
+    method @NonNull public android.content.ContentProviderOperation.Builder withValueBackReferences(@NonNull android.content.ContentValues);
+    method @NonNull public android.content.ContentProviderOperation.Builder withValues(@NonNull android.content.ContentValues);
+    method @NonNull public android.content.ContentProviderOperation.Builder withYieldAllowed(boolean);
   }
 
   public class ContentProviderResult implements android.os.Parcelable {
-    ctor public ContentProviderResult(android.net.Uri);
+    ctor public ContentProviderResult(@NonNull android.net.Uri);
     ctor public ContentProviderResult(int);
+    ctor public ContentProviderResult(@NonNull android.os.Bundle);
+    ctor public ContentProviderResult(@NonNull Exception);
     ctor public ContentProviderResult(android.os.Parcel);
     method public int describeContents();
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.content.ContentProviderResult> CREATOR;
-    field public final Integer count;
-    field public final android.net.Uri uri;
+    field @Nullable public final Integer count;
+    field @Nullable public final Exception exception;
+    field @Nullable public final android.os.Bundle extras;
+    field @Nullable public final android.net.Uri uri;
   }
 
   public class ContentQueryMap extends java.util.Observable {
@@ -40628,8 +40645,9 @@
 package android.security {
 
   public final class AttestedKeyPair {
-    method public java.util.List<java.security.cert.Certificate> getAttestationRecord();
-    method public java.security.KeyPair getKeyPair();
+    ctor public AttestedKeyPair(@Nullable java.security.KeyPair, @Nullable java.security.cert.Certificate[]);
+    method @NonNull public java.util.List<java.security.cert.Certificate> getAttestationRecord();
+    method @Nullable public java.security.KeyPair getKeyPair();
   }
 
   public class ConfirmationAlreadyPresentingException extends java.lang.Exception {
@@ -73166,7 +73184,7 @@
     method public void logp(@NonNull java.util.logging.Level, @Nullable String, @Nullable String, @Nullable String);
     method public void logp(@NonNull java.util.logging.Level, @Nullable String, @Nullable String, @NonNull java.util.function.Supplier<java.lang.String>);
     method public void logp(@NonNull java.util.logging.Level, @Nullable String, @Nullable String, @Nullable String, @Nullable Object);
-    method public void logp(@NonNull java.util.logging.Level, @Nullable String, @Nullable String, @Nullable String, Object[]);
+    method public void logp(@NonNull java.util.logging.Level, @Nullable String, @Nullable String, @Nullable String, @Nullable Object[]);
     method public void logp(@NonNull java.util.logging.Level, @Nullable String, @Nullable String, @Nullable String, @Nullable Throwable);
     method public void logp(@NonNull java.util.logging.Level, @Nullable String, @Nullable String, @Nullable Throwable, @NonNull java.util.function.Supplier<java.lang.String>);
     method @Deprecated public void logrb(@NonNull java.util.logging.Level, @Nullable String, @Nullable String, @Nullable String, @Nullable String);
diff --git a/api/removed.txt b/api/removed.txt
index b075f9e..74c1d3c 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -208,7 +208,7 @@
 package android.icu.util {
 
   public class JapaneseCalendar extends android.icu.util.GregorianCalendar {
-    field public static final int CURRENT_ERA;
+    field @Deprecated public static final int CURRENT_ERA;
   }
 
 }
diff --git a/api/system-current.txt b/api/system-current.txt
index 15b694a..18e30ba 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -3693,7 +3693,7 @@
 package android.media.session {
 
   public final class MediaSessionManager {
-    method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void registerCallback(@NonNull android.media.session.MediaSessionManager.Callback, @Nullable android.os.Handler);
+    method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void registerCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.session.MediaSessionManager.Callback);
     method @RequiresPermission(android.Manifest.permission.SET_MEDIA_KEY_LISTENER) public void setOnMediaKeyListener(android.media.session.MediaSessionManager.OnMediaKeyListener, @Nullable android.os.Handler);
     method @RequiresPermission(android.Manifest.permission.SET_VOLUME_KEY_LONG_PRESS_LISTENER) public void setOnVolumeKeyLongPressListener(android.media.session.MediaSessionManager.OnVolumeKeyLongPressListener, @Nullable android.os.Handler);
     method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void unregisterCallback(@NonNull android.media.session.MediaSessionManager.Callback);
@@ -7170,6 +7170,14 @@
     field public static final String KEY_CARRIER_SETUP_APP_STRING = "carrier_setup_app_string";
   }
 
+  public static final class CarrierConfigManager.Wifi {
+    field public static final String KEY_CARRIER_CONNECTION_MANAGER_PACKAGE_STRING = "wifi.carrier_connection_manager_package_string";
+    field public static final String KEY_CARRIER_PROFILES_VERSION_INT = "wifi.carrier_profiles_version_int";
+    field public static final String KEY_NETWORK_PROFILES_STRING_ARRAY = "wifi.network_profiles_string_array";
+    field public static final String KEY_PASSPOINT_PROFILES_STRING_ARRAY = "wifi.passpoint_profiles_string_array";
+    field public static final String KEY_PREFIX = "wifi.";
+  }
+
   public final class CarrierRestrictionRules implements android.os.Parcelable {
     method @NonNull public java.util.List<java.lang.Boolean> areCarrierIdentifiersAllowed(@NonNull java.util.List<android.service.carrier.CarrierIdentifier>);
     method public int describeContents();
diff --git a/api/test-current.txt b/api/test-current.txt
index 8e6ff30..6fe79c4 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -2348,6 +2348,7 @@
     method public static android.net.Uri scanFile(android.content.Context, java.io.File);
     method public static android.net.Uri scanFileFromShell(android.content.Context, java.io.File);
     method public static void scanVolume(android.content.Context, java.io.File);
+    method public static void waitForIdle(android.content.Context);
   }
 
   public final class Settings {
@@ -2869,6 +2870,11 @@
     method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setTransportType(int);
   }
 
+  public class PhoneNumberUtils {
+    method public static int getMinMatchForTest();
+    method public static void setMinMatchForTest(int);
+  }
+
   public class ServiceState implements android.os.Parcelable {
     method public void addNetworkRegistrationInfo(android.telephony.NetworkRegistrationInfo);
     method public void setCdmaSystemAndNetworkId(int, int);
@@ -3037,6 +3043,7 @@
     field public static final String SCREENRECORD_LONG_PRESS = "settings_screenrecord_long_press";
     field public static final String SEAMLESS_TRANSFER = "settings_seamless_transfer";
     field public static final String SETTINGS_WIFITRACKER2 = "settings_wifitracker2";
+    field public static final String USE_BUGREPORT_API = "settings_use_bugreport_api";
   }
 
   public class TimeUtils {
diff --git a/cmds/idmap/scan.cpp b/cmds/idmap/scan.cpp
index d69dd79..847dda3 100644
--- a/cmds/idmap/scan.cpp
+++ b/cmds/idmap/scan.cpp
@@ -9,7 +9,6 @@
 #include <androidfw/ResourceTypes.h>
 #include <androidfw/StreamingZipInflater.h>
 #include <androidfw/ZipFileRO.h>
-#include <cutils/jstring.h>
 #include <cutils/properties.h>
 #include <private/android_filesystem_config.h> // for AID_SYSTEM
 #include <utils/SortedVector.h>
@@ -84,15 +83,9 @@
     }
 
     bool check_property(String16 property, String16 value) {
-        const char *prop;
-        const char *val;
-
-        prop = strndup16to8(property.string(), property.size());
         char propBuf[PROPERTY_VALUE_MAX];
-        property_get(prop, propBuf, NULL);
-        val = strndup16to8(value.string(), value.size());
-
-        return (strcmp(propBuf, val) == 0);
+        property_get(String8(property).c_str(), propBuf, NULL);
+        return String8(value) == propBuf;
     }
 
     int parse_overlay_tag(const ResXMLTree& parser, const char *target_package_name,
diff --git a/config/boot-profile.txt b/config/boot-profile.txt
index e69de29..57e06c2 100644
--- a/config/boot-profile.txt
+++ b/config/boot-profile.txt
@@ -0,0 +1,642 @@
+Lcom/android/internal/os/RuntimeInit$MethodAndArgsCaller;->run()V
+Lcom/android/internal/os/ZygoteInit;->main([Ljava/lang/String;)V
+Lcom/android/internal/util/ConcurrentUtils$1$1;->run()V
+Lcom/android/server/SystemConfig;->getInstance()Lcom/android/server/SystemConfig;
+Lcom/android/server/SystemConfig;-><init>()V
+Lcom/android/server/SystemConfig;->readPermissions(Ljava/io/File;I)V
+Lcom/android/server/SystemConfig;->readPermissionsFromXml(Ljava/io/File;I)V
+Lcom/android/internal/os/ProcessCpuTracker;->update()V
+Lcom/android/internal/os/ProcessCpuTracker;->init()V
+Lcom/android/internal/os/ProcessCpuTracker;->collectStats(Ljava/lang/String;IZ[ILjava/util/ArrayList;)[I
+Landroid/content/pm/PackageParser$SigningDetails$Builder;->build()Landroid/content/pm/PackageParser$SigningDetails;
+Landroid/content/pm/PackageParser$SigningDetails;-><init>(Landroid/content/pm/PackageParser$SigningDetails;)V
+Landroid/content/pm/PackageParser$SigningDetails;-><init>([Landroid/content/pm/Signature;I)V
+Landroid/content/pm/PackageParser$SigningDetails;-><init>([Landroid/content/pm/Signature;ILandroid/util/ArraySet;[Landroid/content/pm/Signature;)V
+Landroid/content/pm/PackageParser$SigningDetails;-><init>([Landroid/content/pm/Signature;I[Landroid/content/pm/Signature;)V
+Landroid/util/ArrayMap;->get(Ljava/lang/Object;)Ljava/lang/Object;
+Landroid/util/ArrayMap;->indexOfKey(Ljava/lang/Object;)I
+Landroid/content/pm/Signature;->getPublicKey()Ljava/security/PublicKey;
+Landroid/util/ArrayMap;->indexOf(Ljava/lang/Object;I)I
+Landroid/util/ArrayMap;->indexOfNull()I
+Landroid/util/ArrayMap;->indexOfValue(Ljava/lang/Object;)I
+Lcom/android/internal/os/ProcessCpuTracker;->getName(Lcom/android/internal/os/ProcessCpuTracker$Stats;Ljava/lang/String;)V
+Lcom/android/internal/os/ProcStatsUtil;->readTerminatedProcFile(Ljava/lang/String;B)Ljava/lang/String;
+Lcom/android/internal/os/BatteryStatsImpl;->writeAsyncLocked()V
+Lcom/android/internal/os/BatteryStatsImpl;->writeStatsLocked(Z)V
+Lcom/android/internal/os/BatteryStatsImpl;->writeSummaryToParcel(Landroid/os/Parcel;Z)V
+Landroid/util/SparseArray;->get(I)Ljava/lang/Object;
+Landroid/util/SparseArray;->get(ILjava/lang/Object;)Ljava/lang/Object;
+Lcom/android/internal/os/BatteryStatsImpl;->readLocked()V
+Lcom/android/internal/os/BatteryStatsImpl;->readSummaryFromParcel(Landroid/os/Parcel;)V
+Landroid/util/ArrayMap;->binarySearchHashes([III)I
+Landroid/util/ContainerHelpers;->binarySearch([III)I
+Lcom/android/internal/os/BatteryStatsImpl;->updateCpuTimeLocked(ZZ)V
+Lcom/android/internal/os/KernelCpuUidTimeReader;->readDelta(Lcom/android/internal/os/KernelCpuUidTimeReader$Callback;)V
+Landroid/util/ArrayMap;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+Landroid/util/ArrayMap;->putAll(Landroid/util/ArrayMap;)V
+Landroid/util/ArrayMap;->putAll(Ljava/util/Map;)V
+Landroid/util/SparseArray;-><init>()V
+Landroid/util/SparseArray;-><init>(I)V
+Lcom/android/internal/os/KernelCpuUidTimeReader$KernelCpuUidFreqTimeReader;->readDeltaImpl(Lcom/android/internal/os/KernelCpuUidTimeReader$Callback;)V
+Lcom/android/server/SystemConfig;->readPrivAppPermissions(Lorg/xmlpull/v1/XmlPullParser;Landroid/util/ArrayMap;Landroid/util/ArrayMap;)V
+Landroid/content/pm/Signature;-><init>(Ljava/lang/String;)V
+Landroid/content/pm/Signature;-><init>([B)V
+Landroid/content/pm/Signature;-><init>([Ljava/security/cert/Certificate;)V
+Lcom/android/internal/os/ProcessCpuTracker$Stats;-><init>(IIZ)V
+Lcom/android/internal/os/KernelCpuProcStringReader;->asLongs(Ljava/nio/CharBuffer;[J)I
+Lcom/android/internal/util/XmlUtils;->nextElement(Lorg/xmlpull/v1/XmlPullParser;)V
+Lcom/android/internal/util/XmlUtils;->nextElementWithin(Lorg/xmlpull/v1/XmlPullParser;I)Z
+Lcom/android/internal/util/ArrayUtils;->newUnpaddedObjectArray(I)[Ljava/lang/Object;
+Landroid/util/SparseArray;->put(ILjava/lang/Object;)V
+Lcom/android/internal/os/BatteryStatsImpl;->updateKernelWakelocksLocked()V
+Landroid/util/ArraySet;->add(Ljava/lang/Object;)Z
+Landroid/util/ArraySet;->addAll(Landroid/util/ArraySet;)V
+Landroid/util/ArraySet;->addAll(Ljava/util/Collection;)Z
+Lcom/android/internal/os/KernelWakelockReader;->readKernelWakelockStats(Lcom/android/internal/os/KernelWakelockStats;)Lcom/android/internal/os/KernelWakelockStats;
+Lcom/android/internal/util/GrowingArrayUtils;->insert([IIII)[I
+Lcom/android/internal/util/GrowingArrayUtils;->insert([JIIJ)[J
+Lcom/android/internal/util/GrowingArrayUtils;->insert([Ljava/lang/Object;IILjava/lang/Object;)[Ljava/lang/Object;
+Lcom/android/internal/util/GrowingArrayUtils;->insert([ZIIZ)[Z
+HPLcom/android/internal/app/procstats/ProcessStats;-><init>(Landroid/os/Parcel;)V
+Lcom/android/internal/app/procstats/ProcessStats;-><init>(Z)V
+Lcom/android/internal/os/BatteryStatsImpl$Uid;-><init>(Lcom/android/internal/os/BatteryStatsImpl;I)V
+Lcom/android/internal/os/KernelWakelockReader;->parseProcWakelocks([BIZLcom/android/internal/os/KernelWakelockStats;)Lcom/android/internal/os/KernelWakelockStats;
+Landroid/content/pm/PackageParser;->getCachedResult(Ljava/io/File;I)Landroid/content/pm/PackageParser$Package;
+Landroid/content/pm/PackageParser;->parsePackage(Ljava/io/File;I)Landroid/content/pm/PackageParser$Package;
+Landroid/content/pm/PackageParser;->parsePackage(Ljava/io/File;IZ)Landroid/content/pm/PackageParser$Package;
+Landroid/content/pm/PackageParser;->parsePackageItemInfo(Landroid/content/pm/PackageParser$Package;Landroid/content/pm/PackageItemInfo;[Ljava/lang/String;Ljava/lang/String;Landroid/content/res/TypedArray;ZIIIIII)Z
+Landroid/content/pm/PackageParser;->parsePackageList(Ljava/lang/String;)Ljava/util/Set;
+Landroid/content/pm/PackageParser;->parsePackageLite(Ljava/io/File;I)Landroid/content/pm/PackageParser$PackageLite;
+Landroid/content/pm/PackageParser;->parsePackageSplitNames(Lorg/xmlpull/v1/XmlPullParser;Landroid/util/AttributeSet;)Landroid/util/Pair;
+Lcom/android/internal/os/BatteryStatsImpl$DualTimer;->writeSummaryFromParcelLocked(Landroid/os/Parcel;J)V
+Landroid/content/pm/Signature;->parseHexDigit(I)I
+Lcom/android/internal/os/BatteryStatsImpl$DurationTimer;->writeSummaryFromParcelLocked(Landroid/os/Parcel;J)V
+Lcom/android/internal/os/BatteryStatsImpl$Uid;->readWakeSummaryFromParcelLocked(Ljava/lang/String;Landroid/os/Parcel;)V
+Landroid/util/ArraySet;->iterator()Ljava/util/Iterator;
+Landroid/content/pm/PackageParser;->fromCacheEntryStatic([B)Landroid/content/pm/PackageParser$Package;
+Landroid/content/pm/PackageParser;->fromCacheEntry([B)Landroid/content/pm/PackageParser$Package;
+Lcom/android/internal/os/BatteryStatsImpl$Timer;->writeSummaryFromParcelLocked(Landroid/os/Parcel;J)V
+Lcom/android/internal/os/KernelCpuUidTimeReader$KernelCpuUidUserSysTimeReader;->readDeltaImpl(Lcom/android/internal/os/KernelCpuUidTimeReader$Callback;)V
+Landroid/os/FileUtils;->bytesToFile(Ljava/lang/String;[B)V
+Landroid/os/StrictMode;->allowThreadDiskReads()Landroid/os/StrictMode$ThreadPolicy;
+Landroid/os/StrictMode;->allowThreadDiskReadsMask()I
+Landroid/content/pm/PackageParser$Package;-><init>(Landroid/os/Parcel;)V
+Landroid/content/pm/PackageParser$Package;-><init>(Ljava/lang/String;)V
+Lcom/android/server/SystemConfig;->addFeature(Ljava/lang/String;I)V
+Landroid/os/StrictMode;->setThreadPolicy(Landroid/os/StrictMode$ThreadPolicy;)V
+Landroid/os/StrictMode;->setThreadPolicyMask(I)V
+Landroid/content/pm/FallbackCategoryProvider;->loadFallbacks()V
+Landroid/os/Parcel$ReadWriteHelper;->writeString(Landroid/os/Parcel;Ljava/lang/String;)V
+Landroid/os/Parcel;->writeString(Ljava/lang/String;)V
+Landroid/os/Parcel;->writeStringArray([Ljava/lang/String;)V
+Landroid/os/Parcel;->writeStringList(Ljava/util/List;)V
+Lcom/android/internal/os/BatteryStatsImpl$Timer;-><init>(Lcom/android/internal/os/BatteryStatsImpl$Clocks;ILcom/android/internal/os/BatteryStatsImpl$TimeBase;)V
+Lcom/android/internal/os/BatteryStatsImpl$Timer;-><init>(Lcom/android/internal/os/BatteryStatsImpl$Clocks;ILcom/android/internal/os/BatteryStatsImpl$TimeBase;Landroid/os/Parcel;)V
+Lcom/android/internal/os/BatteryStatsImpl$TimeBase;->add(Lcom/android/internal/os/BatteryStatsImpl$TimeBaseObs;)V
+Landroid/os/Parcel;->writeInt(I)V
+Landroid/os/Parcel;->writeIntArray([I)V
+Landroid/os/Parcel;->writeInterfaceToken(Ljava/lang/String;)V
+Landroid/content/pm/PackageParser;->parsePublicKey(Ljava/lang/String;)Ljava/security/PublicKey;
+Lcom/android/internal/os/KernelCpuProcStringReader$ProcFileIterator;->nextLine()Ljava/nio/CharBuffer;
+Landroid/util/Xml;->newPullParser()Lorg/xmlpull/v1/XmlPullParser;
+Lcom/android/internal/os/KernelCpuUidTimeReader$KernelCpuUidFreqTimeReader;->readFreqs(Lcom/android/internal/os/PowerProfile;)[J
+Lcom/android/internal/os/KernelCpuUidTimeReader$KernelCpuUidFreqTimeReader;->readFreqs(Ljava/lang/String;)[J
+Lcom/android/internal/os/BatteryStatsImpl$StopwatchTimer;-><init>(Lcom/android/internal/os/BatteryStatsImpl$Clocks;Lcom/android/internal/os/BatteryStatsImpl$Uid;ILjava/util/ArrayList;Lcom/android/internal/os/BatteryStatsImpl$TimeBase;)V
+Lcom/android/internal/os/BatteryStatsImpl$StopwatchTimer;-><init>(Lcom/android/internal/os/BatteryStatsImpl$Clocks;Lcom/android/internal/os/BatteryStatsImpl$Uid;ILjava/util/ArrayList;Lcom/android/internal/os/BatteryStatsImpl$TimeBase;Landroid/os/Parcel;)V
+Landroid/os/HandlerThread;->run()V
+Landroid/os/Looper;->loop()V
+Landroid/util/SparseArray;->size()I
+Landroid/util/ArrayMap;-><init>()V
+Landroid/util/ArrayMap;-><init>(I)V
+Landroid/util/ArrayMap;-><init>(IZ)V
+Landroid/util/ArrayMap;-><init>(Landroid/util/ArrayMap;)V
+Landroid/os/Parcel;->writeLong(J)V
+Landroid/os/Parcel;->writeLongArray([J)V
+Landroid/os/Parcel;->readParcelable(Ljava/lang/ClassLoader;)Landroid/os/Parcelable;
+Landroid/os/Parcel;->readParcelableArray(Ljava/lang/ClassLoader;Ljava/lang/Class;)[Landroid/os/Parcelable;
+Landroid/os/Parcel;->readParcelableCreator(Ljava/lang/ClassLoader;)Landroid/os/Parcelable$Creator;
+Landroid/os/Parcel;->readParcelableList(Ljava/util/List;Ljava/lang/ClassLoader;)Ljava/util/List;
+Lcom/android/internal/os/BatteryStatsImpl$DualTimer;-><init>(Lcom/android/internal/os/BatteryStatsImpl$Clocks;Lcom/android/internal/os/BatteryStatsImpl$Uid;ILjava/util/ArrayList;Lcom/android/internal/os/BatteryStatsImpl$TimeBase;Lcom/android/internal/os/BatteryStatsImpl$TimeBase;Landroid/os/Parcel;)V
+Landroid/os/SystemProperties;->getBoolean(Ljava/lang/String;Z)Z
+Landroid/content/pm/IntentFilterVerificationInfo;-><init>(Lorg/xmlpull/v1/XmlPullParser;)V
+Landroid/util/ArrayMap;->allocArrays(I)V
+Landroid/os/Parcel;->readInt()I
+Landroid/os/Parcel;->readIntArray([I)V
+Landroid/content/pm/IntentFilterVerificationInfo;->readFromXml(Lorg/xmlpull/v1/XmlPullParser;)V
+Lcom/android/internal/util/ArrayUtils;->appendInt([II)[I
+Lcom/android/internal/util/ArrayUtils;->appendInt([IIZ)[I
+Landroid/util/TimingsTraceLog;->traceEnd()V
+Lcom/android/internal/os/BatteryStatsImpl$Timer;->readSummaryFromParcelLocked(Landroid/os/Parcel;)V
+Lcom/android/internal/os/BatteryStatsImpl$DurationTimer;->readSummaryFromParcelLocked(Landroid/os/Parcel;)V
+Landroid/os/Parcel;->readString()Ljava/lang/String;
+Landroid/os/Parcel;->readStringArray()[Ljava/lang/String;
+Landroid/os/Parcel;->readStringList(Ljava/util/List;)V
+Lcom/android/internal/os/BatteryStatsImpl$OverflowArrayMap;->add(Ljava/lang/String;Ljava/lang/Object;)V
+Lcom/android/internal/os/BatteryStatsImpl;->getKernelWakelockTimerLocked(Ljava/lang/String;)Lcom/android/internal/os/BatteryStatsImpl$SamplingTimer;
+Lcom/android/internal/os/BatteryStatsImpl$DurationTimer;-><init>(Lcom/android/internal/os/BatteryStatsImpl$Clocks;Lcom/android/internal/os/BatteryStatsImpl$Uid;ILjava/util/ArrayList;Lcom/android/internal/os/BatteryStatsImpl$TimeBase;Landroid/os/Parcel;)V
+Lcom/android/internal/os/BatteryStatsImpl$DualTimer;->readSummaryFromParcelLocked(Landroid/os/Parcel;)V
+Landroid/os/storage/StorageManager;->hasAdoptable()Z
+Landroid/os/Parcel$ReadWriteHelper;->readString(Landroid/os/Parcel;)Ljava/lang/String;
+Landroid/os/Handler;->dispatchMessage(Landroid/os/Message;)V
+Lcom/android/internal/os/BatteryStatsImpl$5;->run()V
+Lcom/android/internal/os/BatteryStatsImpl;->commitPendingDataToDisk(Landroid/os/Parcel;Lcom/android/internal/os/AtomicFile;)V
+Lcom/android/internal/os/BatteryStatsImpl$StopwatchTimer;->readSummaryFromParcelLocked(Landroid/os/Parcel;)V
+Landroid/util/ArraySet;->indexOf(Ljava/lang/Object;)I
+Landroid/util/ArraySet;->indexOf(Ljava/lang/Object;I)I
+Landroid/util/ArraySet;->indexOfNull()I
+Landroid/os/Parcel;->readLong()J
+Landroid/os/Parcel;->readLongArray([J)V
+Lcom/android/internal/util/XmlUtils;->skipCurrentTag(Lorg/xmlpull/v1/XmlPullParser;)V
+Lcom/android/internal/os/BatteryStatsImpl$Uid;->getServiceStatsLocked(Ljava/lang/String;Ljava/lang/String;)Lcom/android/internal/os/BatteryStatsImpl$Uid$Pkg$Serv;
+Landroid/os/StrictMode;->setBlockGuardPolicy(I)V
+Landroid/util/TimingsTraceLog;->logDuration(Ljava/lang/String;J)V
+Landroid/util/Base64;->decode(Ljava/lang/String;I)[B
+Landroid/util/Base64;->decode([BI)[B
+Landroid/util/Base64;->decode([BIII)[B
+Landroid/util/ArrayMap;->valueAt(I)Ljava/lang/Object;
+Lcom/android/internal/os/BatteryStatsImpl$Uid;->getWakelockTimerLocked(Lcom/android/internal/os/BatteryStatsImpl$Uid$Wakelock;I)Lcom/android/internal/os/BatteryStatsImpl$StopwatchTimer;
+Landroid/util/ArraySet;-><init>()V
+Landroid/util/ArraySet;-><init>(I)V
+Landroid/util/ArraySet;-><init>(Landroid/util/ArraySet;)V
+Landroid/util/ArraySet;-><init>(Ljava/util/Collection;)V
+Lcom/android/internal/os/KernelCpuProcStringReader;->open(Z)Lcom/android/internal/os/KernelCpuProcStringReader$ProcFileIterator;
+Landroid/content/pm/ApplicationInfo;-><init>()V
+Landroid/content/pm/ApplicationInfo;-><init>(Landroid/content/pm/ApplicationInfo;)V
+Landroid/content/pm/ApplicationInfo;-><init>(Landroid/os/Parcel;)V
+Landroid/util/ArraySet;->remove(Ljava/lang/Object;)Z
+Landroid/util/ArraySet;->removeAll(Ljava/util/Collection;)Z
+Landroid/util/ArraySet;->removeAt(I)Ljava/lang/Object;
+Landroid/util/ArraySet;->removeAll(Landroid/util/ArraySet;)Z
+Landroid/content/pm/ApplicationInfo$1;->createFromParcel(Landroid/os/Parcel;)Landroid/content/pm/ApplicationInfo;
+Landroid/content/pm/ApplicationInfo$1;->createFromParcel(Landroid/os/Parcel;)Ljava/lang/Object;
+Landroid/os/ServiceManagerProxy;->addService(Ljava/lang/String;Landroid/os/IBinder;ZI)V
+Lcom/android/internal/os/PowerProfile;-><init>(Landroid/content/Context;)V
+Lcom/android/internal/os/PowerProfile;-><init>(Landroid/content/Context;Z)V
+Lcom/android/internal/os/BatteryStatsImpl$SamplingTimer;-><init>(Lcom/android/internal/os/BatteryStatsImpl$Clocks;Lcom/android/internal/os/BatteryStatsImpl$TimeBase;Landroid/os/Parcel;)V
+Landroid/os/ServiceManager;->addService(Ljava/lang/String;Landroid/os/IBinder;)V
+Landroid/os/ServiceManager;->addService(Ljava/lang/String;Landroid/os/IBinder;ZI)V
+Lcom/android/internal/os/PowerProfile;->readPowerValuesFromXml(Landroid/content/Context;Z)V
+Lcom/android/server/SystemConfig;->readPermission(Lorg/xmlpull/v1/XmlPullParser;Ljava/lang/String;)V
+Landroid/content/res/ResourcesImpl;-><init>(Landroid/content/res/AssetManager;Landroid/util/DisplayMetrics;Landroid/content/res/Configuration;Landroid/view/DisplayAdjustments;)V
+Landroid/os/ServiceManager;->getService(Ljava/lang/String;)Landroid/os/IBinder;
+Landroid/os/ServiceManager;->getServiceOrThrow(Ljava/lang/String;)Landroid/os/IBinder;
+Landroid/util/Base64$Decoder;->process([BIIZ)Z
+Lcom/android/internal/util/XmlUtils;->readLongAttribute(Lorg/xmlpull/v1/XmlPullParser;Ljava/lang/String;)J
+Lcom/android/internal/util/XmlUtils;->readLongAttribute(Lorg/xmlpull/v1/XmlPullParser;Ljava/lang/String;J)J
+Lcom/android/internal/os/BatteryStatsImpl$Uid;->getPackageStatsLocked(Ljava/lang/String;)Lcom/android/internal/os/BatteryStatsImpl$Uid$Pkg;
+Lcom/android/internal/app/procstats/ProcessStats;->resetCommon()V
+HPLcom/android/internal/app/procstats/ProcessStats;->resetSafely()V
+Landroid/content/res/ResourcesImpl;->updateConfiguration(Landroid/content/res/Configuration;Landroid/util/DisplayMetrics;Landroid/content/res/CompatibilityInfo;)V
+Landroid/content/res/Resources;-><init>()V
+Landroid/content/res/Resources;-><init>(Landroid/content/res/AssetManager;Landroid/util/DisplayMetrics;Landroid/content/res/Configuration;)V
+Landroid/content/res/Resources;-><init>(Ljava/lang/ClassLoader;)V
+Landroid/os/ServiceManager;->rawGetService(Ljava/lang/String;)Landroid/os/IBinder;
+Landroid/util/LongSparseArray;->put(JLjava/lang/Object;)V
+Landroid/util/ArrayMap;->freeArrays([I[Ljava/lang/Object;I)V
+Landroid/util/ArrayMap;->keyAt(I)Ljava/lang/Object;
+Landroid/content/pm/PackageParser$Activity$1;->createFromParcel(Landroid/os/Parcel;)Landroid/content/pm/PackageParser$Activity;
+Landroid/content/pm/PackageParser$Activity$1;->createFromParcel(Landroid/os/Parcel;)Ljava/lang/Object;
+Landroid/content/pm/PackageParser$Activity;-><init>(Landroid/content/pm/PackageParser$ParseComponentArgs;Landroid/content/pm/ActivityInfo;)V
+Landroid/content/pm/PackageParser$Activity;-><init>(Landroid/os/Parcel;)V
+Landroid/content/res/AssetManager;->setConfiguration(IILjava/lang/String;IIIIIIIIIIIIIII)V
+Lcom/android/internal/os/BatteryStatsImpl$Counter;-><init>(Lcom/android/internal/os/BatteryStatsImpl$TimeBase;)V
+Lcom/android/internal/os/BatteryStatsImpl$Counter;-><init>(Lcom/android/internal/os/BatteryStatsImpl$TimeBase;Landroid/os/Parcel;)V
+Landroid/util/ArraySet;->allocArrays(I)V
+Landroid/os/storage/StorageManager;->isFileEncryptedNativeOnly()Z
+Lcom/android/internal/os/BatteryStatsImpl$Counter;->writeSummaryFromParcelLocked(Landroid/os/Parcel;)V
+Lcom/android/internal/os/BatteryStatsImpl;->updateRailStatsLocked()V
+Landroid/os/ServiceManagerProxy;->getService(Ljava/lang/String;)Landroid/os/IBinder;
+Landroid/util/SparseIntArray;-><init>()V
+Landroid/util/SparseIntArray;-><init>(I)V
+Lcom/android/internal/util/XmlUtils;->readIntAttribute(Lorg/xmlpull/v1/XmlPullParser;Ljava/lang/String;)I
+Lcom/android/internal/util/XmlUtils;->readIntAttribute(Lorg/xmlpull/v1/XmlPullParser;Ljava/lang/String;I)I
+Lcom/android/internal/os/BatteryStatsImpl$LongSamplingCounter;-><init>(Lcom/android/internal/os/BatteryStatsImpl$TimeBase;)V
+Lcom/android/internal/os/BatteryStatsImpl$LongSamplingCounter;-><init>(Lcom/android/internal/os/BatteryStatsImpl$TimeBase;Landroid/os/Parcel;)V
+Lcom/android/internal/os/BatteryStatsImpl;-><init>(Lcom/android/internal/os/BatteryStatsImpl$Clocks;Landroid/os/Parcel;)V
+Lcom/android/internal/os/BatteryStatsImpl;-><init>(Lcom/android/internal/os/BatteryStatsImpl$Clocks;Ljava/io/File;Landroid/os/Handler;Lcom/android/internal/os/BatteryStatsImpl$PlatformIdleStateCallback;Lcom/android/internal/os/BatteryStatsImpl$RailEnergyDataCallback;Lcom/android/internal/os/BatteryStatsImpl$UserInfoProvider;)V
+Lcom/android/internal/os/BatteryStatsImpl;-><init>(Ljava/io/File;Landroid/os/Handler;Lcom/android/internal/os/BatteryStatsImpl$PlatformIdleStateCallback;Lcom/android/internal/os/BatteryStatsImpl$RailEnergyDataCallback;Lcom/android/internal/os/BatteryStatsImpl$UserInfoProvider;)V
+Lcom/android/internal/os/BatteryStatsImpl$Uid;->readJobSummaryFromParcelLocked(Ljava/lang/String;Landroid/os/Parcel;)V
+Lcom/android/internal/app/procstats/ProcessStats;->updateFragmentation()V
+Landroid/os/Parcel;->readTypedObject(Landroid/os/Parcelable$Creator;)Ljava/lang/Object;
+Lcom/android/internal/os/BatteryStatsImpl$DurationTimer;->getTotalDurationMsLocked(J)J
+Landroid/os/Parcel;->createTypedArray(Landroid/os/Parcelable$Creator;)[Ljava/lang/Object;
+Landroid/os/Parcel;->createTypedArrayList(Landroid/os/Parcelable$Creator;)Ljava/util/ArrayList;
+Landroid/os/Parcel;->createTypedArrayMap(Landroid/os/Parcelable$Creator;)Landroid/util/ArrayMap;
+Landroid/content/pm/PackageParserCacheHelper$ReadHelper;->readString(Landroid/os/Parcel;)Ljava/lang/String;
+Lcom/android/server/LocalServices;->addService(Ljava/lang/Class;Ljava/lang/Object;)V
+Landroid/util/Slog;->d(Ljava/lang/String;Ljava/lang/String;)I
+Landroid/util/TimingsTraceLog;->traceBegin(Ljava/lang/String;)V
+Landroid/content/res/AssetManager;-><init>()V
+Landroid/content/res/AssetManager;->getResourceValue(IILandroid/util/TypedValue;Z)Z
+Landroid/util/LongSparseLongArray;->put(JJ)V
+Lcom/android/internal/os/BatteryStatsImpl$SystemClocks;->uptimeMillis()J
+Landroid/content/res/AssetManager;->setApkAssets([Landroid/content/res/ApkAssets;Z)V
+Lcom/android/internal/os/BatteryStatsImpl$LongSamplingCounterArray;->readSummaryFromParcelLocked(Landroid/os/Parcel;Lcom/android/internal/os/BatteryStatsImpl$TimeBase;)Lcom/android/internal/os/BatteryStatsImpl$LongSamplingCounterArray;
+Lcom/android/internal/util/XmlUtils;->readBooleanAttribute(Lorg/xmlpull/v1/XmlPullParser;Ljava/lang/String;)Z
+Lcom/android/internal/util/XmlUtils;->readBooleanAttribute(Lorg/xmlpull/v1/XmlPullParser;Ljava/lang/String;Z)Z
+Landroid/os/StrictMode$ThreadPolicy;-><init>(ILandroid/os/StrictMode$OnThreadViolationListener;Ljava/util/concurrent/Executor;)V
+Lcom/android/internal/os/KernelCpuSpeedReader;->readDelta()[J
+Lcom/android/internal/os/AtomicFile;->startWrite()Ljava/io/FileOutputStream;
+Landroid/app/ContextImpl;->createSystemUiContext(Landroid/app/ContextImpl;I)Landroid/app/ContextImpl;
+Landroid/app/ActivityThread;->getSystemUiContext()Landroid/app/ContextImpl;
+Landroid/os/Parcel;->recycle()V
+Landroid/util/Slog;->i(Ljava/lang/String;Ljava/lang/String;)I
+Landroid/os/Binder;-><init>()V
+Landroid/os/Binder;-><init>(Ljava/lang/String;)V
+Landroid/content/Context;->getSystemService(Ljava/lang/Class;)Ljava/lang/Object;
+Lcom/android/internal/util/ArrayUtils;->newUnpaddedLongArray(I)[J
+Landroid/content/res/ResourcesImpl;->getValue(ILandroid/util/TypedValue;Z)V
+Landroid/content/res/ResourcesImpl;->getValueForDensity(IILandroid/util/TypedValue;Z)V
+Landroid/util/LongSparseLongArray;-><init>()V
+Landroid/util/LongSparseLongArray;-><init>(I)V
+Landroid/os/BatteryStats$Timer;-><init>()V
+Lcom/android/internal/os/BatteryStatsImpl$Uid;->createAggregatedPartialWakelockTimerLocked()Lcom/android/internal/os/BatteryStatsImpl$DualTimer;
+Lcom/android/internal/os/BatteryStatsImpl$LongSamplingCounterArray;->access$2300(Lcom/android/internal/os/BatteryStatsImpl$LongSamplingCounterArray;Landroid/os/Parcel;)V
+Lcom/android/internal/os/BatteryStatsImpl$Uid;->readJobCompletionsFromParcelLocked(Landroid/os/Parcel;)V
+Landroid/util/MapCollections$KeySet;->iterator()Ljava/util/Iterator;
+Landroid/text/TextUtils;->isEmpty(Ljava/lang/CharSequence;)Z
+Lcom/android/internal/os/BatteryStatsImpl$TimeBase;->writeSummaryToParcel(Landroid/os/Parcel;JJ)V
+Lcom/android/internal/os/BatteryStatsImpl$StopwatchTimer;->computeRunTimeLocked(J)J
+Landroid/bluetooth/BluetoothAdapter;->getDefaultAdapter()Landroid/bluetooth/BluetoothAdapter;
+Landroid/content/pm/PackageParserCacheHelper$ReadHelper;->startAndInstall()V
+Landroid/content/pm/PackageItemInfo;-><init>(Landroid/content/pm/PackageItemInfo;)V
+Landroid/content/pm/PackageItemInfo;-><init>(Landroid/os/Parcel;)V
+Landroid/content/pm/ActivityInfo;-><init>()V
+Landroid/content/pm/ActivityInfo;-><init>(Landroid/content/pm/ActivityInfo;)V
+Landroid/content/pm/ActivityInfo;-><init>(Landroid/os/Parcel;)V
+Landroid/content/pm/ActivityInfo$1;->createFromParcel(Landroid/os/Parcel;)Landroid/content/pm/ActivityInfo;
+Landroid/content/pm/ActivityInfo$1;->createFromParcel(Landroid/os/Parcel;)Ljava/lang/Object;
+Landroid/os/BinderProxy;->transact(ILandroid/os/Parcel;Landroid/os/Parcel;I)Z
+Landroid/os/HandlerThread;->getLooper()Landroid/os/Looper;
+Landroid/os/FileUtils;->$closeResource(Ljava/lang/Throwable;Ljava/lang/AutoCloseable;)V
+Landroid/os/SystemProperties;->digestOf([Ljava/lang/String;)Ljava/lang/String;
+Lcom/android/internal/util/ArrayUtils;->isEmpty(Ljava/util/Collection;)Z
+Lcom/android/internal/util/ArrayUtils;->isEmpty([Ljava/lang/Object;)Z
+Landroid/util/AtomicFile;-><init>(Ljava/io/File;)V
+Landroid/util/AtomicFile;-><init>(Ljava/io/File;Ljava/lang/String;)V
+Landroid/util/LongSparseArray;-><init>()V
+Landroid/util/LongSparseArray;-><init>(I)V
+Landroid/content/res/Resources;->obtainTypedArray(I)Landroid/content/res/TypedArray;
+Landroid/util/AtomicFile;->openRead()Ljava/io/FileInputStream;
+Lcom/android/internal/os/BatteryStatsImpl$TimeBase;-><init>(Z)V
+Lcom/android/internal/os/BatteryStatsImpl$Counter;->readSummaryFromParcelLocked(Landroid/os/Parcel;)V
+Lcom/android/internal/os/BatteryStatsImpl$Uid;->makeProcessState(ILandroid/os/Parcel;)V
+Lcom/android/internal/os/BatteryStatsImpl$Uid$3;->instantiateObject()Lcom/android/internal/os/BatteryStatsImpl$DualTimer;
+Lcom/android/internal/os/BatteryStatsImpl$Uid$3;->instantiateObject()Ljava/lang/Object;
+Landroid/content/pm/PackageUserState;-><init>()V
+Landroid/app/ActivityManager;->isLowRamDeviceStatic()Z
+Lcom/android/internal/os/KernelCpuUidTimeReader$KernelCpuUidActiveTimeReader;->readDeltaImpl(Lcom/android/internal/os/KernelCpuUidTimeReader$Callback;)V
+Lcom/android/internal/os/BatteryStatsImpl;->updateRpmStatsLocked()V
+Lcom/android/internal/os/BatteryStatsImpl$LongSamplingCounter;->writeSummaryFromParcelLocked(Landroid/os/Parcel;)V
+Lcom/android/internal/os/KernelMemoryBandwidthStats;->updateStats()V
+Landroid/content/pm/PackageParser;->isCacheUpToDate(Ljava/io/File;Ljava/io/File;)Z
+Landroid/os/StrictMode;->initThreadDefaults(Landroid/content/pm/ApplicationInfo;)V
+Landroid/app/ResourcesManager;->getOrCreateResources(Landroid/os/IBinder;Landroid/content/res/ResourcesKey;Ljava/lang/ClassLoader;)Landroid/content/res/Resources;
+Landroid/app/ResourcesManager;->getOrCreateResourcesForActivityLocked(Landroid/os/IBinder;Ljava/lang/ClassLoader;Landroid/content/res/ResourcesImpl;Landroid/content/res/CompatibilityInfo;)Landroid/content/res/Resources;
+Landroid/app/ResourcesManager;->getOrCreateResourcesLocked(Ljava/lang/ClassLoader;Landroid/content/res/ResourcesImpl;Landroid/content/res/CompatibilityInfo;)Landroid/content/res/Resources;
+Landroid/app/ResourcesManager;->getResources(Landroid/os/IBinder;Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;ILandroid/content/res/Configuration;Landroid/content/res/CompatibilityInfo;Ljava/lang/ClassLoader;)Landroid/content/res/Resources;
+Landroid/app/ContextImpl;->createResources(Landroid/os/IBinder;Landroid/app/LoadedApk;Ljava/lang/String;ILandroid/content/res/Configuration;Landroid/content/res/CompatibilityInfo;[Ljava/lang/String;)Landroid/content/res/Resources;
+Landroid/app/ContextImpl;->createResources(Landroid/os/IBinder;Landroid/app/LoadedApk;Ljava/lang/String;ILandroid/content/res/Configuration;Landroid/content/res/CompatibilityInfo;)Landroid/content/res/Resources;
+Landroid/app/ContextImpl;->getSystemService(Ljava/lang/String;)Ljava/lang/Object;
+Landroid/app/ContextImpl;->getSystemServiceName(Ljava/lang/Class;)Ljava/lang/String;
+Landroid/app/SystemServiceRegistry$CachedServiceFetcher;->getService(Landroid/app/ContextImpl;)Ljava/lang/Object;
+Landroid/util/TimingsTraceLog;->assertSameThread()V
+Landroid/os/HandlerThread;-><init>(Ljava/lang/String;)V
+Landroid/os/HandlerThread;-><init>(Ljava/lang/String;I)V
+Lcom/android/internal/util/ArrayUtils;->newUnpaddedIntArray(I)[I
+Landroid/content/res/Configuration;-><init>()V
+Landroid/content/res/Configuration;-><init>(Landroid/content/res/Configuration;)V
+Landroid/view/SurfaceControl;->getInternalDisplayToken()Landroid/os/IBinder;
+Landroid/view/SurfaceControl;->getPhysicalDisplayToken(J)Landroid/os/IBinder;
+Landroid/content/res/Resources;->getInteger(I)I
+Landroid/os/Handler;->sendMessageAtTime(Landroid/os/Message;J)Z
+Lcom/android/internal/os/BatteryStatsImpl$TimeBase;->init(JJ)V
+Lcom/android/internal/os/BatteryStatsImpl$TimeBase;->readSummaryFromParcel(Landroid/os/Parcel;)V
+Lcom/android/internal/os/BatteryStatsImpl$Uid$Pkg;-><init>(Lcom/android/internal/os/BatteryStatsImpl;)V
+Landroid/util/ArraySet;->freeArrays([I[Ljava/lang/Object;I)V
+Landroid/util/ArrayMap;->entrySet()Ljava/util/Set;
+Lcom/android/internal/os/KernelCpuUidTimeReader$KernelCpuUidClusterTimeReader;->readDeltaImpl(Lcom/android/internal/os/KernelCpuUidTimeReader$Callback;)V
+Landroid/telephony/TelephonyManager;->getITelephony()Lcom/android/internal/telephony/ITelephony;
+Landroid/telephony/TelephonyManager;->requestModemActivityInfo(Landroid/os/ResultReceiver;)V
+Lcom/android/internal/os/BatteryStatsImpl$DurationTimer;->getMaxDurationMsLocked(J)J
+Lcom/android/internal/os/BatteryStatsImpl$SamplingTimer;->endSample()V
+Lcom/android/internal/os/BatteryStatsImpl;->updateKernelMemoryBandwidthLocked()V
+Landroid/content/pm/ComponentInfo;-><init>()V
+Landroid/content/pm/ComponentInfo;-><init>(Landroid/content/pm/ComponentInfo;)V
+Landroid/content/pm/ComponentInfo;-><init>(Landroid/os/Parcel;)V
+Landroid/view/SurfaceControl;->getDisplayConfigs(Landroid/os/IBinder;)[Landroid/view/SurfaceControl$PhysicalDisplayInfo;
+Lcom/android/internal/os/AtomicFile;->finishWrite(Ljava/io/FileOutputStream;)V
+Landroid/app/ResourcesManager;->createResourcesImpl(Landroid/content/res/ResourcesKey;)Landroid/content/res/ResourcesImpl;
+Landroid/app/ContextImpl;->updateDisplay(I)V
+Landroid/hardware/display/DisplayManagerGlobal;->getInstance()Landroid/hardware/display/DisplayManagerGlobal;
+Landroid/app/ResourcesManager;->getAdjustedDisplay(ILandroid/content/res/Resources;)Landroid/view/Display;
+Landroid/app/ResourcesManager;->getAdjustedDisplay(ILandroid/view/DisplayAdjustments;)Landroid/view/Display;
+Landroid/os/Parcel;->readStrongBinder()Landroid/os/IBinder;
+Landroid/app/ContextImpl;->setTheme(I)V
+Landroid/content/IntentFilter;->readFromXml(Lorg/xmlpull/v1/XmlPullParser;)V
+Landroid/text/TextUtils;->getLayoutDirectionFromLocale(Ljava/util/Locale;)I
+Landroid/os/Handler;-><init>()V
+Landroid/os/Handler;-><init>(Landroid/os/Handler$Callback;)V
+Landroid/os/Handler;-><init>(Landroid/os/Handler$Callback;Z)V
+Landroid/os/Handler;-><init>(Landroid/os/Looper;)V
+Landroid/os/Handler;-><init>(Landroid/os/Looper;Landroid/os/Handler$Callback;)V
+Landroid/os/Handler;-><init>(Landroid/os/Looper;Landroid/os/Handler$Callback;Z)V
+Landroid/os/Handler;-><init>(Z)V
+Landroid/os/Binder;->queryLocalInterface(Ljava/lang/String;)Landroid/os/IInterface;
+Landroid/content/pm/PackageParser;->isApkFile(Ljava/io/File;)Z
+Landroid/util/SparseIntArray;->put(II)V
+Landroid/content/pm/ApplicationInfo;->initForUser(I)V
+Landroid/os/BinderProxy;->getInstance(JJ)Landroid/os/BinderProxy;
+Landroid/content/pm/IntentFilterVerificationInfo;->getStringFromXml(Lorg/xmlpull/v1/XmlPullParser;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
+Landroid/app/SystemServiceRegistry$35;->createService(Landroid/app/ContextImpl;)Landroid/os/PowerManager;
+Landroid/app/SystemServiceRegistry$35;->createService(Landroid/app/ContextImpl;)Ljava/lang/Object;
+Landroid/util/ArrayMap;->containsKey(Ljava/lang/Object;)Z
+Landroid/app/WindowConfiguration;->setToDefaults()V
+Lcom/android/internal/util/MemInfoReader;->readMemInfo()V
+Landroid/util/LongSparseArray;->get(J)Ljava/lang/Object;
+Landroid/util/LongSparseArray;->get(JLjava/lang/Object;)Ljava/lang/Object;
+Landroid/util/Spline;->createSpline([F[F)Landroid/util/Spline;
+Landroid/os/PowerManager;->getDefaultScreenBrightnessSetting()I
+Landroid/view/Display;-><init>(Landroid/hardware/display/DisplayManagerGlobal;ILandroid/view/DisplayInfo;Landroid/content/res/Resources;)V
+Landroid/view/Display;-><init>(Landroid/hardware/display/DisplayManagerGlobal;ILandroid/view/DisplayInfo;Landroid/view/DisplayAdjustments;)V
+Landroid/view/Display;-><init>(Landroid/hardware/display/DisplayManagerGlobal;ILandroid/view/DisplayInfo;Landroid/view/DisplayAdjustments;Landroid/content/res/Resources;)V
+Landroid/net/Uri;->withAppendedPath(Landroid/net/Uri;Ljava/lang/String;)Landroid/net/Uri;
+Landroid/content/res/TypedArray;->obtain(Landroid/content/res/Resources;I)Landroid/content/res/TypedArray;
+Landroid/provider/Settings$System;->getUriFor(Ljava/lang/String;)Landroid/net/Uri;
+Landroid/util/MapCollections$ArrayIterator;->next()Ljava/lang/Object;
+Landroid/view/DisplayAdjustments;-><init>()V
+Landroid/view/DisplayAdjustments;-><init>(Landroid/content/res/Configuration;)V
+Landroid/view/DisplayAdjustments;-><init>(Landroid/view/DisplayAdjustments;)V
+Landroid/hardware/display/DisplayManager;->getOrCreateDisplayLocked(IZ)Landroid/view/Display;
+Landroid/content/res/Resources;->getIntArray(I)[I
+Landroid/content/res/StringBlock;->get(I)Ljava/lang/CharSequence;
+Landroid/content/res/XmlBlock$Parser;->getText()Ljava/lang/String;
+Lcom/android/internal/os/BatteryStatsImpl$LongSamplingCounter;->readSummaryFromParcelLocked(Landroid/os/Parcel;)V
+Lcom/android/internal/os/BatteryStatsImpl$Uid$Wakelock;-><init>(Lcom/android/internal/os/BatteryStatsImpl;Lcom/android/internal/os/BatteryStatsImpl$Uid;)V
+Lcom/android/internal/os/BatteryStatsImpl$Uid;->readSyncSummaryFromParcelLocked(Ljava/lang/String;Landroid/os/Parcel;)V
+Landroid/hardware/display/DisplayManagerGlobal;->getDisplayInfo(I)Landroid/view/DisplayInfo;
+Landroid/os/FileUtils;->readTextFile(Ljava/io/File;ILjava/lang/String;)Ljava/lang/String;
+Lcom/android/internal/app/procstats/ProcessStats;->buildTimePeriodStartClockStr()V
+Landroid/text/format/DateFormat;->format(Ljava/lang/CharSequence;J)Ljava/lang/CharSequence;
+Landroid/text/format/DateFormat;->format(Ljava/lang/CharSequence;Ljava/util/Calendar;)Ljava/lang/CharSequence;
+Landroid/text/format/DateFormat;->format(Ljava/lang/CharSequence;Ljava/util/Date;)Ljava/lang/CharSequence;
+Landroid/telephony/TelephonyManager;->from(Landroid/content/Context;)Landroid/telephony/TelephonyManager;
+Lcom/android/internal/os/BatteryStatsImpl$TimeBase;->getRealtime(J)J
+Lcom/android/internal/os/BatteryStatsImpl$LongSamplingCounterArray;->writeSummaryToParcelLocked(Landroid/os/Parcel;Lcom/android/internal/os/BatteryStatsImpl$LongSamplingCounterArray;)V
+Lcom/android/internal/os/BatteryStatsImpl$LongSamplingCounterArray;->access$2600(Lcom/android/internal/os/BatteryStatsImpl$LongSamplingCounterArray;Landroid/os/Parcel;)V
+Landroid/os/Parcel;->unmarshall([BII)V
+Landroid/content/pm/PackageParser$Package;->fixupOwner(Ljava/util/List;)V
+Landroid/content/res/Resources;->getBoolean(I)Z
+Landroid/content/res/AssetManager;->getResourceText(I)Ljava/lang/CharSequence;
+Landroid/content/res/AssetManager;->getResourceTextArray(I)[Ljava/lang/CharSequence;
+Landroid/content/res/Resources;->getText(I)Ljava/lang/CharSequence;
+HPLandroid/content/res/Resources;->getText(ILjava/lang/CharSequence;)Ljava/lang/CharSequence;
+Landroid/content/res/Resources;->getTextArray(I)[Ljava/lang/CharSequence;
+Landroid/os/MessageQueue;->next()Landroid/os/Message;
+Landroid/os/Parcel;->marshall()[B
+Lcom/android/internal/logging/EventLogTags;->writeCommitSysConfigFile(Ljava/lang/String;J)V
+Landroid/os/ThreadLocalWorkSource;->restore(J)V
+Landroid/os/Looper;->prepare()V
+Landroid/os/Looper;->prepareMainLooper()V
+Lcom/android/internal/app/procstats/ProcessStats;->splitAndParseNumbers(Ljava/lang/String;)[I
+Landroid/os/Trace;->traceEnd(J)V
+Landroid/os/Parcel;->readExceptionCode()I
+Landroid/os/Parcel;->readException()V
+Landroid/os/Parcel;->readException(ILjava/lang/String;)V
+Lcom/android/internal/util/StatLogger;->logDurationStat(IJ)J
+Landroid/content/res/ResourcesImpl$ThemeImpl;->applyStyle(IZ)V
+Landroid/content/res/Resources$Theme;->applyStyle(IZ)V
+Landroid/content/res/AssetManager;->applyStyleToTheme(JIZ)V
+Landroid/os/Trace;->isTagEnabled(J)Z
+Lcom/android/internal/util/ArrayUtils;->containsAll([Ljava/lang/Object;[Ljava/lang/Object;)Z
+Landroid/os/Trace;->traceBegin(JLjava/lang/String;)V
+Landroid/hardware/display/DisplayManager;-><init>(Landroid/content/Context;)V
+Landroid/os/Bundle;-><init>()V
+Landroid/os/Bundle;-><init>(I)V
+Landroid/os/Bundle;-><init>(Landroid/os/Bundle;)V
+Landroid/os/Bundle;-><init>(Landroid/os/PersistableBundle;)V
+Landroid/content/pm/PackageBackwardCompatibility;->updatePackage(Landroid/content/pm/PackageParser$Package;)V
+Landroid/content/pm/PackageBackwardCompatibility;->modifySharedLibraries(Landroid/content/pm/PackageParser$Package;)V
+Landroid/content/pm/Signature;->areExactMatch([Landroid/content/pm/Signature;[Landroid/content/pm/Signature;)Z
+Lcom/android/internal/util/ArrayUtils;->contains(Ljava/util/Collection;Ljava/lang/Object;)Z
+Lcom/android/internal/util/ArrayUtils;->contains([II)Z
+Lcom/android/internal/util/ArrayUtils;->contains([Ljava/lang/Object;Ljava/lang/Object;)Z
+Lcom/android/internal/util/ConcurrentUtils$1;->newThread(Ljava/lang/Runnable;)Ljava/lang/Thread;
+Landroid/os/PowerManager;-><init>(Landroid/content/Context;Landroid/os/IPowerManager;Landroid/os/Handler;)V
+Landroid/content/res/AssetManager;->getResourceArray(I[I)I
+Landroid/content/res/AssetManager;->getResourceArraySize(I)I
+Landroid/app/WindowConfiguration;-><init>()V
+Landroid/view/SurfaceControl;->getPhysicalDisplayIds()[J
+Lcom/android/internal/os/BackgroundThread;->getHandler()Landroid/os/Handler;
+Landroid/net/Uri$StringUri;->buildUpon()Landroid/net/Uri$Builder;
+Lcom/android/internal/os/AtomicFile;->readFully()[B
+Lcom/android/internal/util/ArrayUtils;->indexOf([Ljava/lang/Object;Ljava/lang/Object;)I
+Landroid/content/res/ResourcesImpl;->loadXmlResourceParser(Ljava/lang/String;IILjava/lang/String;)Landroid/content/res/XmlResourceParser;
+Landroid/content/res/Resources;->loadXmlResourceParser(ILjava/lang/String;)Landroid/content/res/XmlResourceParser;
+Landroid/content/res/Resources;->getXml(I)Landroid/content/res/XmlResourceParser;
+Landroid/content/res/XmlBlock$Parser;->next()I
+Landroid/content/res/XmlBlock$Parser;->nextTag()I
+Landroid/content/res/XmlBlock$Parser;->nextText()Ljava/lang/String;
+Lcom/google/android/collect/Sets;->newArraySet()Landroid/util/ArraySet;
+Lcom/google/android/collect/Sets;->newArraySet([Ljava/lang/Object;)Landroid/util/ArraySet;
+Landroid/util/ArraySet;->contains(Ljava/lang/Object;)Z
+Lcom/android/internal/os/BatteryStatsImpl$Uid;->getSensorTimerLocked(IZ)Lcom/android/internal/os/BatteryStatsImpl$DualTimer;
+Landroid/content/pm/PackageParser$SigningDetails;->hasCertificate(Landroid/content/pm/Signature;)Z
+Landroid/content/pm/PackageParser$SigningDetails;->hasCertificateInternal(Landroid/content/pm/Signature;I)Z
+Landroid/content/res/XmlBlock$Parser;->getAttributeValue(I)Ljava/lang/String;
+Landroid/content/res/XmlBlock$Parser;->getAttributeValue(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
+Lcom/android/internal/os/BatteryStatsImpl;->detachIfNotNull(Lcom/android/internal/os/BatteryStatsImpl$TimeBaseObs;)V
+Lcom/android/internal/os/BatteryStatsImpl;->detachIfNotNull([Lcom/android/internal/os/BatteryStatsImpl$TimeBaseObs;)V
+Lcom/android/internal/os/BatteryStatsImpl;->detachIfNotNull([[Lcom/android/internal/os/BatteryStatsImpl$TimeBaseObs;)V
+Landroid/util/Spline$MonotoneCubicSpline;-><init>([F[F)V
+Landroid/content/res/Configuration;->setTo(Landroid/content/res/Configuration;)V
+Landroid/content/res/Configuration;->setToDefaults()V
+Lcom/android/server/SystemConfig;->readSplitPermission(Lorg/xmlpull/v1/XmlPullParser;Ljava/io/File;)V
+Lcom/android/internal/os/RpmStats;->getSubsystem(Ljava/lang/String;)Lcom/android/internal/os/RpmStats$PowerStateSubsystem;
+Lcom/android/internal/os/BatteryStatsImpl$TimeBase;->computeRealtime(JI)J
+Landroid/os/Parcel;->dataPosition()I
+Lcom/android/internal/os/BatteryStatsImpl$DurationTimer;->getCurrentDurationMsLocked(J)J
+Lcom/android/internal/os/KernelCpuUidTimeReader$KernelCpuUidFreqTimeReader;->checkPrecondition(Lcom/android/internal/os/KernelCpuProcStringReader$ProcFileIterator;)Z
+Lcom/android/internal/os/BatteryStatsImpl$SamplingTimer;->computeRunTimeLocked(J)J
+Lcom/android/internal/os/BatteryStatsImpl$SamplingTimer;->computeCurrentCountLocked()I
+Lcom/android/internal/os/KernelMemoryBandwidthStats;->parseStats(Ljava/io/BufferedReader;)V
+Landroid/util/MapCollections;->getEntrySet()Ljava/util/Set;
+Landroid/util/MapCollections$EntrySet;->iterator()Ljava/util/Iterator;
+Lcom/android/internal/os/BatteryStatsImpl$Uid;->writeJobCompletionsToParcelLocked(Landroid/os/Parcel;)V
+Landroid/os/Parcel;->readBundle()Landroid/os/Bundle;
+Landroid/os/Parcel;->readBundle(Ljava/lang/ClassLoader;)Landroid/os/Bundle;
+Landroid/content/res/Resources;->getString(I)Ljava/lang/String;
+Landroid/content/res/Resources;->getString(I[Ljava/lang/Object;)Ljava/lang/String;
+Landroid/content/res/Resources;->getStringArray(I)[Ljava/lang/String;
+Landroid/os/ThreadLocalWorkSource;->setUid(I)J
+Landroid/content/pm/PackageParser;->parseClusterPackage(Ljava/io/File;I)Landroid/content/pm/PackageParser$Package;
+Landroid/content/pm/PackageParser;->parseClusterPackageLite(Ljava/io/File;I)Landroid/content/pm/PackageParser$PackageLite;
+Landroid/content/pm/split/DefaultSplitAssetLoader;->getBaseAssetManager()Landroid/content/res/AssetManager;
+Landroid/content/pm/PackageParser;->parseBaseApk(Ljava/io/File;Landroid/content/res/AssetManager;I)Landroid/content/pm/PackageParser$Package;
+Landroid/content/pm/PackageParser;->parseBaseApk(Ljava/lang/String;Landroid/content/res/Resources;Landroid/content/res/XmlResourceParser;I[Ljava/lang/String;)Landroid/content/pm/PackageParser$Package;
+Landroid/content/pm/PackageParser;->parseBaseApkCommon(Landroid/content/pm/PackageParser$Package;Ljava/util/Set;Landroid/content/res/Resources;Landroid/content/res/XmlResourceParser;I[Ljava/lang/String;)Landroid/content/pm/PackageParser$Package;
+Landroid/content/pm/PackageParser;->cacheResult(Ljava/io/File;ILandroid/content/pm/PackageParser$Package;)V
+Landroid/content/pm/PackageParser;->parseMonolithicPackage(Ljava/io/File;I)Landroid/content/pm/PackageParser$Package;
+Landroid/content/pm/PackageParser;->parseMonolithicPackageLite(Ljava/io/File;I)Landroid/content/pm/PackageParser$PackageLite;
+Landroid/content/pm/PackageParser;->parseApkLite(Ljava/io/File;I)Landroid/content/pm/PackageParser$ApkLite;
+Landroid/content/pm/PackageParser;->parseApkLite(Ljava/lang/String;Lorg/xmlpull/v1/XmlPullParser;Landroid/util/AttributeSet;Landroid/content/pm/PackageParser$SigningDetails;)Landroid/content/pm/PackageParser$ApkLite;
+Landroid/content/pm/PackageParser;->parseApkLiteInner(Ljava/io/File;Ljava/io/FileDescriptor;Ljava/lang/String;I)Landroid/content/pm/PackageParser$ApkLite;
+Landroid/content/pm/PackageParser;->toCacheEntry(Landroid/content/pm/PackageParser$Package;)[B
+Landroid/content/pm/PackageParser;->parseBaseApplication(Landroid/content/pm/PackageParser$Package;Landroid/content/res/Resources;Landroid/content/res/XmlResourceParser;I[Ljava/lang/String;)Z
+Landroid/os/Parcel;->writeParcelable(Landroid/os/Parcelable;I)V
+Landroid/os/Parcel;->writeParcelableArray([Landroid/os/Parcelable;I)V
+Landroid/os/Parcel;->writeParcelableCreator(Landroid/os/Parcelable;)V
+Landroid/os/Parcel;->writeParcelableList(Ljava/util/List;I)V
+Landroid/content/pm/PackageParser$Package;->writeToParcel(Landroid/os/Parcel;I)V
+Landroid/content/res/Resources;->obtainAttributes(Landroid/util/AttributeSet;[I)Landroid/content/res/TypedArray;
+Landroid/content/res/Resources;->obtainAttributes(Landroid/content/res/Resources;Landroid/content/res/Resources$Theme;Landroid/util/AttributeSet;[I)Landroid/content/res/TypedArray;
+Landroid/content/pm/split/DefaultSplitAssetLoader;->close()V
+Landroid/content/res/AssetManager;->openXmlResourceParser(ILjava/lang/String;)Landroid/content/res/XmlResourceParser;
+Landroid/content/res/AssetManager;->close()V
+Landroid/content/res/AssetManager;->openXmlBlockAsset(ILjava/lang/String;)Landroid/content/res/XmlBlock;
+Landroid/content/pm/PackageParser;->generateAppDetailsHiddenActivity(Landroid/content/pm/PackageParser$Package;I[Ljava/lang/String;Z)Landroid/content/pm/PackageParser$Activity;
+Landroid/content/pm/split/DefaultSplitAssetLoader;->loadApkAssets(Ljava/lang/String;I)Landroid/content/res/ApkAssets;
+Landroid/content/pm/PackageParser$Activity;->writeToParcel(Landroid/os/Parcel;I)V
+Landroid/os/FileUtils;->trimFilename(Ljava/lang/StringBuilder;I)V
+Landroid/content/res/ApkAssets;->openXml(Ljava/lang/String;)Landroid/content/res/XmlResourceParser;
+Landroid/content/res/Configuration;->setLocales(Landroid/os/LocaleList;)V
+Landroid/content/pm/PackageParser;->buildTaskAffinityName(Ljava/lang/String;Ljava/lang/String;Ljava/lang/CharSequence;[Ljava/lang/String;)Ljava/lang/String;
+Landroid/content/res/AssetManager;->retrieveAttributes(Landroid/content/res/XmlBlock$Parser;[I[I[I)Z
+Landroid/content/pm/PackageParser;->buildCompoundName(Ljava/lang/String;Ljava/lang/CharSequence;Ljava/lang/String;[Ljava/lang/String;)Ljava/lang/String;
+Landroid/content/pm/ActivityInfo;->writeToParcel(Landroid/os/Parcel;I)V
+Landroid/content/res/XmlBlock$Parser;->close()V
+Landroid/content/pm/PackageParser;->validateName(Ljava/lang/String;ZZ)Ljava/lang/String;
+Landroid/util/ArraySet;->equals(Ljava/lang/Object;)Z
+Landroid/content/pm/PackageItemInfo;->writeToParcel(Landroid/os/Parcel;I)V
+Landroid/content/pm/PackageParserCacheHelper$WriteHelper;->finishAndUninstall()V
+Landroid/content/res/TypedArray;->loadStringValueAt(I)Ljava/lang/CharSequence;
+Landroid/content/pm/ApplicationInfo;->writeToParcel(Landroid/os/Parcel;I)V
+Landroid/os/FileUtils;->isValidExtFilename(Ljava/lang/String;)Z
+Landroid/content/res/AssetManager;->findCookieForPath(Ljava/lang/String;)I
+Landroid/content/res/TypedArray;->getNonConfigurationString(II)Ljava/lang/String;
+Landroid/content/res/TypedArray;->peekValue(I)Landroid/util/TypedValue;
+Landroid/app/ActivityThread;->attach(ZJ)V
+Landroid/content/res/TypedArray;->getValueAt(ILandroid/util/TypedValue;)Z
+Landroid/content/res/XmlBlock$Parser;->getAttributeName(I)Ljava/lang/String;
+Landroid/content/res/XmlBlock$Parser;->getAttributeNameResource(I)I
+Landroid/content/pm/PackageParser$ApkLite;-><init>(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZLjava/lang/String;Ljava/lang/String;ZIIIILjava/util/List;Landroid/content/pm/PackageParser$SigningDetails;ZZZZZZZII)V
+Landroid/app/ResourcesManager;->createAssetManager(Landroid/content/res/ResourcesKey;)Landroid/content/res/AssetManager;
+Landroid/content/res/AssetManager$Builder;->build()Landroid/content/res/AssetManager;
+Landroid/os/FileUtils;->deleteContents(Ljava/io/File;)Z
+Landroid/os/FileUtils;->deleteContentsAndDir(Ljava/io/File;)Z
+Landroid/content/res/ResourcesImpl;->adjustLanguageTag(Ljava/lang/String;)Ljava/lang/String;
+Landroid/sysprop/DisplayProperties;->tryParseBoolean(Ljava/lang/String;)Ljava/lang/Boolean;
+Landroid/content/pm/PackageParserCacheHelper$WriteHelper;-><init>(Landroid/os/Parcel;)V
+Landroid/content/pm/PackageParser$Package;->getLongVersionCode()J
+Lcom/android/internal/util/function/pooled/OmniFunction;->run()V
+Lcom/android/internal/util/function/pooled/PooledLambdaImpl;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+Landroid/os/SystemProperties;->get(Ljava/lang/String;)Ljava/lang/String;
+Landroid/os/SystemProperties;->get(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
+Landroid/os/SystemProperties;->getInt(Ljava/lang/String;I)I
+Landroid/os/SystemProperties;->getLong(Ljava/lang/String;J)J
+Landroid/content/res/ThemedResourceCache;->onConfigurationChange(I)V
+Landroid/content/res/TypedArray;->recycle()V
+Landroid/content/res/Configuration;->fixUpLocaleList()V
+Landroid/content/res/XmlBlock;->newParser(I)Landroid/content/res/XmlResourceParser;
+Landroid/content/pm/ComponentInfo;->writeToParcel(Landroid/os/Parcel;I)V
+Landroid/content/res/ApkAssets;->getAssetPath()Ljava/lang/String;
+Landroid/util/MapCollections$MapIterator;->next()Ljava/lang/Object;
+Landroid/content/res/ResourcesImpl;->flushLayoutCache()V
+Landroid/os/FileUtils;->buildValidExtFilename(Ljava/lang/String;)Ljava/lang/String;
+Landroid/content/res/ApkAssets;->getStringFromPool(I)Ljava/lang/CharSequence;
+Landroid/content/pm/Signature;->equals(Ljava/lang/Object;)Z
+Landroid/content/pm/PackageUserState;->equals(Ljava/lang/Object;)Z
+Landroid/util/ArrayMap$1;->colGetEntry(II)Ljava/lang/Object;
+Lcom/android/internal/os/BackgroundThread;->ensureThreadLocked()V
+Landroid/app/ActivityThread;-><init>()V
+Landroid/app/ActivityThread;->getSystemContext()Landroid/app/ContextImpl;
+Landroid/app/ContextImpl;->createSystemContext(Landroid/app/ActivityThread;)Landroid/app/ContextImpl;
+Landroid/app/ContextImpl;-><init>(Landroid/app/ContextImpl;Landroid/app/ActivityThread;Landroid/app/LoadedApk;Ljava/lang/String;Landroid/os/IBinder;Landroid/os/UserHandle;ILjava/lang/ClassLoader;Ljava/lang/String;)V
+Landroid/app/ResourcesManager;->getDisplayMetrics()Landroid/util/DisplayMetrics;
+Landroid/app/ResourcesManager;->getDisplayMetrics(ILandroid/view/DisplayAdjustments;)Landroid/util/DisplayMetrics;
+Landroid/content/pm/PackageParser$Package;->setApplicationVolumeUuid(Ljava/lang/String;)V
+Landroid/content/pm/AndroidHidlUpdater;->updatePackage(Landroid/content/pm/PackageParser$Package;)V
+Landroid/content/res/ApkAssets;->close()V
+Landroid/content/res/XmlBlock$Parser;->getAttributeBooleanValue(IZ)Z
+Landroid/content/res/XmlBlock$Parser;->getAttributeBooleanValue(Ljava/lang/String;Ljava/lang/String;Z)Z
+Landroid/content/pm/PackageParser;->setMaxAspectRatio(Landroid/content/pm/PackageParser$Package;)V
+Landroid/content/pm/PackageParserCacheHelper$WriteHelper;->writeString(Landroid/os/Parcel;Ljava/lang/String;)V
+Landroid/os/Parcel;->writeTypedList(Ljava/util/List;)V
+Landroid/os/Parcel;->writeTypedList(Ljava/util/List;I)V
+Landroid/content/res/Configuration;->getLocales()Landroid/os/LocaleList;
+Landroid/view/DisplayEventReceiver;-><init>(Landroid/os/Looper;I)V
+Lcom/android/internal/util/function/pooled/PooledLambdaImpl;->doInvoke()Ljava/lang/Object;
+Landroid/content/pm/PackageSharedLibraryUpdater;->prefixImplicitDependency(Landroid/content/pm/PackageParser$Package;Ljava/lang/String;Ljava/lang/String;)V
+Landroid/util/MapCollections$MapIterator;->getKey()Ljava/lang/Object;
+Landroid/util/MapCollections$ValuesCollection;->iterator()Ljava/util/Iterator;
+Lcom/android/internal/os/BatteryStatsImpl$SystemClocks;->elapsedRealtime()J
+Landroid/app/LoadedApk;->makeApplication(ZLandroid/app/Instrumentation;)Landroid/app/Application;
+Landroid/content/pm/IntentFilterVerificationInfo;->getIntFromXml(Lorg/xmlpull/v1/XmlPullParser;Ljava/lang/String;I)I
+Landroid/content/res/ResourcesImpl;->calcConfigChanges(Landroid/content/res/Configuration;)I
+Landroid/content/pm/PackageBackwardCompatibility$AndroidTestRunnerSplitUpdater;->updatePackage(Landroid/content/pm/PackageParser$Package;)V
+Landroid/util/SparseArray;->valueAt(I)Ljava/lang/Object;
+Landroid/util/ArraySet;->ensureCapacity(I)V
+Landroid/os/storage/StorageManager;->convert(Ljava/lang/String;)Ljava/util/UUID;
+Landroid/os/storage/StorageManager;->convert(Ljava/util/UUID;)Ljava/lang/String;
+Landroid/content/pm/PackageParser;->checkOverlayRequiredSystemProperty(Ljava/lang/String;Ljava/lang/String;)Z
+Landroid/content/res/ThemedResourceCache;->prune(I)Z
+Landroid/content/res/ThemedResourceCache;->pruneEntriesLocked(Landroid/util/LongSparseArray;I)Z
+Landroid/util/Pools$SynchronizedPool;->acquire()Ljava/lang/Object;
+Landroid/content/res/XmlBlock$Parser;->getAttributeCount()I
+Landroid/content/pm/PackageParser;->parseMetaData(Landroid/content/res/Resources;Landroid/content/res/XmlResourceParser;Landroid/os/Bundle;[Ljava/lang/String;)Landroid/os/Bundle;
+Landroid/content/res/Resources;->getDisplayMetrics()Landroid/util/DisplayMetrics;
+Landroid/text/TextUtils;->writeToParcel(Ljava/lang/CharSequence;Landroid/os/Parcel;I)V
+Landroid/view/DisplayAdjustments;->setCompatibilityInfo(Landroid/content/res/CompatibilityInfo;)V
+Landroid/content/res/CompatibilityInfo;->applyToDisplayMetrics(Landroid/util/DisplayMetrics;)V
+Landroid/content/res/TypedArray;->getString(I)Ljava/lang/String;
+Lcom/android/internal/os/BatteryStatsImpl$SamplingTimer;->getUpdateVersion()I
+Landroid/os/ResultReceiver;->send(ILandroid/os/Bundle;)V
+Lcom/android/internal/os/ProcessCpuTracker;->getCpuTimeForPid(I)J
+Landroid/os/FileUtils;->contains(Ljava/io/File;Ljava/io/File;)Z
+Landroid/os/FileUtils;->contains(Ljava/lang/String;Ljava/lang/String;)Z
+Landroid/content/pm/PackageParser$SigningDetails;->checkCapability(Landroid/content/pm/PackageParser$SigningDetails;I)Z
+Landroid/util/MapCollections$MapIterator;->getValue()Ljava/lang/Object;
+Landroid/os/BinderProxy$ProxyMap;->get(J)Landroid/os/BinderProxy;
+Landroid/util/TimingsTraceLog;-><init>(Ljava/lang/String;J)V
+Landroid/os/PowerManager;->newWakeLock(ILjava/lang/String;)Landroid/os/PowerManager$WakeLock;
+Landroid/content/ComponentName;->hashCode()I
+Landroid/util/MapCollections$ArrayIterator;->hasNext()Z
+Landroid/app/IActivityTaskManager$Stub;-><init>()V
+Lcom/android/internal/os/ProcessCpuTracker;-><init>(Z)V
+Lcom/android/internal/util/RingBuffer;-><init>(Ljava/lang/Class;I)V
+Lcom/android/server/LocalServices;->getService(Ljava/lang/Class;)Ljava/lang/Object;
+Lcom/android/internal/util/XmlUtils;->readStringAttribute(Lorg/xmlpull/v1/XmlPullParser;Ljava/lang/String;)Ljava/lang/String;
+Lcom/android/internal/os/BatteryStatsImpl;->setPowerProfileLocked(Lcom/android/internal/os/PowerProfile;)V
+Lcom/android/internal/os/BatteryStatsImpl;->readDailyStatsLocked()V
+Lcom/android/internal/widget/LockPatternUtils;-><init>(Landroid/content/Context;)V
+Landroid/text/SpannableStringBuilder;->replace(IILjava/lang/CharSequence;)Landroid/text/Editable;
+Landroid/text/SpannableStringBuilder;->replace(IILjava/lang/CharSequence;)Landroid/text/SpannableStringBuilder;
+Landroid/text/SpannableStringBuilder;->replace(IILjava/lang/CharSequence;II)Landroid/text/SpannableStringBuilder;
+Landroid/content/res/Resources;->newTheme()Landroid/content/res/Resources$Theme;
+Landroid/os/Parcel;->obtain()Landroid/os/Parcel;
+Landroid/os/Parcel;->obtain(J)Landroid/os/Parcel;
+Landroid/content/res/Configuration;->updateFrom(Landroid/content/res/Configuration;)I
+Landroid/app/ContextImpl;->createAppContext(Landroid/app/ActivityThread;Landroid/app/LoadedApk;)Landroid/app/ContextImpl;
+Landroid/app/ContextImpl;->createAppContext(Landroid/app/ActivityThread;Landroid/app/LoadedApk;Ljava/lang/String;)Landroid/app/ContextImpl;
+Landroid/util/SparseArray;->clear()V
+Landroid/util/ArrayMap;->remove(Ljava/lang/Object;)Ljava/lang/Object;
+Landroid/util/ArrayMap;->removeAt(I)Ljava/lang/Object;
+Landroid/os/Parcel;->writeBundle(Landroid/os/Bundle;)V
+Landroid/content/pm/PackageParser;->hasDomainURLs(Landroid/content/pm/PackageParser$Package;)Z
+Landroid/util/Pools$SynchronizedPool;->release(Ljava/lang/Object;)Z
+Landroid/os/Parcel;->setDataPosition(I)V
+Landroid/os/LocaleList;->getDefault()Landroid/os/LocaleList;
+Landroid/content/res/ConfigurationBoundResourceCache;->onConfigurationChange(I)V
+Landroid/util/DisplayMetrics;->setToDefaults()V
+Landroid/content/pm/PackageParser;->computeMinSdkVersion(ILjava/lang/String;I[Ljava/lang/String;[Ljava/lang/String;)I
+Lcom/android/internal/os/ProcessCpuTracker;->onMeasureProcessName(Ljava/lang/String;)I
+Lcom/android/server/SystemConfig$SharedLibraryEntry;-><init>(Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;)V
+Landroid/util/MapCollections;->getKeySet()Ljava/util/Set;
+Landroid/content/ComponentName;->unflattenFromString(Ljava/lang/String;)Landroid/content/ComponentName;
+Landroid/util/Slog;->e(Ljava/lang/String;Ljava/lang/String;)I
+Landroid/util/Slog;->e(Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;)I
+Landroid/os/SynchronousResultReceiver;->awaitResult(J)Landroid/os/SynchronousResultReceiver$Result;
+Landroid/os/SynchronousResultReceiver;->onReceiveResult(ILandroid/os/Bundle;)V
+Landroid/view/SurfaceControl;->getHdrCapabilities(Landroid/os/IBinder;)Landroid/view/Display$HdrCapabilities;
+Lcom/android/internal/util/function/pooled/PooledLambdaImpl;->doRecycle()V
+Landroid/os/Handler;->postAtFrontOfQueue(Ljava/lang/Runnable;)Z
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index f655c89..f4df6b7 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -808,7 +808,9 @@
     /*package*/ ActivityInfo mActivityInfo;
     @UnsupportedAppUsage
     /*package*/ ActivityThread mMainThread;
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(trackingBug = 137825207, maxTargetSdk = Build.VERSION_CODES.Q,
+            publicAlternatives = "Use {@code androidx.fragment.app.Fragment} and "
+                    + "{@code androidx.fragment.app.FragmentManager} instead")
     Activity mParent;
     @UnsupportedAppUsage
     boolean mCalled;
@@ -1547,7 +1549,9 @@
      * had previously been frozen by {@link #onSaveInstanceState}.
      *
      * <p>This method is called between {@link #onStart} and
-     * {@link #onPostCreate}.
+     * {@link #onPostCreate}. This method is called only when recreating
+     * an activity; the method isn't invoked if {@link #onStart} is called for
+     * any other reason.</p>
      *
      * @param savedInstanceState the data most recently supplied in {@link #onSaveInstanceState}.
      *
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index 69e7118..1fd7e52 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -127,17 +127,6 @@
     public abstract void setHasOverlayUi(int pid, boolean hasOverlayUi);
 
     /**
-     * Sets if the given pid is currently running a remote animation, which is taken a signal for
-     * determining oom adjustment and scheduling behavior.
-     *
-     * @param pid The pid we are setting overlay UI for.
-     * @param runningRemoteAnimation True if the process is running a remote animation, false
-     *                               otherwise.
-     * @see RemoteAnimationAdapter
-     */
-    public abstract void setRunningRemoteAnimation(int pid, boolean runningRemoteAnimation);
-
-    /**
      * Called after the network policy rules are updated by
      * {@link com.android.server.net.NetworkPolicyManagerService} for a specific {@param uid} and
      * {@param procStateSeq}.
diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java
index 415ec64..e891828 100644
--- a/core/java/android/app/ActivityView.java
+++ b/core/java/android/app/ActivityView.java
@@ -120,8 +120,10 @@
 
         mActivityTaskManager = ActivityTaskManager.getService();
         mSurfaceView = new SurfaceView(context);
+        // Since ActivityView#getAlpha has been overridden, we should use parent class's alpha
+        // as master to synchronize surface view's alpha value.
+        mSurfaceView.setAlpha(super.getAlpha());
         mSurfaceView.setUseAlpha();
-        mSurfaceView.setAlpha(0f);
         mSurfaceCallback = new SurfaceCallback();
         mSurfaceView.getHolder().addCallback(mSurfaceCallback);
         addView(mSurfaceView);
@@ -348,9 +350,20 @@
         mSurfaceView.layout(0 /* left */, 0 /* top */, r - l /* right */, b - t /* bottom */);
     }
 
+    /**
+     * Sets the alpha value when the content of {@link SurfaceView} needs to show or hide.
+     * <p>Note: The surface view may ignore the alpha value in some cases. Refer to
+     * {@link SurfaceView#setAlpha} for more details.
+     *
+     * @param alpha The opacity of the view.
+     */
     @Override
     public void setAlpha(float alpha) {
-        mSurfaceView.setAlpha(alpha);
+        super.setAlpha(alpha);
+
+        if (mSurfaceView != null) {
+            mSurfaceView.setAlpha(alpha);
+        }
     }
 
     @Override
diff --git a/core/java/android/app/DisabledWallpaperManager.java b/core/java/android/app/DisabledWallpaperManager.java
new file mode 100644
index 0000000..5185941
--- /dev/null
+++ b/core/java/android/app/DisabledWallpaperManager.java
@@ -0,0 +1,346 @@
+/*
+ * 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.app;
+
+import android.annotation.NonNull;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.ParcelFileDescriptor;
+import android.util.Log;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * A no-op implementation of {@link WallpaperManager}.
+ */
+final class DisabledWallpaperManager extends WallpaperManager {
+
+    private static final String TAG = DisabledWallpaperManager.class.getSimpleName();
+
+    // Don't need to worry about synchronization
+    private static DisabledWallpaperManager sInstance;
+
+    // TODO(b/138939803): STOPSHIP changed to false and/or remove it
+    private static final boolean DEBUG = true;
+
+    @NonNull
+    static DisabledWallpaperManager getInstance() {
+        if (sInstance == null) {
+            sInstance = new DisabledWallpaperManager();
+        }
+        return sInstance;
+    }
+
+    private DisabledWallpaperManager() {
+        super(null, null, null);
+    }
+
+    @Override
+    public boolean isWallpaperSupported() {
+        return false;
+    }
+
+    @Override
+    public boolean isSetWallpaperAllowed() {
+        return false;
+    }
+
+    // TODO(b/138939803): STOPSHIP methods below should not be necessary,
+    // callers should check if isWallpaperSupported(), consider removing them to keep this class
+    // simpler
+
+    private static <T> T unsupported() {
+        if (DEBUG) Log.w(TAG, "unsupported method called; returning null", new Exception());
+        return null;
+    }
+
+    private static boolean unsupportedBoolean() {
+        if (DEBUG) Log.w(TAG, "unsupported method called; returning false", new Exception());
+        return false;
+    }
+
+    @Override
+    public Drawable getDrawable() {
+        return unsupported();
+    }
+
+    @Override
+    public Drawable getBuiltInDrawable() {
+        return unsupported();
+    }
+
+    @Override
+    public Drawable getBuiltInDrawable(int which) {
+        return unsupported();
+    }
+
+    @Override
+    public Drawable getBuiltInDrawable(int outWidth, int outHeight, boolean scaleToFit,
+            float horizontalAlignment, float verticalAlignment) {
+        return unsupported();
+    }
+
+    @Override
+    public Drawable getBuiltInDrawable(int outWidth, int outHeight, boolean scaleToFit,
+            float horizontalAlignment, float verticalAlignment, int which) {
+        return unsupported();
+    }
+
+    @Override
+    public Drawable peekDrawable() {
+        return unsupported();
+    }
+
+    @Override
+    public Drawable getFastDrawable() {
+        return unsupported();
+    }
+
+    @Override
+    public Drawable peekFastDrawable() {
+        return unsupported();
+    }
+
+    @Override
+    public Bitmap getBitmap() {
+        return unsupported();
+    }
+
+    @Override
+    public Bitmap getBitmap(boolean hardware) {
+        return unsupported();
+    }
+
+    @Override
+    public Bitmap getBitmapAsUser(int userId, boolean hardware) {
+        return unsupported();
+    }
+
+    @Override
+    public ParcelFileDescriptor getWallpaperFile(int which) {
+        return unsupported();
+    }
+
+    @Override
+    public void addOnColorsChangedListener(OnColorsChangedListener listener, Handler handler) {
+        unsupported();
+    }
+
+    @Override
+    public void addOnColorsChangedListener(OnColorsChangedListener listener, Handler handler,
+            int userId) {
+        unsupported();
+    }
+
+    @Override
+    public void removeOnColorsChangedListener(OnColorsChangedListener callback) {
+        unsupported();
+    }
+
+    @Override
+    public void removeOnColorsChangedListener(OnColorsChangedListener callback, int userId) {
+        unsupported();
+    }
+
+    @Override
+    public WallpaperColors getWallpaperColors(int which) {
+        return unsupported();
+    }
+
+    @Override
+    public WallpaperColors getWallpaperColors(int which, int userId) {
+        return unsupported();
+    }
+
+    @Override
+    public ParcelFileDescriptor getWallpaperFile(int which, int userId) {
+        return unsupported();
+    }
+
+    @Override
+    public void forgetLoadedWallpaper() {
+        unsupported();
+    }
+
+    @Override
+    public WallpaperInfo getWallpaperInfo() {
+        return unsupported();
+    }
+
+    @Override
+    public WallpaperInfo getWallpaperInfo(int userId) {
+        return unsupported();
+    }
+
+    @Override
+    public int getWallpaperId(int which) {
+        return unsupported();
+    }
+
+    @Override
+    public int getWallpaperIdForUser(int which, int userId) {
+        return unsupported();
+    }
+
+    @Override
+    public Intent getCropAndSetWallpaperIntent(Uri imageUri) {
+        return unsupported();
+    }
+
+    @Override
+    public void setResource(int resid) throws IOException {
+        unsupported();
+    }
+
+    @Override
+    public int setResource(int resid, int which) throws IOException {
+        return unsupported();
+    }
+
+    @Override
+    public void setBitmap(Bitmap bitmap) throws IOException {
+        unsupported();
+    }
+
+    @Override
+    public int setBitmap(Bitmap fullImage, Rect visibleCropHint, boolean allowBackup)
+            throws IOException {
+        return unsupported();
+    }
+
+    @Override
+    public int setBitmap(Bitmap fullImage, Rect visibleCropHint, boolean allowBackup, int which)
+            throws IOException {
+        return unsupported();
+    }
+
+    @Override
+    public int setBitmap(Bitmap fullImage, Rect visibleCropHint, boolean allowBackup, int which,
+            int userId) throws IOException {
+        return unsupported();
+    }
+
+    @Override
+    public void setStream(InputStream bitmapData) throws IOException {
+        unsupported();
+    }
+
+    @Override
+    public int setStream(InputStream bitmapData, Rect visibleCropHint, boolean allowBackup)
+            throws IOException {
+        return unsupported();
+    }
+
+    @Override
+    public int setStream(InputStream bitmapData, Rect visibleCropHint, boolean allowBackup,
+            int which) throws IOException {
+        return unsupported();
+    }
+
+    @Override
+    public boolean hasResourceWallpaper(int resid) {
+        return unsupportedBoolean();
+    }
+
+    @Override
+    public int getDesiredMinimumWidth() {
+        return unsupported();
+    }
+
+    @Override
+    public int getDesiredMinimumHeight() {
+        return unsupported();
+    }
+
+    @Override
+    public void suggestDesiredDimensions(int minimumWidth, int minimumHeight) {
+        unsupported();
+    }
+
+    @Override
+    public void setDisplayPadding(Rect padding) {
+        unsupported();
+    }
+
+    @Override
+    public void setDisplayOffset(IBinder windowToken, int x, int y) {
+        unsupported();
+    }
+
+    @Override
+    public void clearWallpaper() {
+        unsupported();
+    }
+
+    @Override
+    public void clearWallpaper(int which, int userId) {
+        unsupported();
+    }
+
+    @Override
+    public boolean setWallpaperComponent(ComponentName name) {
+        return unsupportedBoolean();
+    }
+
+    @Override
+    public boolean setWallpaperComponent(ComponentName name, int userId) {
+        return unsupportedBoolean();
+    }
+
+    @Override
+    public void setWallpaperOffsets(IBinder windowToken, float xOffset, float yOffset) {
+        unsupported();
+    }
+
+    @Override
+    public void setWallpaperOffsetSteps(float xStep, float yStep) {
+        unsupported();
+    }
+
+    @Override
+    public void sendWallpaperCommand(IBinder windowToken, String action, int x, int y, int z,
+            Bundle extras) {
+        unsupported();
+    }
+
+    @Override
+    public void clearWallpaperOffsets(IBinder windowToken) {
+        unsupported();
+    }
+
+    @Override
+    public void clear() throws IOException {
+        unsupported();
+    }
+
+    @Override
+    public void clear(int which) throws IOException {
+        unsupported();
+    }
+
+    @Override
+    public boolean isWallpaperBackupEligible(int which) {
+        return unsupportedBoolean();
+    }
+}
diff --git a/core/java/android/app/DownloadManager.java b/core/java/android/app/DownloadManager.java
index 1166cb5..80c9ba2 100644
--- a/core/java/android/app/DownloadManager.java
+++ b/core/java/android/app/DownloadManager.java
@@ -132,6 +132,9 @@
      */
     public final static String COLUMN_STATUS = Downloads.Impl.COLUMN_STATUS;
 
+    /** {@hide} */
+    public final static String COLUMN_FILE_NAME_HINT = Downloads.Impl.COLUMN_FILE_NAME_HINT;
+
     /**
      * Provides more detail on the status of the download.  Its meaning depends on the value of
      * {@link #COLUMN_STATUS}.
@@ -169,6 +172,9 @@
      */
     public static final String COLUMN_MEDIAPROVIDER_URI = Downloads.Impl.COLUMN_MEDIAPROVIDER_URI;
 
+    /** {@hide} */
+    public static final String COLUMN_DESTINATION = Downloads.Impl.COLUMN_DESTINATION;
+
     /** @hide */
     @TestApi
     public static final String COLUMN_MEDIASTORE_URI = Downloads.Impl.COLUMN_MEDIASTORE_URI;
@@ -340,26 +346,22 @@
      */
     @UnsupportedAppUsage
     public static final String[] UNDERLYING_COLUMNS = new String[] {
-        Downloads.Impl._ID,
-        Downloads.Impl._DATA + " AS " + COLUMN_LOCAL_FILENAME,
-        Downloads.Impl.COLUMN_MEDIAPROVIDER_URI,
-        Downloads.Impl.COLUMN_DESTINATION,
-        Downloads.Impl.COLUMN_TITLE,
-        Downloads.Impl.COLUMN_DESCRIPTION,
-        Downloads.Impl.COLUMN_URI,
-        Downloads.Impl.COLUMN_STATUS,
-        Downloads.Impl.COLUMN_FILE_NAME_HINT,
-        Downloads.Impl.COLUMN_MIME_TYPE + " AS " + COLUMN_MEDIA_TYPE,
-        Downloads.Impl.COLUMN_TOTAL_BYTES + " AS " + COLUMN_TOTAL_SIZE_BYTES,
-        Downloads.Impl.COLUMN_LAST_MODIFICATION + " AS " + COLUMN_LAST_MODIFIED_TIMESTAMP,
-        Downloads.Impl.COLUMN_CURRENT_BYTES + " AS " + COLUMN_BYTES_DOWNLOADED_SO_FAR,
-        Downloads.Impl.COLUMN_ALLOW_WRITE,
-        /* add the following 'computed' columns to the cursor.
-         * they are not 'returned' by the database, but their inclusion
-         * eliminates need to have lot of methods in CursorTranslator
-         */
-        "'placeholder' AS " + COLUMN_LOCAL_URI,
-        "'placeholder' AS " + COLUMN_REASON
+        DownloadManager.COLUMN_ID,
+        DownloadManager.COLUMN_LOCAL_FILENAME,
+        DownloadManager.COLUMN_MEDIAPROVIDER_URI,
+        DownloadManager.COLUMN_DESTINATION,
+        DownloadManager.COLUMN_TITLE,
+        DownloadManager.COLUMN_DESCRIPTION,
+        DownloadManager.COLUMN_URI,
+        DownloadManager.COLUMN_STATUS,
+        DownloadManager.COLUMN_FILE_NAME_HINT,
+        DownloadManager.COLUMN_MEDIA_TYPE,
+        DownloadManager.COLUMN_TOTAL_SIZE_BYTES,
+        DownloadManager.COLUMN_LAST_MODIFIED_TIMESTAMP,
+        DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR,
+        DownloadManager.COLUMN_ALLOW_WRITE,
+        DownloadManager.COLUMN_LOCAL_URI,
+        DownloadManager.COLUMN_REASON
     };
 
     /**
diff --git a/core/java/android/app/ITaskStackListener.aidl b/core/java/android/app/ITaskStackListener.aidl
index 650147b..61867ea 100644
--- a/core/java/android/app/ITaskStackListener.aidl
+++ b/core/java/android/app/ITaskStackListener.aidl
@@ -185,4 +185,9 @@
      * @param newDisplayId id of the new display.
      */
     void onTaskDisplayChanged(int taskId, int newDisplayId);
+
+    /**
+     * Called when any additions or deletions to the recent tasks list have been made.
+     */
+    void onRecentTaskListUpdated();
 }
diff --git a/core/java/android/app/LocalActivityManager.java b/core/java/android/app/LocalActivityManager.java
index 19575b2..87b064d 100644
--- a/core/java/android/app/LocalActivityManager.java
+++ b/core/java/android/app/LocalActivityManager.java
@@ -22,6 +22,7 @@
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
 import android.os.Binder;
+import android.os.Build;
 import android.os.Bundle;
 import android.util.Log;
 import android.view.Window;
@@ -74,23 +75,33 @@
     /** Thread our activities are running in. */
     private final ActivityThread mActivityThread;
     /** The containing activity that owns the activities we create. */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(trackingBug = 137825207, maxTargetSdk = Build.VERSION_CODES.Q,
+            publicAlternatives = "Use {@code androidx.fragment.app.Fragment} and "
+                    + "{@code androidx.fragment.app.FragmentManager} instead")
     private final Activity mParent;
 
     /** The activity that is currently resumed. */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(trackingBug = 137825207, maxTargetSdk = Build.VERSION_CODES.Q,
+            publicAlternatives = "Use {@code androidx.fragment.app.Fragment} and "
+                    + "{@code androidx.fragment.app.FragmentManager} instead")
     private LocalActivityRecord mResumed;
     /** id -> record of all known activities. */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(trackingBug = 137825207, maxTargetSdk = Build.VERSION_CODES.Q,
+            publicAlternatives = "Use {@code androidx.fragment.app.Fragment} and "
+                    + "{@code androidx.fragment.app.FragmentManager} instead")
     private final Map<String, LocalActivityRecord> mActivities
             = new HashMap<String, LocalActivityRecord>();
     /** array of all known activities for easy iterating. */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(trackingBug = 137825207, maxTargetSdk = Build.VERSION_CODES.Q,
+            publicAlternatives = "Use {@code androidx.fragment.app.Fragment} and "
+                    + "{@code androidx.fragment.app.FragmentManager} instead")
     private final ArrayList<LocalActivityRecord> mActivityArray
             = new ArrayList<LocalActivityRecord>();
 
     /** True if only one activity can be resumed at a time */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(trackingBug = 137825207, maxTargetSdk = Build.VERSION_CODES.Q,
+            publicAlternatives = "Use {@code androidx.fragment.app.Fragment} and "
+                    + "{@code androidx.fragment.app.FragmentManager} instead")
     private boolean mSingleMode;
     
     /** Set to true once we find out the container is finishing. */
@@ -117,7 +128,9 @@
         mSingleMode = singleMode;
     }
 
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(trackingBug = 137825207, maxTargetSdk = Build.VERSION_CODES.Q,
+            publicAlternatives = "Use {@code androidx.fragment.app.Fragment} and "
+                    + "{@code androidx.fragment.app.FragmentManager} instead")
     private void moveToState(LocalActivityRecord r, int desiredState) {
         if (r.curState == RESTORED || r.curState == DESTROYED) {
             // startActivity() has not yet been called, so nothing to do.
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 5034b53..c58972e 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -695,11 +695,22 @@
             @Override
             public WallpaperManager createService(ContextImpl ctx)
                     throws ServiceNotFoundException {
-                final IBinder b;
-                if (ctx.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.P) {
-                    b = ServiceManager.getServiceOrThrow(Context.WALLPAPER_SERVICE);
-                } else {
-                    b = ServiceManager.getService(Context.WALLPAPER_SERVICE);
+                final IBinder b = ServiceManager.getService(Context.WALLPAPER_SERVICE);
+                if (b == null) {
+                    // There are 2 reason service can be null:
+                    // 1.Device doesn't support it - that's fine
+                    // 2.App is running on instant mode - should fail
+                    final boolean enabled = Resources.getSystem()
+                            .getBoolean(com.android.internal.R.bool.config_enableWallpaperService);
+                    if (!enabled) {
+                        // Life moves on...
+                        return DisabledWallpaperManager.getInstance();
+                    }
+                    if (ctx.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.P) {
+                        // Instant app
+                        throw new ServiceNotFoundException(Context.WALLPAPER_SERVICE);
+                    }
+                    // Bad state - WallpaperManager methods will throw exception
                 }
                 IWallpaperManager service = IWallpaperManager.Stub.asInterface(b);
                 return new WallpaperManager(service, ctx.getOuterContext(),
diff --git a/core/java/android/app/TaskStackListener.java b/core/java/android/app/TaskStackListener.java
index b63feb5..e3a0e11 100644
--- a/core/java/android/app/TaskStackListener.java
+++ b/core/java/android/app/TaskStackListener.java
@@ -182,4 +182,8 @@
     @Override
     public void onTaskDisplayChanged(int taskId, int newDisplayId) throws RemoteException {
     }
+
+    @Override
+    public void onRecentTaskListUpdated() throws RemoteException {
+    }
 }
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index d305238..59ecf4a 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -510,7 +510,9 @@
 
     /*package*/ WallpaperManager(IWallpaperManager service, Context context, Handler handler) {
         mContext = context;
-        initGlobals(service, context.getMainLooper());
+        if (service != null) {
+            initGlobals(service, context.getMainLooper());
+        }
     }
 
     /**
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 5624ba5..49cfd41 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -4981,6 +4981,42 @@
         return null;
     }
 
+
+    /**
+     * Called by a device or profile owner, or delegated certificate chooser (an app that has been
+     * delegated the {@link #DELEGATION_CERT_SELECTION} privilege), to grant an application access
+     * to an already-installed (or generated) KeyChain key.
+     * This is useful (in combination with {@link #installKeyPair} or {@link #generateKeyPair}) to
+     * let an application call {@link android.security.KeyChain#getPrivateKey} without having to
+     * call {@link android.security.KeyChain#choosePrivateKeyAlias} first.
+     *
+     * The grantee app will receive the {@link android.security.KeyChain#ACTION_KEY_ACCESS_CHANGED}
+     * broadcast when access to a key is granted or revoked.
+     *
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
+     *        {@code null} if calling from a delegated certificate installer.
+     * @param alias The alias of the key to grant access to.
+     * @param packageName The name of the (already installed) package to grant access to.
+     * @param hasGrant Whether to grant access to the alias or revoke it.
+     * @return {@code true} if the grant was set successfully, {@code false} otherwise.
+     *
+     * @throws SecurityException if the caller is not a device owner, a profile  owner or
+     *         delegated certificate chooser.
+     * @throws IllegalArgumentException if {@code packageName} or {@code alias} are empty, or if
+     *         {@code packageName} is not a name of an installed package.
+     */
+    public boolean setKeyGrantForApp(@Nullable ComponentName admin, @NonNull String alias,
+            @NonNull String packageName, boolean hasGrant) {
+        throwIfParentInstance("addKeyGrant");
+        try {
+            return mService.setKeyGrantForApp(
+                    admin, mContext.getPackageName(), alias, packageName, hasGrant);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+        return false;
+    }
+
     /**
      * Returns {@code true} if the device supports attestation of device identifiers in addition
      * to key attestation.
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 2b96419..5cdef6d 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -436,4 +436,6 @@
     boolean isUnattendedManagedKiosk();
 
     boolean startViewCalendarEventInManagedProfile(String packageName, long eventId, long start, long end, boolean allDay, int flags);
+
+    boolean setKeyGrantForApp(in ComponentName admin, String callerPackage, String alias, String packageName, boolean hasGrant);
 }
diff --git a/core/java/android/app/backup/WallpaperBackupHelper.java b/core/java/android/app/backup/WallpaperBackupHelper.java
index 36f5f96..5c0ddc1 100644
--- a/core/java/android/app/backup/WallpaperBackupHelper.java
+++ b/core/java/android/app/backup/WallpaperBackupHelper.java
@@ -85,6 +85,10 @@
      */
     @Override
     public void restoreEntity(BackupDataInputStream data) {
+        if (mWpm == null) {
+            Slog.w(TAG, "restoreEntity(): no wallpaper service");
+            return;
+        }
         final String key = data.getKey();
         if (isKeyInList(key, mKeys)) {
             if (key.equals(WALLPAPER_IMAGE_KEY)) {
diff --git a/core/java/android/app/job/JobParameters.java b/core/java/android/app/job/JobParameters.java
index dadfe3d..ecc859d 100644
--- a/core/java/android/app/job/JobParameters.java
+++ b/core/java/android/app/job/JobParameters.java
@@ -50,6 +50,19 @@
     /** @hide */
     public static final int REASON_DEVICE_THERMAL = JobProtoEnums.STOP_REASON_DEVICE_THERMAL; // 5.
 
+    /**
+     * All the stop reason codes. This should be regarded as an immutable array at runtime.
+     * @hide
+     */
+    public static final int[] JOB_STOP_REASON_CODES = {
+            REASON_CANCELED,
+            REASON_CONSTRAINTS_NOT_SATISFIED,
+            REASON_PREEMPT,
+            REASON_TIMEOUT,
+            REASON_DEVICE_IDLE,
+            REASON_DEVICE_THERMAL,
+    };
+
     /** @hide */
     public static String getReasonName(int reason) {
         switch (reason) {
@@ -58,6 +71,7 @@
             case REASON_PREEMPT: return "preempt";
             case REASON_TIMEOUT: return "timeout";
             case REASON_DEVICE_IDLE: return "device_idle";
+            case REASON_DEVICE_THERMAL: return "thermal";
             default: return "unknown:" + reason;
         }
     }
diff --git a/core/java/android/app/job/JobSchedulerFrameworkInitializer.java b/core/java/android/app/job/JobSchedulerFrameworkInitializer.java
index cf2979c..c90b872 100644
--- a/core/java/android/app/job/JobSchedulerFrameworkInitializer.java
+++ b/core/java/android/app/job/JobSchedulerFrameworkInitializer.java
@@ -19,6 +19,7 @@
 import android.app.JobSchedulerImpl;
 import android.app.SystemServiceRegistry;
 import android.content.Context;
+import android.os.BatteryStats;
 
 /**
  * This class needs to be pre-loaded by zygote.  This is where the job scheduler service wrapper
@@ -31,5 +32,8 @@
         SystemServiceRegistry.registerStaticService(
                 Context.JOB_SCHEDULER_SERVICE, JobScheduler.class,
                 (b) -> new JobSchedulerImpl(IJobScheduler.Stub.asInterface(b)));
+
+        BatteryStats.setJobStopReasons(JobParameters.JOB_STOP_REASON_CODES,
+                JobParameters::getReasonName);
     }
 }
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index 3c79991..4ea3726 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -2112,6 +2112,10 @@
                 mSingleUser = (info.flags & ProviderInfo.FLAG_SINGLE_USER) != 0;
                 setAuthorities(info.authority);
             }
+            if (Build.IS_DEBUGGABLE) {
+                setTransportLoggingEnabled(Log.isLoggable(getClass().getSimpleName(),
+                        Log.VERBOSE));
+            }
             ContentProvider.this.onCreate();
         }
     }
diff --git a/core/java/android/content/ContentProviderOperation.java b/core/java/android/content/ContentProviderOperation.java
index c201e4d..621f331 100644
--- a/core/java/android/content/ContentProviderOperation.java
+++ b/core/java/android/content/ContentProviderOperation.java
@@ -16,17 +16,22 @@
 
 package android.content;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.UnsupportedAppUsage;
 import android.database.Cursor;
 import android.net.Uri;
+import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.TextUtils;
+import android.util.ArrayMap;
 import android.util.Log;
+import android.util.SparseArray;
 
 import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.Map;
+import java.util.Objects;
 
 /**
  * Represents a single operation to be performed as part of a batch of operations.
@@ -45,20 +50,23 @@
     public final static int TYPE_DELETE = 3;
     /** @hide exposed for unit tests */
     public final static int TYPE_ASSERT = 4;
+    /** @hide exposed for unit tests */
+    public final static int TYPE_CALL = 5;
 
     @UnsupportedAppUsage
     private final int mType;
     @UnsupportedAppUsage
     private final Uri mUri;
+    private final String mMethod;
+    private final String mArg;
+    private final ArrayMap<String, Object> mValues;
+    private final ArrayMap<String, Object> mExtras;
     @UnsupportedAppUsage
     private final String mSelection;
-    private final String[] mSelectionArgs;
-    private final ContentValues mValues;
+    private final SparseArray<Object> mSelectionArgs;
     private final Integer mExpectedCount;
-    private final ContentValues mValuesBackReferences;
-    private final Map<Integer, Integer> mSelectionArgsBackReferences;
     private final boolean mYieldAllowed;
-    private final boolean mFailureAllowed;
+    private final boolean mExceptionAllowed;
 
     private final static String TAG = "ContentProviderOperation";
 
@@ -69,124 +77,130 @@
     private ContentProviderOperation(Builder builder) {
         mType = builder.mType;
         mUri = builder.mUri;
+        mMethod = builder.mMethod;
+        mArg = builder.mArg;
         mValues = builder.mValues;
+        mExtras = builder.mExtras;
         mSelection = builder.mSelection;
         mSelectionArgs = builder.mSelectionArgs;
         mExpectedCount = builder.mExpectedCount;
-        mSelectionArgsBackReferences = builder.mSelectionArgsBackReferences;
-        mValuesBackReferences = builder.mValuesBackReferences;
         mYieldAllowed = builder.mYieldAllowed;
-        mFailureAllowed = builder.mFailureAllowed;
+        mExceptionAllowed = builder.mExceptionAllowed;
     }
 
     private ContentProviderOperation(Parcel source) {
         mType = source.readInt();
         mUri = Uri.CREATOR.createFromParcel(source);
-        mValues = source.readInt() != 0 ? ContentValues.CREATOR.createFromParcel(source) : null;
-        mSelection = source.readInt() != 0 ? source.readString() : null;
-        mSelectionArgs = source.readInt() != 0 ? source.readStringArray() : null;
-        mExpectedCount = source.readInt() != 0 ? source.readInt() : null;
-        mValuesBackReferences = source.readInt() != 0
-                ? ContentValues.CREATOR.createFromParcel(source)
-                : null;
-        mSelectionArgsBackReferences = source.readInt() != 0
-                ? new HashMap<Integer, Integer>()
-                : null;
-        if (mSelectionArgsBackReferences != null) {
-            final int count = source.readInt();
-            for (int i = 0; i < count; i++) {
-                mSelectionArgsBackReferences.put(source.readInt(), source.readInt());
-            }
+        mMethod = source.readInt() != 0 ? source.readString() : null;
+        mArg = source.readInt() != 0 ? source.readString() : null;
+        final int valuesSize = source.readInt();
+        if (valuesSize != -1) {
+            mValues = new ArrayMap<>(valuesSize);
+            source.readArrayMap(mValues, null);
+        } else {
+            mValues = null;
         }
+        final int extrasSize = source.readInt();
+        if (extrasSize != -1) {
+            mExtras = new ArrayMap<>(extrasSize);
+            source.readArrayMap(mExtras, null);
+        } else {
+            mExtras = null;
+        }
+        mSelection = source.readInt() != 0 ? source.readString() : null;
+        mSelectionArgs = source.readSparseArray(null);
+        mExpectedCount = source.readInt() != 0 ? source.readInt() : null;
         mYieldAllowed = source.readInt() != 0;
-        mFailureAllowed = source.readInt() != 0;
+        mExceptionAllowed = source.readInt() != 0;
     }
 
     /** @hide */
     public ContentProviderOperation(ContentProviderOperation cpo, Uri withUri) {
         mType = cpo.mType;
         mUri = withUri;
+        mMethod = cpo.mMethod;
+        mArg = cpo.mArg;
         mValues = cpo.mValues;
+        mExtras = cpo.mExtras;
         mSelection = cpo.mSelection;
         mSelectionArgs = cpo.mSelectionArgs;
         mExpectedCount = cpo.mExpectedCount;
-        mSelectionArgsBackReferences = cpo.mSelectionArgsBackReferences;
-        mValuesBackReferences = cpo.mValuesBackReferences;
         mYieldAllowed = cpo.mYieldAllowed;
-        mFailureAllowed = cpo.mFailureAllowed;
+        mExceptionAllowed = cpo.mExceptionAllowed;
     }
 
+    @Override
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeInt(mType);
         Uri.writeToParcel(dest, mUri);
-        if (mValues != null) {
+        if (mMethod != null) {
             dest.writeInt(1);
-            mValues.writeToParcel(dest, 0);
+            dest.writeString(mMethod);
         } else {
             dest.writeInt(0);
         }
+        if (mArg != null) {
+            dest.writeInt(1);
+            dest.writeString(mArg);
+        } else {
+            dest.writeInt(0);
+        }
+        if (mValues != null) {
+            dest.writeInt(mValues.size());
+            dest.writeArrayMap(mValues);
+        } else {
+            dest.writeInt(-1);
+        }
+        if (mExtras != null) {
+            dest.writeInt(mExtras.size());
+            dest.writeArrayMap(mExtras);
+        } else {
+            dest.writeInt(-1);
+        }
         if (mSelection != null) {
             dest.writeInt(1);
             dest.writeString(mSelection);
         } else {
             dest.writeInt(0);
         }
-        if (mSelectionArgs != null) {
-            dest.writeInt(1);
-            dest.writeStringArray(mSelectionArgs);
-        } else {
-            dest.writeInt(0);
-        }
+        dest.writeSparseArray(mSelectionArgs);
         if (mExpectedCount != null) {
             dest.writeInt(1);
             dest.writeInt(mExpectedCount);
         } else {
             dest.writeInt(0);
         }
-        if (mValuesBackReferences != null) {
-            dest.writeInt(1);
-            mValuesBackReferences.writeToParcel(dest, 0);
-        } else {
-            dest.writeInt(0);
-        }
-        if (mSelectionArgsBackReferences != null) {
-            dest.writeInt(1);
-            dest.writeInt(mSelectionArgsBackReferences.size());
-            for (Map.Entry<Integer, Integer> entry : mSelectionArgsBackReferences.entrySet()) {
-                dest.writeInt(entry.getKey());
-                dest.writeInt(entry.getValue());
-            }
-        } else {
-            dest.writeInt(0);
-        }
         dest.writeInt(mYieldAllowed ? 1 : 0);
-        dest.writeInt(mFailureAllowed ? 1 : 0);
+        dest.writeInt(mExceptionAllowed ? 1 : 0);
     }
 
     /**
-     * Create a {@link Builder} suitable for building an insert {@link ContentProviderOperation}.
-     * @param uri The {@link Uri} that is the target of the insert.
-     * @return a {@link Builder}
+     * Create a {@link Builder} suitable for building an operation that will
+     * invoke {@link ContentProvider#insert}.
+     *
+     * @param uri The {@link Uri} that is the target of the operation.
      */
-    public static Builder newInsert(Uri uri) {
+    public static @NonNull Builder newInsert(@NonNull Uri uri) {
         return new Builder(TYPE_INSERT, uri);
     }
 
     /**
-     * Create a {@link Builder} suitable for building an update {@link ContentProviderOperation}.
-     * @param uri The {@link Uri} that is the target of the update.
-     * @return a {@link Builder}
+     * Create a {@link Builder} suitable for building an operation that will
+     * invoke {@link ContentProvider#update}.
+     *
+     * @param uri The {@link Uri} that is the target of the operation.
      */
-    public static Builder newUpdate(Uri uri) {
+    public static @NonNull Builder newUpdate(@NonNull Uri uri) {
         return new Builder(TYPE_UPDATE, uri);
     }
 
     /**
-     * Create a {@link Builder} suitable for building a delete {@link ContentProviderOperation}.
-     * @param uri The {@link Uri} that is the target of the delete.
-     * @return a {@link Builder}
+     * Create a {@link Builder} suitable for building an operation that will
+     * invoke {@link ContentProvider#delete}.
+     *
+     * @param uri The {@link Uri} that is the target of the operation.
      */
-    public static Builder newDelete(Uri uri) {
+    public static @NonNull Builder newDelete(@NonNull Uri uri) {
         return new Builder(TYPE_DELETE, uri);
     }
 
@@ -195,14 +209,25 @@
      * {@link ContentProviderOperation} to assert a set of values as provided
      * through {@link Builder#withValues(ContentValues)}.
      */
-    public static Builder newAssertQuery(Uri uri) {
+    public static @NonNull Builder newAssertQuery(@NonNull Uri uri) {
         return new Builder(TYPE_ASSERT, uri);
     }
 
     /**
+     * Create a {@link Builder} suitable for building an operation that will
+     * invoke {@link ContentProvider#call}.
+     *
+     * @param uri The {@link Uri} that is the target of the operation.
+     */
+    public static @NonNull Builder newCall(@NonNull Uri uri, @Nullable String method,
+            @Nullable String arg) {
+        return new Builder(TYPE_CALL, uri, method, arg);
+    }
+
+    /**
      * Gets the Uri for the target of the operation.
      */
-    public Uri getUri() {
+    public @NonNull Uri getUri() {
         return mUri;
     }
 
@@ -216,9 +241,13 @@
         return mYieldAllowed;
     }
 
-    /** {@hide} */
-    public boolean isFailureAllowed() {
-        return mFailureAllowed;
+    /**
+     * Returns true if this operation allows subsequent operations to continue
+     * even if this operation throws an exception. When true, any encountered
+     * exception is returned via {@link ContentProviderResult#exception}.
+     */
+    public boolean isExceptionAllowed() {
+        return mExceptionAllowed;
     }
 
     /** @hide exposed for unit tests */
@@ -228,7 +257,8 @@
     }
 
     /**
-     * Returns true if the operation represents an insertion.
+     * Returns true if the operation represents a {@link ContentProvider#insert}
+     * operation.
      *
      * @see #newInsert
      */
@@ -237,7 +267,8 @@
     }
 
     /**
-     * Returns true if the operation represents a deletion.
+     * Returns true if the operation represents a {@link ContentProvider#delete}
+     * operation.
      *
      * @see #newDelete
      */
@@ -246,7 +277,8 @@
     }
 
     /**
-     * Returns true if the operation represents an update.
+     * Returns true if the operation represents a {@link ContentProvider#update}
+     * operation.
      *
      * @see #newUpdate
      */
@@ -264,6 +296,16 @@
     }
 
     /**
+     * Returns true if the operation represents a {@link ContentProvider#call}
+     * operation.
+     *
+     * @see #newCall
+     */
+    public boolean isCall() {
+        return mType == TYPE_CALL;
+    }
+
+    /**
      * Returns true if the operation represents an insertion, deletion, or update.
      *
      * @see #isInsert
@@ -297,13 +339,14 @@
      * @throws OperationApplicationException thrown if either the insert fails or
      * if the number of rows affected didn't match the expected count
      */
-    public ContentProviderResult apply(ContentProvider provider, ContentProviderResult[] backRefs,
-            int numBackRefs) throws OperationApplicationException {
-        if (mFailureAllowed) {
+    public @NonNull ContentProviderResult apply(@NonNull ContentProvider provider,
+            @NonNull ContentProviderResult[] backRefs, int numBackRefs)
+            throws OperationApplicationException {
+        if (mExceptionAllowed) {
             try {
                 return applyInternal(provider, backRefs, numBackRefs);
             } catch (Exception e) {
-                return new ContentProviderResult(e.getMessage());
+                return new ContentProviderResult(e);
             }
         } else {
             return applyInternal(provider, backRefs, numBackRefs);
@@ -313,9 +356,9 @@
     private ContentProviderResult applyInternal(ContentProvider provider,
             ContentProviderResult[] backRefs, int numBackRefs)
             throws OperationApplicationException {
-        ContentValues values = resolveValueBackReferences(backRefs, numBackRefs);
-        String[] selectionArgs =
-                resolveSelectionArgsBackReferences(backRefs, numBackRefs);
+        final ContentValues values = resolveValueBackReferences(backRefs, numBackRefs);
+        final Bundle extras = resolveExtrasBackReferences(backRefs, numBackRefs);
+        final String[] selectionArgs = resolveSelectionArgsBackReferences(backRefs, numBackRefs);
 
         if (mType == TYPE_INSERT) {
             final Uri newUri = provider.insert(mUri, values);
@@ -325,6 +368,9 @@
                 throw new OperationApplicationException(
                         "Insert into " + mUri + " returned no result");
             }
+        } else if (mType == TYPE_CALL) {
+            final Bundle res = provider.call(mUri.getAuthority(), mMethod, mArg, extras);
+            return new ContentProviderResult(res);
         }
 
         final int numRows;
@@ -376,124 +422,218 @@
     }
 
     /**
-     * The ContentValues back references are represented as a ContentValues object where the
-     * key refers to a column and the value is an index of the back reference whose
-     * valued should be associated with the column.
-     * <p>
-     * This is intended to be a private method but it is exposed for
-     * unit testing purposes
-     * @param backRefs an array of previous results
-     * @param numBackRefs the number of valid previous results in backRefs
-     * @return the ContentValues that should be used in this operation application after
-     * expansion of back references. This can be called if either mValues or mValuesBackReferences
-     * is null
+     * Return the values for this operation after resolving any requested
+     * back-references using the given results.
+     *
+     * @param backRefs the results to use when resolving any back-references
+     * @param numBackRefs the number of results which are valid
      */
-    public ContentValues resolveValueBackReferences(
-            ContentProviderResult[] backRefs, int numBackRefs) {
-        if (mValuesBackReferences == null) {
-            return mValues;
-        }
-        final ContentValues values;
-        if (mValues == null) {
-            values = new ContentValues();
-        } else {
-            values = new ContentValues(mValues);
-        }
-        for (Map.Entry<String, Object> entry : mValuesBackReferences.valueSet()) {
-            String key = entry.getKey();
-            Integer backRefIndex = mValuesBackReferences.getAsInteger(key);
-            if (backRefIndex == null) {
-                Log.e(TAG, this.toString());
-                throw new IllegalArgumentException("values backref " + key + " is not an integer");
+    public @Nullable ContentValues resolveValueBackReferences(
+            @NonNull ContentProviderResult[] backRefs, int numBackRefs) {
+        if (mValues != null) {
+            final ContentValues values = new ContentValues();
+            for (int i = 0; i < mValues.size(); i++) {
+                final Object value = mValues.valueAt(i);
+                final Object resolved;
+                if (value instanceof BackReference) {
+                    resolved = ((BackReference) value).resolve(backRefs, numBackRefs);
+                } else {
+                    resolved = value;
+                }
+                values.putObject(mValues.keyAt(i), resolved);
             }
-            values.put(key, backRefToValue(backRefs, numBackRefs, backRefIndex));
+            return values;
+        } else {
+            return null;
         }
-        return values;
     }
 
     /**
-     * The Selection Arguments back references are represented as a Map of Integer->Integer where
-     * the key is an index into the selection argument array (see {@link Builder#withSelection})
-     * and the value is the index of the previous result that should be used for that selection
-     * argument array slot.
-     * <p>
-     * This is intended to be a private method but it is exposed for
-     * unit testing purposes
-     * @param backRefs an array of previous results
-     * @param numBackRefs the number of valid previous results in backRefs
-     * @return the ContentValues that should be used in this operation application after
-     * expansion of back references. This can be called if either mValues or mValuesBackReferences
-     * is null
+     * Return the extras for this operation after resolving any requested
+     * back-references using the given results.
+     *
+     * @param backRefs the results to use when resolving any back-references
+     * @param numBackRefs the number of results which are valid
      */
-    public String[] resolveSelectionArgsBackReferences(
-            ContentProviderResult[] backRefs, int numBackRefs) {
-        if (mSelectionArgsBackReferences == null) {
-            return mSelectionArgs;
+    public @Nullable Bundle resolveExtrasBackReferences(
+            @NonNull ContentProviderResult[] backRefs, int numBackRefs) {
+        if (mExtras != null) {
+            final Bundle extras = new Bundle();
+            for (int i = 0; i < mExtras.size(); i++) {
+                final Object value = mExtras.valueAt(i);
+                final Object resolved;
+                if (value instanceof BackReference) {
+                    resolved = ((BackReference) value).resolve(backRefs, numBackRefs);
+                } else {
+                    resolved = value;
+                }
+                extras.putObject(mExtras.keyAt(i), resolved);
+            }
+            return extras;
+        } else {
+            return null;
         }
-        String[] newArgs = new String[mSelectionArgs.length];
-        System.arraycopy(mSelectionArgs, 0, newArgs, 0, mSelectionArgs.length);
-        for (Map.Entry<Integer, Integer> selectionArgBackRef
-                : mSelectionArgsBackReferences.entrySet()) {
-            final Integer selectionArgIndex = selectionArgBackRef.getKey();
-            final int backRefIndex = selectionArgBackRef.getValue();
-            newArgs[selectionArgIndex] =
-                    String.valueOf(backRefToValue(backRefs, numBackRefs, backRefIndex));
+    }
+
+    /**
+     * Return the selection arguments for this operation after resolving any
+     * requested back-references using the given results.
+     *
+     * @param backRefs the results to use when resolving any back-references
+     * @param numBackRefs the number of results which are valid
+     */
+    public @Nullable String[] resolveSelectionArgsBackReferences(
+            @NonNull ContentProviderResult[] backRefs, int numBackRefs) {
+        if (mSelectionArgs != null) {
+            int max = -1;
+            for (int i = 0; i < mSelectionArgs.size(); i++) {
+                max = Math.max(max, mSelectionArgs.keyAt(i));
+            }
+
+            final String[] selectionArgs = new String[max + 1];
+            for (int i = 0; i < mSelectionArgs.size(); i++) {
+                final Object value = mSelectionArgs.valueAt(i);
+                final Object resolved;
+                if (value instanceof BackReference) {
+                    resolved = ((BackReference) value).resolve(backRefs, numBackRefs);
+                } else {
+                    resolved = value;
+                }
+                selectionArgs[mSelectionArgs.keyAt(i)] = String.valueOf(resolved);
+            }
+            return selectionArgs;
+        } else {
+            return null;
         }
-        return newArgs;
+    }
+
+    /** {@hide} */
+    public static String typeToString(int type) {
+        switch (type) {
+            case TYPE_INSERT: return "insert";
+            case TYPE_UPDATE: return "update";
+            case TYPE_DELETE: return "delete";
+            case TYPE_ASSERT: return "assert";
+            case TYPE_CALL: return "call";
+            default: return Integer.toString(type);
+        }
     }
 
     @Override
     public String toString() {
-        return "mType: " + mType + ", mUri: " + mUri +
-                ", mSelection: " + mSelection +
-                ", mExpectedCount: " + mExpectedCount +
-                ", mYieldAllowed: " + mYieldAllowed +
-                ", mValues: " + mValues +
-                ", mValuesBackReferences: " + mValuesBackReferences +
-                ", mSelectionArgsBackReferences: " + mSelectionArgsBackReferences;
+        final StringBuilder sb = new StringBuilder("ContentProviderOperation(");
+        sb.append("type=" + typeToString(mType) + " ");
+        if (mUri != null) {
+            sb.append("uri=" + mUri + " ");
+        }
+        if (mValues != null) {
+            sb.append("values=" + mValues + " ");
+        }
+        if (mSelection != null) {
+            sb.append("selection=" + mSelection + " ");
+        }
+        if (mSelectionArgs != null) {
+            sb.append("selectionArgs=" + mSelectionArgs + " ");
+        }
+        if (mExpectedCount != null) {
+            sb.append("expectedCount=" + mExpectedCount + " ");
+        }
+        if (mYieldAllowed) {
+            sb.append("yieldAllowed ");
+        }
+        if (mExceptionAllowed) {
+            sb.append("exceptionAllowed ");
+        }
+        sb.deleteCharAt(sb.length() - 1);
+        sb.append(")");
+        return sb.toString();
     }
 
-    /**
-     * Return the string representation of the requested back reference.
-     * @param backRefs an array of results
-     * @param numBackRefs the number of items in the backRefs array that are valid
-     * @param backRefIndex which backRef to be used
-     * @throws ArrayIndexOutOfBoundsException thrown if the backRefIndex is larger than
-     * the numBackRefs
-     * @return the string representation of the requested back reference.
-     */
-    private long backRefToValue(ContentProviderResult[] backRefs, int numBackRefs,
-            Integer backRefIndex) {
-        if (backRefIndex >= numBackRefs) {
-            Log.e(TAG, this.toString());
-            throw new ArrayIndexOutOfBoundsException("asked for back ref " + backRefIndex
-                    + " but there are only " + numBackRefs + " back refs");
-        }
-        ContentProviderResult backRef = backRefs[backRefIndex];
-        long backRefValue;
-        if (backRef.uri != null) {
-            backRefValue = ContentUris.parseId(backRef.uri);
-        } else {
-            backRefValue = backRef.count;
-        }
-        return backRefValue;
-    }
-
+    @Override
     public int describeContents() {
         return 0;
     }
 
     public static final @android.annotation.NonNull Creator<ContentProviderOperation> CREATOR =
             new Creator<ContentProviderOperation>() {
+        @Override
         public ContentProviderOperation createFromParcel(Parcel source) {
             return new ContentProviderOperation(source);
         }
 
+        @Override
         public ContentProviderOperation[] newArray(int size) {
             return new ContentProviderOperation[size];
         }
     };
 
+    /** {@hide} */
+    public static class BackReference implements Parcelable {
+        private final int fromIndex;
+        private final String fromKey;
+
+        private BackReference(int fromIndex, String fromKey) {
+            this.fromIndex = fromIndex;
+            this.fromKey = fromKey;
+        }
+
+        public BackReference(Parcel src) {
+            this.fromIndex = src.readInt();
+            if (src.readInt() != 0) {
+                this.fromKey = src.readString();
+            } else {
+                this.fromKey = null;
+            }
+        }
+
+        public Object resolve(ContentProviderResult[] backRefs, int numBackRefs) {
+            if (fromIndex >= numBackRefs) {
+                Log.e(TAG, this.toString());
+                throw new ArrayIndexOutOfBoundsException("asked for back ref " + fromIndex
+                        + " but there are only " + numBackRefs + " back refs");
+            }
+            ContentProviderResult backRef = backRefs[fromIndex];
+            Object backRefValue;
+            if (backRef.extras != null) {
+                backRefValue = backRef.extras.get(fromKey);
+            } else if (backRef.uri != null) {
+                backRefValue = ContentUris.parseId(backRef.uri);
+            } else {
+                backRefValue = (long) backRef.count;
+            }
+            return backRefValue;
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeInt(fromIndex);
+            if (fromKey != null) {
+                dest.writeInt(1);
+                dest.writeString(fromKey);
+            } else {
+                dest.writeInt(0);
+            }
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        public static final @android.annotation.NonNull Creator<BackReference> CREATOR =
+                new Creator<BackReference>() {
+            @Override
+            public BackReference createFromParcel(Parcel source) {
+                return new BackReference(source);
+            }
+
+            @Override
+            public BackReference[] newArray(int size) {
+                return new BackReference[size];
+            }
+        };
+    }
+
     /**
      * Used to add parameters to a {@link ContentProviderOperation}. The {@link Builder} is
      * first created by calling {@link ContentProviderOperation#newInsert(android.net.Uri)},
@@ -507,35 +647,36 @@
     public static class Builder {
         private final int mType;
         private final Uri mUri;
+        private final String mMethod;
+        private final String mArg;
+        private ArrayMap<String, Object> mValues;
+        private ArrayMap<String, Object> mExtras;
         private String mSelection;
-        private String[] mSelectionArgs;
-        private ContentValues mValues;
+        private SparseArray<Object> mSelectionArgs;
         private Integer mExpectedCount;
-        private ContentValues mValuesBackReferences;
-        private Map<Integer, Integer> mSelectionArgsBackReferences;
         private boolean mYieldAllowed;
-        private boolean mFailureAllowed;
+        private boolean mExceptionAllowed;
 
-        /** Create a {@link Builder} of a given type. The uri must not be null. */
         private Builder(int type, Uri uri) {
-            if (uri == null) {
-                throw new IllegalArgumentException("uri must not be null");
-            }
+            this(type, uri, null, null);
+        }
+
+        private Builder(int type, Uri uri, String method, String arg) {
             mType = type;
-            mUri = uri;
+            mUri = Objects.requireNonNull(uri);
+            mMethod = method;
+            mArg = arg;
         }
 
         /** Create a ContentProviderOperation from this {@link Builder}. */
-        public ContentProviderOperation build() {
+        public @NonNull ContentProviderOperation build() {
             if (mType == TYPE_UPDATE) {
-                if ((mValues == null || mValues.isEmpty())
-                      && (mValuesBackReferences == null || mValuesBackReferences.isEmpty())) {
+                if ((mValues == null || mValues.isEmpty())) {
                     throw new IllegalArgumentException("Empty values");
                 }
             }
             if (mType == TYPE_ASSERT) {
                 if ((mValues == null || mValues.isEmpty())
-                      && (mValuesBackReferences == null || mValuesBackReferences.isEmpty())
                         && (mExpectedCount == null)) {
                     throw new IllegalArgumentException("Empty values");
                 }
@@ -543,152 +684,259 @@
             return new ContentProviderOperation(this);
         }
 
-        /**
-         * Add a {@link ContentValues} of back references. The key is the name of the column
-         * and the value is an integer that is the index of the previous result whose
-         * value should be used for the column. The value is added as a {@link String}.
-         * A column value from the back references takes precedence over a value specified in
-         * {@link #withValues}.
-         * This can only be used with builders of type insert, update, or assert.
-         * @return this builder, to allow for chaining.
-         */
-        public Builder withValueBackReferences(ContentValues backReferences) {
-            if (mType != TYPE_INSERT && mType != TYPE_UPDATE && mType != TYPE_ASSERT) {
-                throw new IllegalArgumentException(
-                        "only inserts, updates, and asserts can have value back-references");
-            }
-            mValuesBackReferences = backReferences;
-            return this;
-        }
-
-        /**
-         * Add a ContentValues back reference.
-         * A column value from the back references takes precedence over a value specified in
-         * {@link #withValues}.
-         * This can only be used with builders of type insert, update, or assert.
-         * @return this builder, to allow for chaining.
-         */
-        public Builder withValueBackReference(String key, int previousResult) {
-            if (mType != TYPE_INSERT && mType != TYPE_UPDATE && mType != TYPE_ASSERT) {
-                throw new IllegalArgumentException(
-                        "only inserts, updates, and asserts can have value back-references");
-            }
-            if (mValuesBackReferences == null) {
-                mValuesBackReferences = new ContentValues();
-            }
-            mValuesBackReferences.put(key, previousResult);
-            return this;
-        }
-
-        /**
-         * Add a back references as a selection arg. Any value at that index of the selection arg
-         * that was specified by {@link #withSelection} will be overwritten.
-         * This can only be used with builders of type update, delete, or assert.
-         * @return this builder, to allow for chaining.
-         */
-        public Builder withSelectionBackReference(int selectionArgIndex, int previousResult) {
-            if (mType != TYPE_UPDATE && mType != TYPE_DELETE && mType != TYPE_ASSERT) {
-                throw new IllegalArgumentException("only updates, deletes, and asserts "
-                        + "can have selection back-references");
-            }
-            if (mSelectionArgsBackReferences == null) {
-                mSelectionArgsBackReferences = new HashMap<Integer, Integer>();
-            }
-            mSelectionArgsBackReferences.put(selectionArgIndex, previousResult);
-            return this;
-        }
-
-        /**
-         * The ContentValues to use. This may be null. These values may be overwritten by
-         * the corresponding value specified by {@link #withValueBackReference} or by
-         * future calls to {@link #withValues} or {@link #withValue}.
-         * This can only be used with builders of type insert, update, or assert.
-         * @return this builder, to allow for chaining.
-         */
-        public Builder withValues(ContentValues values) {
-            if (mType != TYPE_INSERT && mType != TYPE_UPDATE && mType != TYPE_ASSERT) {
-                throw new IllegalArgumentException(
-                        "only inserts, updates, and asserts can have values");
-            }
+        private void setValue(@NonNull String key, @NonNull Object value) {
             if (mValues == null) {
-                mValues = new ContentValues();
+                mValues = new ArrayMap<>();
             }
-            mValues.putAll(values);
+            final boolean oldReference = mValues.get(key) instanceof BackReference;
+            final boolean newReference = value instanceof BackReference;
+            if (!oldReference || newReference) {
+                mValues.put(key, value);
+            }
+        }
+
+        private void setExtra(@NonNull String key, @NonNull Object value) {
+            if (mExtras == null) {
+                mExtras = new ArrayMap<>();
+            }
+            final boolean oldReference = mExtras.get(key) instanceof BackReference;
+            final boolean newReference = value instanceof BackReference;
+            if (!oldReference || newReference) {
+                mExtras.put(key, value);
+            }
+        }
+
+        private void setSelectionArg(int index, @NonNull Object value) {
+            if (mSelectionArgs == null) {
+                mSelectionArgs = new SparseArray<>();
+            }
+            final boolean oldReference = mSelectionArgs.get(index) instanceof BackReference;
+            final boolean newReference = value instanceof BackReference;
+            if (!oldReference || newReference) {
+                mSelectionArgs.put(index, value);
+            }
+        }
+
+        /**
+         * Configure the values to use for this operation. This method will
+         * replace any previously defined values for the contained keys, but it
+         * will not replace any back-reference requests.
+         * <p>
+         * Any value may be dynamically overwritten using the result of a
+         * previous operation by using methods such as
+         * {@link #withValueBackReference(String, int)}.
+         */
+        public @NonNull Builder withValues(@NonNull ContentValues values) {
+            assertValuesAllowed();
+            final ArrayMap<String, Object> rawValues = values.getValues();
+            for (int i = 0; i < rawValues.size(); i++) {
+                setValue(rawValues.keyAt(i), rawValues.valueAt(i));
+            }
             return this;
         }
 
         /**
-         * A value to insert or update. This value may be overwritten by
-         * the corresponding value specified by {@link #withValueBackReference}.
-         * This can only be used with builders of type insert, update, or assert.
-         * @param key the name of this value
-         * @param value the value itself. the type must be acceptable for insertion by
-         * {@link ContentValues#put}
-         * @return this builder, to allow for chaining.
+         * Configure the given value to use for this operation. This method will
+         * replace any previously defined value for this key.
+         *
+         * @param key the key indicating which value to configure
          */
-        public Builder withValue(String key, Object value) {
-            if (mType != TYPE_INSERT && mType != TYPE_UPDATE && mType != TYPE_ASSERT) {
-                throw new IllegalArgumentException("only inserts and updates can have values");
-            }
-            if (mValues == null) {
-                mValues = new ContentValues();
-            }
-            if (value == null) {
-                mValues.putNull(key);
-            } else if (value instanceof String) {
-                mValues.put(key, (String) value);
-            } else if (value instanceof Byte) {
-                mValues.put(key, (Byte) value);
-            } else if (value instanceof Short) {
-                mValues.put(key, (Short) value);
-            } else if (value instanceof Integer) {
-                mValues.put(key, (Integer) value);
-            } else if (value instanceof Long) {
-                mValues.put(key, (Long) value);
-            } else if (value instanceof Float) {
-                mValues.put(key, (Float) value);
-            } else if (value instanceof Double) {
-                mValues.put(key, (Double) value);
-            } else if (value instanceof Boolean) {
-                mValues.put(key, (Boolean) value);
-            } else if (value instanceof byte[]) {
-                mValues.put(key, (byte[]) value);
-            } else {
+        public @NonNull Builder withValue(@NonNull String key, @Nullable Object value) {
+            assertValuesAllowed();
+            if (!ContentValues.isSupportedValue(value)) {
                 throw new IllegalArgumentException("bad value type: " + value.getClass().getName());
             }
+            setValue(key, value);
             return this;
         }
 
         /**
-         * The selection and arguments to use. An occurrence of '?' in the selection will be
-         * replaced with the corresponding occurrence of the selection argument. Any of the
-         * selection arguments may be overwritten by a selection argument back reference as
-         * specified by {@link #withSelectionBackReference}.
-         * This can only be used with builders of type update, delete, or assert.
-         * @return this builder, to allow for chaining.
+         * Configure the given values to be dynamically overwritten using the
+         * result of a previous operation. This method will replace any
+         * previously defined values for these keys.
+         *
+         * @param backReferences set of values where the key indicates which
+         *            value to configure and the value the index indicating
+         *            which historical {@link ContentProviderResult} should
+         *            overwrite the value
          */
-        public Builder withSelection(String selection, String[] selectionArgs) {
-            if (mType != TYPE_UPDATE && mType != TYPE_DELETE && mType != TYPE_ASSERT) {
-                throw new IllegalArgumentException(
-                        "only updates, deletes, and asserts can have selections");
+        public @NonNull Builder withValueBackReferences(@NonNull ContentValues backReferences) {
+            assertValuesAllowed();
+            final ArrayMap<String, Object> rawValues = backReferences.getValues();
+            for (int i = 0; i < rawValues.size(); i++) {
+                setValue(rawValues.keyAt(i),
+                        new BackReference((int) rawValues.valueAt(i), null));
             }
+            return this;
+        }
+
+        /**
+         * Configure the given value to be dynamically overwritten using the
+         * result of a previous operation. This method will replace any
+         * previously defined value for this key.
+         *
+         * @param key the key indicating which value to configure
+         * @param fromIndex the index indicating which historical
+         *            {@link ContentProviderResult} should overwrite the value
+         */
+        public @NonNull Builder withValueBackReference(@NonNull String key, int fromIndex) {
+            assertValuesAllowed();
+            setValue(key, new BackReference(fromIndex, null));
+            return this;
+        }
+
+        /**
+         * Configure the given value to be dynamically overwritten using the
+         * result of a previous operation. This method will replace any
+         * previously defined value for this key.
+         *
+         * @param key the key indicating which value to configure
+         * @param fromIndex the index indicating which historical
+         *            {@link ContentProviderResult} should overwrite the value
+         * @param fromKey the key of indicating which
+         *            {@link ContentProviderResult#extras} value should
+         *            overwrite the value
+         */
+        public @NonNull Builder withValueBackReference(@NonNull String key, int fromIndex,
+                @NonNull String fromKey) {
+            assertValuesAllowed();
+            setValue(key, new BackReference(fromIndex, fromKey));
+            return this;
+        }
+
+        /**
+         * Configure the extras to use for this operation. This method will
+         * replace any previously defined values for the contained keys, but it
+         * will not replace any back-reference requests.
+         * <p>
+         * Any value may be dynamically overwritten using the result of a
+         * previous operation by using methods such as
+         * {@link #withExtraBackReference(String, int)}.
+         */
+        public @NonNull Builder withExtras(@NonNull Bundle extras) {
+            assertExtrasAllowed();
+            for (String key : extras.keySet()) {
+                setExtra(key, extras.get(key));
+            }
+            return this;
+        }
+
+        /**
+         * Configure the given extra to use for this operation. This method will
+         * replace any previously defined extras for this key.
+         *
+         * @param key the key indicating which extra to configure
+         */
+        public @NonNull Builder withExtra(@NonNull String key, @Nullable Object value) {
+            assertExtrasAllowed();
+            setExtra(key, value);
+            return this;
+        }
+
+        /**
+         * Configure the given extra to be dynamically overwritten using the
+         * result of a previous operation. This method will replace any
+         * previously defined extras for this key.
+         *
+         * @param key the key indicating which extra to configure
+         * @param fromIndex the index indicating which historical
+         *            {@link ContentProviderResult} should overwrite the extra
+         */
+        public @NonNull Builder withExtraBackReference(@NonNull String key, int fromIndex) {
+            assertExtrasAllowed();
+            setExtra(key, new BackReference(fromIndex, null));
+            return this;
+        }
+
+        /**
+         * Configure the given extra to be dynamically overwritten using the
+         * result of a previous operation. This method will replace any
+         * previously defined extras for this key.
+         *
+         * @param key the key indicating which extra to configure
+         * @param fromIndex the index indicating which historical
+         *            {@link ContentProviderResult} should overwrite the extra
+         * @param fromKey the key of indicating which
+         *            {@link ContentProviderResult#extras} value should
+         *            overwrite the extra
+         */
+        public @NonNull Builder withExtraBackReference(@NonNull String key, int fromIndex,
+                @NonNull String fromKey) {
+            assertExtrasAllowed();
+            setExtra(key, new BackReference(fromIndex, fromKey));
+            return this;
+        }
+
+        /**
+         * Configure the selection and selection arguments to use for this
+         * operation. This method will replace any previously defined selection
+         * and selection arguments, but it will not replace any back-reference
+         * requests.
+         * <p>
+         * An occurrence of {@code ?} in the selection will be replaced with the
+         * corresponding selection argument when the operation is executed.
+         * <p>
+         * Any selection argument may be dynamically overwritten using the
+         * result of a previous operation by using methods such as
+         * {@link #withSelectionBackReference(int, int)}.
+         */
+        public @NonNull Builder withSelection(@Nullable String selection,
+                @Nullable String[] selectionArgs) {
+            assertSelectionAllowed();
             mSelection = selection;
-            if (selectionArgs == null) {
-                mSelectionArgs = null;
-            } else {
-                mSelectionArgs = new String[selectionArgs.length];
-                System.arraycopy(selectionArgs, 0, mSelectionArgs, 0, selectionArgs.length);
+            if (selectionArgs != null) {
+                for (int i = 0; i < selectionArgs.length; i++) {
+                    setSelectionArg(i, selectionArgs[i]);
+                }
             }
             return this;
         }
 
         /**
+         * Configure the given selection argument to be dynamically overwritten
+         * using the result of a previous operation. This method will replace
+         * any previously defined selection argument at this index.
+         *
+         * @param index the index indicating which selection argument to
+         *            configure
+         * @param fromIndex the index indicating which historical
+         *            {@link ContentProviderResult} should overwrite the
+         *            selection argument
+         */
+        public @NonNull Builder withSelectionBackReference(int index, int fromIndex) {
+            assertSelectionAllowed();
+            setSelectionArg(index, new BackReference(fromIndex, null));
+            return this;
+        }
+
+        /**
+         * Configure the given selection argument to be dynamically overwritten
+         * using the result of a previous operation. This method will replace
+         * any previously defined selection argument at this index.
+         *
+         * @param index the index indicating which selection argument to
+         *            configure
+         * @param fromIndex the index indicating which historical
+         *            {@link ContentProviderResult} should overwrite the
+         *            selection argument
+         * @param fromKey the key of indicating which
+         *            {@link ContentProviderResult#extras} value should
+         *            overwrite the selection argument
+         */
+        public @NonNull Builder withSelectionBackReference(int index, int fromIndex,
+                @NonNull String fromKey) {
+            assertSelectionAllowed();
+            setSelectionArg(index, new BackReference(fromIndex, fromKey));
+            return this;
+        }
+
+        /**
          * If set then if the number of rows affected by this operation does not match
          * this count {@link OperationApplicationException} will be throw.
          * This can only be used with builders of type update, delete, or assert.
          * @return this builder, to allow for chaining.
          */
-        public Builder withExpectedCount(int count) {
+        public @NonNull Builder withExpectedCount(int count) {
             if (mType != TYPE_UPDATE && mType != TYPE_DELETE && mType != TYPE_ASSERT) {
                 throw new IllegalArgumentException(
                         "only updates, deletes, and asserts can have expected counts");
@@ -703,15 +951,59 @@
          * @return this builder, to allow for chaining.
          * @see android.database.sqlite.SQLiteDatabase#yieldIfContendedSafely()
          */
-        public Builder withYieldAllowed(boolean yieldAllowed) {
+        public @NonNull Builder withYieldAllowed(boolean yieldAllowed) {
             mYieldAllowed = yieldAllowed;
             return this;
         }
 
-        /** {@hide} */
-        public Builder withFailureAllowed(boolean failureAllowed) {
-            mFailureAllowed = failureAllowed;
+        /**
+         * If set to true, this operation allows subsequent operations to
+         * continue even if this operation throws an exception. When true, any
+         * encountered exception is returned via
+         * {@link ContentProviderResult#exception}.
+         */
+        public @NonNull Builder withExceptionAllowed(boolean exceptionAllowed) {
+            mExceptionAllowed = exceptionAllowed;
             return this;
         }
+
+        /** {@hide} */
+        public @NonNull Builder withFailureAllowed(boolean failureAllowed) {
+            return withExceptionAllowed(failureAllowed);
+        }
+
+        private void assertValuesAllowed() {
+            switch (mType) {
+                case TYPE_INSERT:
+                case TYPE_UPDATE:
+                case TYPE_ASSERT:
+                    break;
+                default:
+                    throw new IllegalArgumentException(
+                            "Values not supported for " + typeToString(mType));
+            }
+        }
+
+        private void assertSelectionAllowed() {
+            switch (mType) {
+                case TYPE_UPDATE:
+                case TYPE_DELETE:
+                case TYPE_ASSERT:
+                    break;
+                default:
+                    throw new IllegalArgumentException(
+                            "Selection not supported for " + typeToString(mType));
+            }
+        }
+
+        private void assertExtrasAllowed() {
+            switch (mType) {
+                case TYPE_CALL:
+                    break;
+                default:
+                    throw new IllegalArgumentException(
+                            "Extras not supported for " + typeToString(mType));
+            }
+        }
     }
 }
diff --git a/core/java/android/content/ContentProviderResult.java b/core/java/android/content/ContentProviderResult.java
index b301011..11dda83 100644
--- a/core/java/android/content/ContentProviderResult.java
+++ b/core/java/android/content/ContentProviderResult.java
@@ -16,40 +16,50 @@
 
 package android.content;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.net.Uri;
+import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.ParcelableException;
 
-import com.android.internal.util.Preconditions;
+import java.util.Objects;
 
 /**
- * Contains the result of the application of a {@link ContentProviderOperation}. It is guaranteed
- * to have exactly one of {@link #uri} or {@link #count} set.
+ * Contains the result of the application of a {@link ContentProviderOperation}.
+ * <p>
+ * It is guaranteed to have exactly one of {@link #uri}, {@link #count},
+ * {@link #extras}, or {@link #exception} set.
  */
 public class ContentProviderResult implements Parcelable {
-    public final Uri uri;
-    public final Integer count;
-    /** {@hide} */
-    public final String failure;
+    public final @Nullable Uri uri;
+    public final @Nullable Integer count;
+    public final @Nullable Bundle extras;
+    public final @Nullable Exception exception;
 
-    public ContentProviderResult(Uri uri) {
-        this(Preconditions.checkNotNull(uri), null, null);
+    public ContentProviderResult(@NonNull Uri uri) {
+        this(Objects.requireNonNull(uri), null, null, null);
     }
 
     public ContentProviderResult(int count) {
-        this(null, count, null);
+        this(null, count, null, null);
+    }
+
+    public ContentProviderResult(@NonNull Bundle extras) {
+        this(null, null, Objects.requireNonNull(extras), null);
+    }
+
+    public ContentProviderResult(@NonNull Exception exception) {
+        this(null, null, null, exception);
     }
 
     /** {@hide} */
-    public ContentProviderResult(String failure) {
-        this(null, null, failure);
-    }
-
-    /** {@hide} */
-    public ContentProviderResult(Uri uri, Integer count, String failure) {
+    public ContentProviderResult(Uri uri, Integer count, Bundle extras, Exception exception) {
         this.uri = uri;
         this.count = count;
-        this.failure = failure;
+        this.extras = extras;
+        this.exception = exception;
     }
 
     public ContentProviderResult(Parcel source) {
@@ -64,9 +74,14 @@
             count = null;
         }
         if (source.readInt() != 0) {
-            failure = source.readString();
+            extras = source.readBundle();
         } else {
-            failure = null;
+            extras = null;
+        }
+        if (source.readInt() != 0) {
+            exception = (Exception) ParcelableException.readFromParcel(source);
+        } else {
+            exception = null;
         }
     }
 
@@ -74,7 +89,8 @@
     public ContentProviderResult(ContentProviderResult cpr, int userId) {
         uri = ContentProvider.maybeAddUserId(cpr.uri, userId);
         count = cpr.count;
-        failure = cpr.failure;
+        extras = cpr.extras;
+        exception = cpr.exception;
     }
 
     @Override
@@ -91,9 +107,15 @@
         } else {
             dest.writeInt(0);
         }
-        if (failure != null) {
+        if (extras != null) {
             dest.writeInt(1);
-            dest.writeString(failure);
+            dest.writeBundle(extras);
+        } else {
+            dest.writeInt(0);
+        }
+        if (exception != null) {
+            dest.writeInt(1);
+            ParcelableException.writeToParcel(dest, exception);
         } else {
             dest.writeInt(0);
         }
@@ -126,8 +148,11 @@
         if (count != null) {
             sb.append("count=" + count + " ");
         }
-        if (uri != null) {
-            sb.append("failure=" + failure + " ");
+        if (extras != null) {
+            sb.append("extras=" + extras + " ");
+        }
+        if (exception != null) {
+            sb.append("exception=" + exception + " ");
         }
         sb.deleteCharAt(sb.length() - 1);
         sb.append(")");
diff --git a/core/java/android/content/ContentValues.java b/core/java/android/content/ContentValues.java
index eafeed2..8223a0b 100644
--- a/core/java/android/content/ContentValues.java
+++ b/core/java/android/content/ContentValues.java
@@ -16,6 +16,8 @@
 
 package android.content;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -217,6 +219,33 @@
         mMap.put(key, null);
     }
 
+    /** {@hide} */
+    public void putObject(@Nullable String key, @Nullable Object value) {
+        if (value == null) {
+            putNull(key);
+        } else if (value instanceof String) {
+            put(key, (String) value);
+        } else if (value instanceof Byte) {
+            put(key, (Byte) value);
+        } else if (value instanceof Short) {
+            put(key, (Short) value);
+        } else if (value instanceof Integer) {
+            put(key, (Integer) value);
+        } else if (value instanceof Long) {
+            put(key, (Long) value);
+        } else if (value instanceof Float) {
+            put(key, (Float) value);
+        } else if (value instanceof Double) {
+            put(key, (Double) value);
+        } else if (value instanceof Boolean) {
+            put(key, (Boolean) value);
+        } else if (value instanceof byte[]) {
+            put(key, (byte[]) value);
+        } else {
+            throw new IllegalArgumentException("Unsupported type " + value.getClass());
+        }
+    }
+
     /**
      * Returns the number of values.
      *
@@ -556,4 +585,31 @@
         }
         return sb.toString();
     }
+
+    /** {@hide} */
+    public static boolean isSupportedValue(Object value) {
+        if (value == null) {
+            return true;
+        } else if (value instanceof String) {
+            return true;
+        } else if (value instanceof Byte) {
+            return true;
+        } else if (value instanceof Short) {
+            return true;
+        } else if (value instanceof Integer) {
+            return true;
+        } else if (value instanceof Long) {
+            return true;
+        } else if (value instanceof Float) {
+            return true;
+        } else if (value instanceof Double) {
+            return true;
+        } else if (value instanceof Boolean) {
+            return true;
+        } else if (value instanceof byte[]) {
+            return true;
+        } else {
+            return false;
+        }
+    }
 }
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index 5ac13d8..a0170da 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -206,10 +206,16 @@
                     continue;
                 }
 
-                if (filterTags == null || Arrays.binarySearch(filterTags,
-                        CameraMetadataNative.getTag(keyName, vendorId)) >= 0) {
+
+                if (filterTags != null && Arrays.binarySearch(filterTags,
+                        CameraMetadataNative.getTag(keyName, vendorId)) < 0) {
+                    // ignore vendor keys not in filterTags
+                    continue;
+                }
+                if (instance == null || instance.getProtected(k) != null)  {
                     keyList.add(k);
                 }
+
             }
         }
 
diff --git a/core/java/android/hardware/radio/TunerAdapter.java b/core/java/android/hardware/radio/TunerAdapter.java
index be2846f..aa5480a 100644
--- a/core/java/android/hardware/radio/TunerAdapter.java
+++ b/core/java/android/hardware/radio/TunerAdapter.java
@@ -271,6 +271,8 @@
             mCallback.setProgramListObserver(list, () -> {
                 try {
                     mTuner.stopProgramListUpdates();
+                } catch (IllegalStateException ex) {
+                    // it's fine to not stop updates if tuner is already closed
                 } catch (RemoteException ex) {
                     Log.e(TAG, "Couldn't stop program list updates", ex);
                 }
diff --git a/core/java/android/net/LinkQualityInfo.java b/core/java/android/net/LinkQualityInfo.java
index 3c5d474..2e6915f 100644
--- a/core/java/android/net/LinkQualityInfo.java
+++ b/core/java/android/net/LinkQualityInfo.java
@@ -24,8 +24,8 @@
  *  Class that represents useful attributes of generic network links
  *  such as the upload/download throughput or packet error rate.
  *  Generally speaking, you should be dealing with instances of
- *  LinkQualityInfo subclasses, such as {@link android.net.#WifiLinkQualityInfo}
- *  or {@link android.net.#MobileLinkQualityInfo} which provide additional
+ *  LinkQualityInfo subclasses, such as {@link android.net.WifiLinkQualityInfo}
+ *  or {@link android.net.MobileLinkQualityInfo} which provide additional
  *  information.
  *  @hide
  */
diff --git a/core/java/android/os/BaseBundle.java b/core/java/android/os/BaseBundle.java
index 7f63f8f..9d9c683 100644
--- a/core/java/android/os/BaseBundle.java
+++ b/core/java/android/os/BaseBundle.java
@@ -563,6 +563,35 @@
         return mMap.keySet();
     }
 
+    /** {@hide} */
+    public void putObject(@Nullable String key, @Nullable Object value) {
+        if (value == null) {
+            putString(key, null);
+        } else if (value instanceof Boolean) {
+            putBoolean(key, (Boolean) value);
+        } else if (value instanceof Integer) {
+            putInt(key, (Integer) value);
+        } else if (value instanceof Long) {
+            putLong(key, (Long) value);
+        } else if (value instanceof Double) {
+            putDouble(key, (Double) value);
+        } else if (value instanceof String) {
+            putString(key, (String) value);
+        } else if (value instanceof boolean[]) {
+            putBooleanArray(key, (boolean[]) value);
+        } else if (value instanceof int[]) {
+            putIntArray(key, (int[]) value);
+        } else if (value instanceof long[]) {
+            putLongArray(key, (long[]) value);
+        } else if (value instanceof double[]) {
+            putDoubleArray(key, (double[]) value);
+        } else if (value instanceof String[]) {
+            putStringArray(key, (String[]) value);
+        } else {
+            throw new IllegalArgumentException("Unsupported type " + value.getClass());
+        }
+    }
+
     /**
      * Inserts a Boolean value into the mapping of this Bundle, replacing
      * any existing value for the given key.  Either key or value may be null.
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index a399e83..c5c0945 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -21,7 +21,6 @@
 
 import android.annotation.UnsupportedAppUsage;
 import android.app.ActivityManager;
-import android.app.job.JobParameters;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.server.ServerProtoEnums;
@@ -45,6 +44,7 @@
 import com.android.internal.location.gnssmetrics.GnssMetrics;
 import com.android.internal.os.BatterySipper;
 import com.android.internal.os.BatteryStatsHelper;
+import com.android.internal.util.Preconditions;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -56,6 +56,7 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.function.Function;
 
 /**
  * A class providing access to battery usage statistics, including information on
@@ -407,6 +408,40 @@
     };
 
     /**
+     * "Job stop reason codes" from the job scheduler subsystem, which we can't refer to from this
+     * class, so we initialize it from the job scheduler side at runtime using
+     * {@link #setJobStopReasons}.
+     */
+    private static int[] sJobStopReasonCodes = {0};
+
+    /**
+     * A function that converts the "job stop reason codes" to their names.
+     *
+     * Similarly to {@link #sJobStopReasonCodes} it's initialized by the job scheduler subsystem
+     * using {@link #setJobStopReasons}.
+     */
+    private static Function<Integer, String> sJobStopReasonNameConverter = (x) -> "unknown";
+
+    /**
+     * Set by the job scheduler subsystem to "push" job stop reasons, and a function that returns
+     * the "name" of each code. We do it this way to remove a build time dependency from this
+     * class to the job scheduler framework code.
+     *
+     * Note the passed array will be used as-is, without copying. The caller must not change
+     * the array it passed to it.
+     *
+     * @hide
+     */
+    public static void setJobStopReasons(int[] reasonCodes,
+            Function<Integer, String> jobStopReasonNameConverter) {
+        Preconditions.checkArgument(reasonCodes.length > 0);
+        Preconditions.checkArgument(jobStopReasonNameConverter != null);
+
+        sJobStopReasonCodes = reasonCodes;
+        sJobStopReasonNameConverter = jobStopReasonNameConverter;
+    }
+
+    /**
      * State for keeping track of counting information.
      */
     public static abstract class Counter {
@@ -4260,17 +4295,18 @@
                 }
             }
 
+            final Object[] jobCompletionArgs = new Object[sJobStopReasonCodes.length + 1];
+
             final ArrayMap<String, SparseIntArray> completions = u.getJobCompletionStats();
             for (int ic=completions.size()-1; ic>=0; ic--) {
                 SparseIntArray types = completions.valueAt(ic);
                 if (types != null) {
-                    dumpLine(pw, uid, category, JOB_COMPLETION_DATA,
-                            "\"" + completions.keyAt(ic) + "\"",
-                            types.get(JobParameters.REASON_CANCELED, 0),
-                            types.get(JobParameters.REASON_CONSTRAINTS_NOT_SATISFIED, 0),
-                            types.get(JobParameters.REASON_PREEMPT, 0),
-                            types.get(JobParameters.REASON_TIMEOUT, 0),
-                            types.get(JobParameters.REASON_DEVICE_IDLE, 0));
+                    jobCompletionArgs[0] = "\"" + completions.keyAt(ic) + "\"";
+                    for (int i = 0; i < sJobStopReasonCodes.length; i++) {
+                        jobCompletionArgs[i + 1] = types.get(sJobStopReasonCodes[i], 0);
+                    }
+
+                    dumpLine(pw, uid, category, JOB_COMPLETION_DATA, jobCompletionArgs);
                 }
             }
 
@@ -5887,7 +5923,7 @@
                     pw.print(":");
                     for (int it=0; it<types.size(); it++) {
                         pw.print(" ");
-                        pw.print(JobParameters.getReasonName(types.keyAt(it)));
+                        pw.print(sJobStopReasonNameConverter.apply(types.keyAt(it)));
                         pw.print("(");
                         pw.print(types.valueAt(it));
                         pw.print("x)");
@@ -7478,13 +7514,6 @@
 
             // Job completion (JOB_COMPLETION_DATA)
             final ArrayMap<String, SparseIntArray> completions = u.getJobCompletionStats();
-            final int[] reasons = new int[]{
-                JobParameters.REASON_CANCELED,
-                JobParameters.REASON_CONSTRAINTS_NOT_SATISFIED,
-                JobParameters.REASON_PREEMPT,
-                JobParameters.REASON_TIMEOUT,
-                JobParameters.REASON_DEVICE_IDLE,
-            };
             for (int ic = 0; ic < completions.size(); ++ic) {
                 SparseIntArray types = completions.valueAt(ic);
                 if (types != null) {
@@ -7492,7 +7521,7 @@
 
                     proto.write(UidProto.JobCompletion.NAME, completions.keyAt(ic));
 
-                    for (int r : reasons) {
+                    for (int r : sJobStopReasonCodes) {
                         long rToken = proto.start(UidProto.JobCompletion.REASON_COUNT);
                         proto.write(UidProto.JobCompletion.ReasonCount.NAME, r);
                         proto.write(UidProto.JobCompletion.ReasonCount.COUNT, types.get(r, 0));
diff --git a/core/java/android/os/BugreportManager.java b/core/java/android/os/BugreportManager.java
index 3cdebac..c5cbad3 100644
--- a/core/java/android/os/BugreportManager.java
+++ b/core/java/android/os/BugreportManager.java
@@ -235,22 +235,5 @@
                 Binder.restoreCallingIdentity(identity);
             }
         }
-
-        // Old methods; should go away
-        @Override
-        public void onProgressUpdated(int progress) throws RemoteException {
-            // TODO(b/111441001): remove from interface
-        }
-
-        @Override
-        public void onMaxProgressUpdated(int maxProgress) throws RemoteException {
-            // TODO(b/111441001): remove from interface
-        }
-
-        @Override
-        public void onSectionComplete(String title, int status, int size, int durationMs)
-                throws RemoteException {
-            // TODO(b/111441001): remove from interface
-        }
     }
 }
diff --git a/core/java/android/os/Bundle.java b/core/java/android/os/Bundle.java
index b82e517..7e11840 100644
--- a/core/java/android/os/Bundle.java
+++ b/core/java/android/os/Bundle.java
@@ -435,6 +435,56 @@
         return bundle;
     }
 
+    /** {@hide} */
+    @Override
+    public void putObject(@Nullable String key, @Nullable Object value) {
+        if (value instanceof Byte) {
+            putByte(key, (Byte) value);
+        } else if (value instanceof Character) {
+            putChar(key, (Character) value);
+        } else if (value instanceof Short) {
+            putShort(key, (Short) value);
+        } else if (value instanceof Float) {
+            putFloat(key, (Float) value);
+        } else if (value instanceof CharSequence) {
+            putCharSequence(key, (CharSequence) value);
+        } else if (value instanceof Parcelable) {
+            putParcelable(key, (Parcelable) value);
+        } else if (value instanceof Size) {
+            putSize(key, (Size) value);
+        } else if (value instanceof SizeF) {
+            putSizeF(key, (SizeF) value);
+        } else if (value instanceof Parcelable[]) {
+            putParcelableArray(key, (Parcelable[]) value);
+        } else if (value instanceof ArrayList) {
+            putParcelableArrayList(key, (ArrayList) value);
+        } else if (value instanceof List) {
+            putParcelableList(key, (List) value);
+        } else if (value instanceof SparseArray) {
+            putSparseParcelableArray(key, (SparseArray) value);
+        } else if (value instanceof Serializable) {
+            putSerializable(key, (Serializable) value);
+        } else if (value instanceof byte[]) {
+            putByteArray(key, (byte[]) value);
+        } else if (value instanceof short[]) {
+            putShortArray(key, (short[]) value);
+        } else if (value instanceof char[]) {
+            putCharArray(key, (char[]) value);
+        } else if (value instanceof float[]) {
+            putFloatArray(key, (float[]) value);
+        } else if (value instanceof CharSequence[]) {
+            putCharSequenceArray(key, (CharSequence[]) value);
+        } else if (value instanceof Bundle) {
+            putBundle(key, (Bundle) value);
+        } else if (value instanceof Binder) {
+            putBinder(key, (Binder) value);
+        } else if (value instanceof IBinder) {
+            putIBinder(key, (IBinder) value);
+        } else {
+            super.putObject(key, value);
+        }
+    }
+
     /**
      * Inserts a byte value into the mapping of this Bundle, replacing
      * any existing value for the given key.
diff --git a/core/java/android/os/UserManagerInternal.java b/core/java/android/os/UserManagerInternal.java
index 1f6c3cc..2e3b000 100644
--- a/core/java/android/os/UserManagerInternal.java
+++ b/core/java/android/os/UserManagerInternal.java
@@ -221,4 +221,7 @@
      */
     public abstract boolean isSettingRestrictedForUser(String setting, int userId, String value,
             int callingUid);
+
+    /** @return a specific user restriction that's in effect currently. */
+    public abstract boolean hasUserRestriction(String restriction, int userId);
 }
diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java
index cdd0d45..eaf9929 100644
--- a/core/java/android/os/ZygoteProcess.java
+++ b/core/java/android/os/ZygoteProcess.java
@@ -738,6 +738,31 @@
     }
 
     /**
+     * Notify the Zygote processes that boot completed.
+     */
+    public void bootCompleted() {
+        // Notify both the 32-bit and 64-bit zygote.
+        if (Build.SUPPORTED_32_BIT_ABIS.length > 0) {
+            bootCompleted(Build.SUPPORTED_32_BIT_ABIS[0]);
+        }
+        if (Build.SUPPORTED_64_BIT_ABIS.length > 0) {
+            bootCompleted(Build.SUPPORTED_64_BIT_ABIS[0]);
+        }
+    }
+
+    private void bootCompleted(String abi) {
+        try {
+            synchronized (mLock) {
+                ZygoteState state = openZygoteSocketIfNeeded(abi);
+                state.mZygoteOutputWriter.write("1\n--boot-completed\n");
+                state.mZygoteOutputWriter.flush();
+            }
+        } catch (Exception ex) {
+            throw new RuntimeException("Failed to inform zygote of boot_completed", ex);
+        }
+    }
+
+    /**
      * Push hidden API blacklisting exemptions into the zygote process(es).
      *
      * <p>The list of exemptions will take affect for all new processes forked from the zygote after
diff --git a/core/java/android/os/image/DynamicSystemManager.java b/core/java/android/os/image/DynamicSystemManager.java
index cec1945..e4f88c5 100644
--- a/core/java/android/os/image/DynamicSystemManager.java
+++ b/core/java/android/os/image/DynamicSystemManager.java
@@ -76,7 +76,7 @@
         @RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM)
         public boolean commit() {
             try {
-                return mService.commit();
+                return mService.setEnable(true, true);
             } catch (RemoteException e) {
                 throw new RuntimeException(e.toString());
             }
@@ -188,9 +188,9 @@
      * @return {@code true} if the call succeeds. {@code false} if there is no installed image.
      */
     @RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM)
-    public boolean setEnable(boolean enable) {
+    public boolean setEnable(boolean enable, boolean oneShot) {
         try {
-            return mService.setEnable(enable);
+            return mService.setEnable(enable, oneShot);
         } catch (RemoteException e) {
             throw new RuntimeException(e.toString());
         }
diff --git a/core/java/android/os/image/IDynamicSystemService.aidl b/core/java/android/os/image/IDynamicSystemService.aidl
index a34daca..2f4ab2d 100644
--- a/core/java/android/os/image/IDynamicSystemService.aidl
+++ b/core/java/android/os/image/IDynamicSystemService.aidl
@@ -72,9 +72,11 @@
     /**
      * Enable or disable DynamicSystem.
      *
+     * @param oneShot       If true, the GSI will boot once and then disable itself.
+     *
      * @return true if the call succeeds
      */
-    boolean setEnable(boolean enable);
+    boolean setEnable(boolean enable, boolean oneShot);
 
     /**
      * Write a chunk of the DynamicSystem system image
@@ -83,10 +85,4 @@
      */
     boolean write(in byte[] buf);
 
-    /**
-     * Finish write and make device to boot into the it after reboot.
-     *
-     * @return true if the call succeeds
-     */
-    boolean commit();
 }
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 69c1295..5b9205d 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -1987,11 +1987,31 @@
      */
     public static final int FLAG_ALLOCATE_DEFY_HALF_RESERVED = 1 << 2;
 
+    /**
+     * Flag indicating that a disk space check should not take into account
+     * freeable cached space when determining allocatable space.
+     *
+     * Intended for use with {@link #getAllocatableBytes()}.
+     * @hide
+     */
+    public static final int FLAG_ALLOCATE_NON_CACHE_ONLY = 1 << 3;
+
+    /**
+     * Flag indicating that a disk space check should only return freeable
+     * cached space when determining allocatable space.
+     *
+     * Intended for use with {@link #getAllocatableBytes()}.
+     * @hide
+     */
+    public static final int FLAG_ALLOCATE_CACHE_ONLY = 1 << 4;
+
     /** @hide */
     @IntDef(flag = true, prefix = { "FLAG_ALLOCATE_" }, value = {
             FLAG_ALLOCATE_AGGRESSIVE,
             FLAG_ALLOCATE_DEFY_ALL_RESERVED,
             FLAG_ALLOCATE_DEFY_HALF_RESERVED,
+            FLAG_ALLOCATE_NON_CACHE_ONLY,
+            FLAG_ALLOCATE_CACHE_ONLY,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface AllocateFlags {}
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index 81e1eb9..af3a16c 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -870,8 +870,8 @@
     protected interface ContactOptionsColumns {
         /**
          * The number of times a contact has been contacted.
-         * <p class="caution"><b>Caution: </b>As of January 7, 2019, this field is obsolete. For
-         * more information, see the
+         * <p class="caution"><b>Caution: </b>If you publish your app to the Google Play Store,
+         * this field is obsolete, regardless of Android version. For more information, see the
          * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
          * page.</p>
          * <P>Type: INTEGER</P>
@@ -885,8 +885,8 @@
 
         /**
          * The last time a contact was contacted.
-         * <p class="caution"><b>Caution: </b>As of January 7, 2019, this field is obsolete. For
-         * more information, see the
+         * <p class="caution"><b>Caution: </b>If you publish your app to the Google Play Store,
+         * this field is obsolete, regardless of Android version. For more information, see the
          * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
          * page.</p>
          * <P>Type: INTEGER</P>
@@ -1691,10 +1691,10 @@
          * TIMES_CONTACTED field is incremented by 1 and the LAST_TIME_CONTACTED
          * field is populated with the current system time.
          *
-         * <p class="caution"><b>Caution: </b>As of January 7, 2019, this method is obsolete. For
-         * more information, see the
+         * <p class="caution"><b>Caution: </b>If you publish your app to the Google Play Store,
+         * this field is obsolete, regardless of Android version. For more information, see the
          * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
-         * page.
+         * page.</p>
          *
          * @param resolver the ContentResolver to use
          * @param contactId the person who was contacted
@@ -1730,8 +1730,8 @@
          * Frequent contacts are no longer included in the result as of
          * Android version {@link android.os.Build.VERSION_CODES#Q}.
          *
-         * <p class="caution"><b>Caution: </b>As of January 7, 2019, this field no longer sorts
-         * results based on contacts frequency. For more information, see the
+         * <p class="caution"><b>Caution: </b>If you publish your app to the Google Play Store, this
+         * field doesn't sort results based on contacts frequency. For more information, see the
          * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
          * page.
          */
@@ -1745,8 +1745,8 @@
          * Android version {@link android.os.Build.VERSION_CODES#Q}.
          * This URI always returns an empty cursor.
          *
-         * <p class="caution"><b>Caution: </b>As of January 7, 2019, this field no longer sorts
-         * results based on contacts frequency. For more information, see the
+         * <p class="caution"><b>Caution: </b>If you publish your app to the Google Play Store, this
+         * field doesn't sort results based on contacts frequency. For more information, see the
          * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
          * page.
          */
@@ -1760,8 +1760,8 @@
          * various parts of the contact name. The filter argument should be passed
          * as an additional path segment after this URI.
          *
-         * <p class="caution"><b>Caution: </b>As of January 7, 2019, this field no longer sorts
-         * results based on contacts frequency. For more information, see the
+         * <p class="caution"><b>Caution: </b>If you publish your app to the Google Play Store, this
+         * field doesn't sort results based on contacts frequency. For more information, see the
          * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
          * page.
          */
@@ -4292,10 +4292,10 @@
          * Android version {@link android.os.Build.VERSION_CODES#Q}.
          * This column always contains 0.
          *
-         * <p class="caution"><b>Caution: </b>As of January 7, 2019, this field is obsolete.
-         * For more information, see the
+         * <p class="caution"><b>Caution: </b>If you publish your app to the Google Play Store,
+         * this field is obsolete, regardless of Android version. For more information, see the
          * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
-         * page.
+         * page.</p>
          */
         @Deprecated
         public static final String LAST_TIME_USED = "last_time_used";
@@ -4306,10 +4306,10 @@
          * Android version {@link android.os.Build.VERSION_CODES#Q}.
          * This column always contains 0.
          *
-         * <p class="caution"><b>Caution: </b>As of January 7, 2019, this field is obsolete.
-         * For more information, see the
+         * <p class="caution"><b>Caution: </b>If you publish your app to the Google Play Store,
+         * this field is obsolete, regardless of Android version. For more information, see the
          * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
-         * page.
+         * page.</p>
          */
         @Deprecated
         public static final String TIMES_USED = "times_used";
@@ -5259,8 +5259,8 @@
         /**
          * The content:// style URI for this table.
          *
-         * <p class="caution"><b>Caution: </b>As of January 7, 2019, this field no longer
-         * sorts results based on contacts frequency. For more information, see the
+         * <p class="caution"><b>Caution: </b>If you publish your app to the Google Play Store, this
+         * field doesn't sort results based on contacts frequency. For more information, see the
          * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
          * page.
          *
@@ -5277,8 +5277,8 @@
         /**
          * <p>URI used for the "enterprise caller-id".</p>
          *
-         * <p class="caution"><b>Caution: </b>As of January 7, 2019, this field no longer
-         * sorts results based on contacts frequency. For more information, see the
+         * <p class="caution"><b>Caution: </b>If you publish your app to the Google Play Store, this
+         * field doesn't sort results based on contacts frequency. For more information, see the
          * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
          * page.
          *
@@ -6079,8 +6079,8 @@
              * to display names as well as phone numbers. The filter argument should be passed
              * as an additional path segment after this URI.
              *
-             * <p class="caution"><b>Caution: </b>As of January 7, 2019, this field no longer
-             * sorts results based on contacts frequency. For more information, see the
+             * <p class="caution"><b>Caution: </b>This field deosn't sort results based on contacts
+             * frequency. For more information, see the
              * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
              * page.
              */
@@ -6092,8 +6092,9 @@
              * same columns. This URI requires {@link ContactsContract#DIRECTORY_PARAM_KEY} in
              * parameters, otherwise it will throw IllegalArgumentException.
              *
-             * <p class="caution"><b>Caution: </b>As of January 7, 2019, this field no longer sorts
-             * results based on contacts frequency. For more information, see the
+             * <p class="caution"><b>Caution: </b>If you publish your app to the Google Play Store,
+             * this field doesn't sort results based on contacts frequency. For more information,
+             * see the
              * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
              * page.
              */
@@ -6360,8 +6361,9 @@
              * as an additional path segment after this URI.
              * </p>
              *
-             * <p class="caution"><b>Caution: </b>As of January 7, 2019, this field no longer sorts
-             * results based on contacts frequency. For more information, see the
+             * <p class="caution"><b>Caution: </b>If you publish your app to the Google Play Store,
+             * this field doesn't sort results based on contacts frequency. For more information,
+             * see the
              * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
              * page.</p>
              *
@@ -6383,8 +6385,9 @@
              * same columns. This URI requires {@link ContactsContract#DIRECTORY_PARAM_KEY} in
              * parameters, otherwise it will throw IllegalArgumentException.
              *
-             * <p class="caution"><b>Caution: </b>As of January 7, 2019, this field no longer
-             * sorts results based on contacts frequency. For more information, see the
+             * <p class="caution"><b>Caution: </b>If you publish your app to the Google Play Store,
+             * this field doesn't sort results based on contacts frequency. For more information,
+             * see the
              * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
              * page.
              */
@@ -7602,8 +7605,8 @@
              * <p>Similar to {@link Phone#CONTENT_FILTER_URI}, but allows users to filter callable
              * data.
              *
-             * <p class="caution"><b>Caution: </b>As of January 7, 2019, this field no longer
-             * sorts results based on contacts frequency. For more information, see the
+             * <p class="caution"><b>Caution: </b>This field no longer sorts results based on
+             * contacts frequency. For more information, see the
              * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
              * page.
              */
@@ -7615,8 +7618,9 @@
              * callable data. This URI requires {@link ContactsContract#DIRECTORY_PARAM_KEY} in
              * parameters, otherwise it will throw IllegalArgumentException.
              *
-             * <p class="caution"><b>Caution: </b>As of January 7, 2019, this field no longer
-             * sorts results based on contacts frequency. For more information, see the
+             * <p class="caution"><b>Caution: </b>If you publish your app to the Google Play Store,
+             * this field doesn't sort results based on contacts frequency. For more information,
+             * see the
              * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
              * page.</p>
              */
@@ -7646,8 +7650,9 @@
              * <p>The content:// style URI for these data items, which allows for a query parameter
              * to be appended onto the end to filter for data items matching the query.
              *
-             * <p class="caution"><b>Caution: </b>As of January 7, 2019, this field no longer
-             * sorts results based on contacts frequency. For more information, see the
+             * <p class="caution"><b>Caution: </b>If you publish your app to the Google Play Store,
+             * this field doesn't sort results based on contacts frequency. For more information,
+             * see the
              * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
              * page.
              */
@@ -8298,15 +8303,14 @@
     }
 
     /**
-     * <p class="caution"><b>Caution: </b>As of January 7, 2019, this class is obsolete. For
-     * more information, see the
-     * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
-     * page.
-     * </p>
      * <p>
      * API allowing applications to send usage information for each {@link Data} row to the
      * Contacts Provider.  Applications can also clear all usage information.
      * </p>
+     * <p class="caution"><b>Caution: </b>If you publish your app to the Google Play Store,
+     * this field is obsolete, regardless of Android version. For more information, see the
+     * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
+     * page.</p>
      * <p>
      * With the feedback, Contacts Provider may return more contextually appropriate results for
      * Data listing, typically supplied with
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index d0401e3..4f7c8c5 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -346,6 +346,20 @@
                 "system_gestures_excluded_by_pre_q_sticky_immersive";
 
         /**
+         * The minimum duration between gesture exclusion logging for a given window in
+         * milliseconds.
+         *
+         * Events that happen in-between will be silently dropped.
+         *
+         * A non-positive value disables logging.
+         *
+         * @see android.provider.DeviceConfig#NAMESPACE_WINDOW_MANAGER
+         * @hide
+         */
+        String KEY_SYSTEM_GESTURE_EXCLUSION_LOG_DEBOUNCE_MILLIS =
+                "system_gesture_exclusion_log_debounce_millis";
+
+        /**
          * Key for controlling which packages are explicitly blocked from running at refresh rates
          * higher than 90hz.
          *
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index 2a590ce..2299aad 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -137,6 +137,8 @@
     public static final String VOLUME_EXTERNAL_PRIMARY = "external_primary";
 
     /** {@hide} */
+    public static final String WAIT_FOR_IDLE_CALL = "wait_for_idle";
+    /** {@hide} */
     public static final String SCAN_FILE_CALL = "scan_file";
     /** {@hide} */
     public static final String SCAN_VOLUME_CALL = "scan_volume";
@@ -3562,6 +3564,17 @@
 
     /** @hide */
     @TestApi
+    public static void waitForIdle(Context context) {
+        final ContentResolver resolver = context.getContentResolver();
+        try (ContentProviderClient client = resolver.acquireContentProviderClient(AUTHORITY)) {
+            client.call(WAIT_FOR_IDLE_CALL, null, null);
+        } catch (RemoteException e) {
+            throw e.rethrowAsRuntimeException();
+        }
+    }
+
+    /** @hide */
+    @TestApi
     public static Uri scanFile(Context context, File file) {
         return scan(context, SCAN_FILE_CALL, file, false);
     }
diff --git a/core/java/android/service/autofill/FillContext.java b/core/java/android/service/autofill/FillContext.java
index 70f434c..8331550 100644
--- a/core/java/android/service/autofill/FillContext.java
+++ b/core/java/android/service/autofill/FillContext.java
@@ -30,6 +30,8 @@
 import android.util.SparseIntArray;
 import android.view.autofill.AutofillId;
 
+import com.android.internal.util.DataClass;
+
 import java.util.LinkedList;
 
 /**
@@ -46,58 +48,36 @@
  * to {@link FillResponse.Builder#setClientState(Bundle)} to avoid interpreting
  * the UI state again while saving.
  */
+@DataClass(
+        genHiddenConstructor = true,
+        genAidl = false)
 public final class FillContext implements Parcelable {
+
+    /**
+     * The id of the {@link FillRequest fill request} this context
+     * corresponds to. This is useful to associate your custom client
+     * state with every request to avoid reinterpreting the UI when saving
+     * user data.
+     */
     private final int mRequestId;
+
+    /**
+     * The screen content.
+     */
     private final @NonNull AssistStructure mStructure;
+
+    /**
+     * The AutofillId of the view that triggered autofill.
+     */
     private final @NonNull AutofillId mFocusedId;
 
     /**
      * Lookup table AutofillId->ViewNode to speed up {@link #findViewNodesByAutofillIds}
      * This is purely a cache and can be deleted at any time
      */
-    @Nullable private ArrayMap<AutofillId, AssistStructure.ViewNode> mViewNodeLookupTable;
+    private transient @Nullable ArrayMap<AutofillId, AssistStructure.ViewNode> mViewNodeLookupTable;
 
 
-    /** @hide */
-    public FillContext(int requestId, @NonNull AssistStructure structure,
-            @NonNull AutofillId autofillId) {
-        mRequestId = requestId;
-        mStructure = structure;
-        mFocusedId = autofillId;
-    }
-
-    private FillContext(Parcel parcel) {
-        this(parcel.readInt(), parcel.readParcelable(null), parcel.readParcelable(null));
-    }
-
-    /**
-     * Gets the id of the {@link FillRequest fill request} this context
-     * corresponds to. This is useful to associate your custom client
-     * state with every request to avoid reinterpreting the UI when saving
-     * user data.
-     *
-     * @return The request id.
-     */
-    public int getRequestId() {
-        return mRequestId;
-    }
-
-    /**
-     * @return The screen content.
-     */
-    @NonNull
-    public AssistStructure getStructure() {
-        return mStructure;
-    }
-
-    /**
-     * @return the AutofillId of the view that triggered autofill.
-     */
-    @NonNull
-    public AutofillId getFocusedId() {
-        return mFocusedId;
-    }
-
     @Override
     public String toString() {
         if (!sDebug)  return super.toString();
@@ -105,18 +85,6 @@
         return "FillContext [reqId=" + mRequestId + ", focusedId=" + mFocusedId + "]";
     }
 
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel parcel, int flags) {
-        parcel.writeInt(mRequestId);
-        parcel.writeParcelable(mStructure, flags);
-        parcel.writeParcelable(mFocusedId, flags);
-    }
-
     /**
      * Finds {@link ViewNode ViewNodes} that have the requested ids.
      *
@@ -190,18 +158,119 @@
         return foundNodes;
     }
 
-    public static final @android.annotation.NonNull Parcelable.Creator<FillContext> CREATOR =
-            new Parcelable.Creator<FillContext>() {
-        @Override
-        @NonNull
-        public FillContext createFromParcel(Parcel parcel) {
-            return new FillContext(parcel);
-        }
 
+
+    // Code below generated by codegen v1.0.0.
+    //
+    // DO NOT MODIFY!
+    //
+    // To regenerate run:
+    // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/service/autofill/FillContext.java
+    //
+    // CHECKSTYLE:OFF Generated code
+
+    /**
+     * Creates a new FillContext.
+     *
+     * @param requestId
+     *   The id of the {@link FillRequest fill request} this context
+     *   corresponds to. This is useful to associate your custom client
+     *   state with every request to avoid reinterpreting the UI when saving
+     *   user data.
+     * @param structure
+     *   The screen content.
+     * @param focusedId
+     *   The AutofillId of the view that triggered autofill.
+     * @hide
+     */
+    @DataClass.Generated.Member
+    public FillContext(
+            int requestId,
+            @NonNull AssistStructure structure,
+            @NonNull AutofillId focusedId) {
+        this.mRequestId = requestId;
+        this.mStructure = structure;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mStructure);
+        this.mFocusedId = focusedId;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mFocusedId);
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    /**
+     * The id of the {@link FillRequest fill request} this context
+     * corresponds to. This is useful to associate your custom client
+     * state with every request to avoid reinterpreting the UI when saving
+     * user data.
+     */
+    @DataClass.Generated.Member
+    public int getRequestId() {
+        return mRequestId;
+    }
+
+    /**
+     * The screen content.
+     */
+    @DataClass.Generated.Member
+    public @NonNull AssistStructure getStructure() {
+        return mStructure;
+    }
+
+    /**
+     * The AutofillId of the view that triggered autofill.
+     */
+    @DataClass.Generated.Member
+    public @NonNull AutofillId getFocusedId() {
+        return mFocusedId;
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public void writeToParcel(Parcel dest, int flags) {
+        // You can override field parcelling by defining methods like:
+        // void parcelFieldName(Parcel dest, int flags) { ... }
+
+        dest.writeInt(mRequestId);
+        dest.writeTypedObject(mStructure, flags);
+        dest.writeTypedObject(mFocusedId, flags);
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public int describeContents() { return 0; }
+
+    @DataClass.Generated.Member
+    public static final @NonNull Parcelable.Creator<FillContext> CREATOR
+            = new Parcelable.Creator<FillContext>() {
         @Override
-        @NonNull
         public FillContext[] newArray(int size) {
             return new FillContext[size];
         }
+
+        @Override
+        @SuppressWarnings({"unchecked", "RedundantCast"})
+        public FillContext createFromParcel(Parcel in) {
+            // You can override field unparcelling by defining methods like:
+            // static FieldType unparcelFieldName(Parcel in) { ... }
+
+            int requestId = in.readInt();
+            AssistStructure structure = (AssistStructure) in.readTypedObject(AssistStructure.CREATOR);
+            AutofillId focusedId = (AutofillId) in.readTypedObject(AutofillId.CREATOR);
+            return new FillContext(
+                    requestId,
+                    structure,
+                    focusedId);
+        }
     };
+
+    @DataClass.Generated(
+            time = 1565152135263L,
+            codegenVersion = "1.0.0",
+            sourceFile = "frameworks/base/core/java/android/service/autofill/FillContext.java",
+            inputSignatures = "private final  int mRequestId\nprivate final @android.annotation.NonNull android.app.assist.AssistStructure mStructure\nprivate final @android.annotation.NonNull android.view.autofill.AutofillId mFocusedId\nprivate transient @android.annotation.Nullable android.util.ArrayMap<android.view.autofill.AutofillId,android.app.assist.AssistStructure.ViewNode> mViewNodeLookupTable\npublic @java.lang.Override java.lang.String toString()\npublic @android.annotation.NonNull android.app.assist.AssistStructure.ViewNode[] findViewNodesByAutofillIds(android.view.autofill.AutofillId[])\nclass FillContext extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genHiddenConstructor=true, genAidl=false)")
+    @Deprecated
+    private void __metadata() {}
+
 }
diff --git a/core/java/android/service/autofill/FillRequest.java b/core/java/android/service/autofill/FillRequest.java
index 91f77ea..e53ebad 100644
--- a/core/java/android/service/autofill/FillRequest.java
+++ b/core/java/android/service/autofill/FillRequest.java
@@ -24,6 +24,7 @@
 import android.os.Parcelable;
 import android.view.View;
 
+import com.android.internal.util.DataClass;
 import com.android.internal.util.Preconditions;
 
 import java.lang.annotation.Retention;
@@ -39,6 +40,10 @@
  *
  * @see AutofillService#onFillRequest(FillRequest, android.os.CancellationSignal, FillCallback)
  */
+@DataClass(
+        genToString = true,
+        genHiddenConstructor = true,
+        genHiddenConstDefs = true)
 public final class FillRequest implements Parcelable {
 
     /**
@@ -63,54 +68,45 @@
      * is called. For example, standard {@link android.widget.TextView} views show an
      * {@code AUTOFILL} option in the overflow menu that triggers such request.
      */
-    public static final int FLAG_MANUAL_REQUEST = 0x1;
+    public static final @RequestFlags int FLAG_MANUAL_REQUEST = 0x1;
 
     /**
      * Indicates this request was made using
      * <a href="AutofillService.html#CompatibilityMode">compatibility mode</a>.
      */
-    public static final int FLAG_COMPATIBILITY_MODE_REQUEST = 0x2;
+    public static final @RequestFlags int FLAG_COMPATIBILITY_MODE_REQUEST = 0x2;
 
     /** @hide */
     public static final int INVALID_REQUEST_ID = Integer.MIN_VALUE;
 
-    /** @hide */
-    @IntDef(flag = true, prefix = { "FLAG_" }, value = {
-            FLAG_MANUAL_REQUEST, FLAG_COMPATIBILITY_MODE_REQUEST
-    })
-    @Retention(RetentionPolicy.SOURCE)
-    @interface RequestFlags{}
-
-    private final int mId;
-    private final @RequestFlags int mFlags;
-    private final @NonNull ArrayList<FillContext> mContexts;
-    private final @Nullable Bundle mClientState;
-
-    private FillRequest(@NonNull Parcel parcel) {
-        mId = parcel.readInt();
-        mContexts = new ArrayList<>();
-        parcel.readParcelableList(mContexts, null);
-
-        mClientState = parcel.readBundle();
-        mFlags = parcel.readInt();
-    }
-
-    /** @hide */
-    public FillRequest(int id, @NonNull ArrayList<FillContext> contexts,
-            @Nullable Bundle clientState, @RequestFlags int flags) {
-        mId = id;
-        mFlags = Preconditions.checkFlagsArgument(flags,
-                FLAG_MANUAL_REQUEST | FLAG_COMPATIBILITY_MODE_REQUEST);
-        mContexts = Preconditions.checkCollectionElementsNotNull(contexts, "contexts");
-        mClientState = clientState;
-    }
-
     /**
      * Gets the unique id of this request.
      */
-    public int getId() {
-        return mId;
-    }
+    private final int mId;
+
+    /**
+     * Gets the contexts associated with each previous fill request.
+     *
+     * <p><b>Note:</b> Starting on Android {@link android.os.Build.VERSION_CODES#Q}, it could also
+     * include contexts from requests whose {@link SaveInfo} had the
+     * {@link SaveInfo#FLAG_DELAY_SAVE} flag.
+     */
+    private final @NonNull List<FillContext> mFillContexts;
+
+    /**
+     * Gets the latest client state bundle set by the service in a
+     * {@link FillResponse.Builder#setClientState(Bundle) fill response}.
+     *
+     * <p><b>Note:</b> Prior to Android {@link android.os.Build.VERSION_CODES#P}, only client state
+     * bundles set by {@link FillResponse.Builder#setClientState(Bundle)} were considered. On
+     * Android {@link android.os.Build.VERSION_CODES#P} and higher, bundles set in the result of
+     * an authenticated request through the
+     * {@link android.view.autofill.AutofillManager#EXTRA_CLIENT_STATE} extra are
+     * also considered (and take precedence when set).
+     *
+     * @return The client state.
+     */
+    private final @Nullable Bundle mClientState;
 
     /**
      * Gets the flags associated with this request.
@@ -118,8 +114,105 @@
      * @return any combination of {@link #FLAG_MANUAL_REQUEST} and
      *         {@link #FLAG_COMPATIBILITY_MODE_REQUEST}.
      */
-    public @RequestFlags int getFlags() {
-        return mFlags;
+    private final @RequestFlags int mFlags;
+
+    private void onConstructed() {
+        Preconditions.checkCollectionElementsNotNull(mFillContexts, "contexts");
+    }
+
+
+
+    // Code below generated by codegen v1.0.0.
+    //
+    // DO NOT MODIFY!
+    //
+    // To regenerate run:
+    // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/service/autofill/FillRequest.java
+    //
+    // CHECKSTYLE:OFF Generated code
+
+    /** @hide */
+    @IntDef(flag = true, prefix = "FLAG_", value = {
+        FLAG_MANUAL_REQUEST,
+        FLAG_COMPATIBILITY_MODE_REQUEST
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    @DataClass.Generated.Member
+    public @interface RequestFlags {}
+
+    /** @hide */
+    @DataClass.Generated.Member
+    public static String requestFlagsToString(@RequestFlags int value) {
+        return com.android.internal.util.BitUtils.flagsToString(
+                value, FillRequest::singleRequestFlagsToString);
+    }
+
+    @DataClass.Generated.Member
+    static String singleRequestFlagsToString(@RequestFlags int value) {
+        switch (value) {
+            case FLAG_MANUAL_REQUEST:
+                    return "FLAG_MANUAL_REQUEST";
+            case FLAG_COMPATIBILITY_MODE_REQUEST:
+                    return "FLAG_COMPATIBILITY_MODE_REQUEST";
+            default: return Integer.toHexString(value);
+        }
+    }
+
+    /**
+     * Creates a new FillRequest.
+     *
+     * @param id
+     *   Gets the unique id of this request.
+     * @param fillContexts
+     *   Gets the contexts associated with each previous fill request.
+     *
+     *   <p><b>Note:</b> Starting on Android {@link android.os.Build.VERSION_CODES#Q}, it could also
+     *   include contexts from requests whose {@link SaveInfo} had the
+     *   {@link SaveInfo#FLAG_DELAY_SAVE} flag.
+     * @param clientState
+     *   Gets the latest client state bundle set by the service in a
+     *   {@link FillResponse.Builder#setClientState(Bundle) fill response}.
+     *
+     *   <p><b>Note:</b> Prior to Android {@link android.os.Build.VERSION_CODES#P}, only client state
+     *   bundles set by {@link FillResponse.Builder#setClientState(Bundle)} were considered. On
+     *   Android {@link android.os.Build.VERSION_CODES#P} and higher, bundles set in the result of
+     *   an authenticated request through the
+     *   {@link android.view.autofill.AutofillManager#EXTRA_CLIENT_STATE} extra are
+     *   also considered (and take precedence when set).
+     * @param flags
+     *   Gets the flags associated with this request.
+     *
+     *   @return any combination of {@link #FLAG_MANUAL_REQUEST} and
+     *           {@link #FLAG_COMPATIBILITY_MODE_REQUEST}.
+     * @hide
+     */
+    @DataClass.Generated.Member
+    public FillRequest(
+            int id,
+            @NonNull List<FillContext> fillContexts,
+            @Nullable Bundle clientState,
+            @RequestFlags int flags) {
+        this.mId = id;
+        this.mFillContexts = fillContexts;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mFillContexts);
+        this.mClientState = clientState;
+        this.mFlags = flags;
+
+        Preconditions.checkFlagsArgument(
+                mFlags,
+                FLAG_MANUAL_REQUEST
+                        | FLAG_COMPATIBILITY_MODE_REQUEST);
+
+        onConstructed();
+    }
+
+    /**
+     * Gets the unique id of this request.
+     */
+    @DataClass.Generated.Member
+    public int getId() {
+        return mId;
     }
 
     /**
@@ -129,13 +222,9 @@
      * include contexts from requests whose {@link SaveInfo} had the
      * {@link SaveInfo#FLAG_DELAY_SAVE} flag.
      */
+    @DataClass.Generated.Member
     public @NonNull List<FillContext> getFillContexts() {
-        return mContexts;
-    }
-
-    @Override
-    public String toString() {
-        return "FillRequest: [id=" + mId + ", flags=" + mFlags + ", ctxts= " + mContexts + "]";
+        return mFillContexts;
     }
 
     /**
@@ -151,33 +240,89 @@
      *
      * @return The client state.
      */
+    @DataClass.Generated.Member
     public @Nullable Bundle getClientState() {
         return mClientState;
     }
 
-    @Override
-    public int describeContents() {
-        return 0;
+    /**
+     * Gets the flags associated with this request.
+     *
+     * @return any combination of {@link #FLAG_MANUAL_REQUEST} and
+     *         {@link #FLAG_COMPATIBILITY_MODE_REQUEST}.
+     */
+    @DataClass.Generated.Member
+    public @RequestFlags int getFlags() {
+        return mFlags;
     }
 
     @Override
-    public void writeToParcel(Parcel parcel, int flags) {
-        parcel.writeInt(mId);
-        parcel.writeParcelableList(mContexts, flags);
-        parcel.writeBundle(mClientState);
-        parcel.writeInt(mFlags);
+    @DataClass.Generated.Member
+    public String toString() {
+        // You can override field toString logic by defining methods like:
+        // String fieldNameToString() { ... }
+
+        return "FillRequest { " +
+                "id = " + mId + ", " +
+                "fillContexts = " + mFillContexts + ", " +
+                "clientState = " + mClientState + ", " +
+                "flags = " + requestFlagsToString(mFlags) +
+        " }";
     }
 
-    public static final @android.annotation.NonNull Parcelable.Creator<FillRequest> CREATOR =
-            new Parcelable.Creator<FillRequest>() {
-        @Override
-        public FillRequest createFromParcel(Parcel parcel) {
-            return new FillRequest(parcel);
-        }
+    @Override
+    @DataClass.Generated.Member
+    public void writeToParcel(Parcel dest, int flags) {
+        // You can override field parcelling by defining methods like:
+        // void parcelFieldName(Parcel dest, int flags) { ... }
 
+        byte flg = 0;
+        if (mClientState != null) flg |= 0x4;
+        dest.writeByte(flg);
+        dest.writeInt(mId);
+        dest.writeParcelableList(mFillContexts, flags);
+        if (mClientState != null) dest.writeBundle(mClientState);
+        dest.writeInt(mFlags);
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public int describeContents() { return 0; }
+
+    @DataClass.Generated.Member
+    public static final @NonNull Parcelable.Creator<FillRequest> CREATOR
+            = new Parcelable.Creator<FillRequest>() {
         @Override
         public FillRequest[] newArray(int size) {
             return new FillRequest[size];
         }
+
+        @Override
+        @SuppressWarnings({"unchecked", "RedundantCast"})
+        public FillRequest createFromParcel(Parcel in) {
+            // You can override field unparcelling by defining methods like:
+            // static FieldType unparcelFieldName(Parcel in) { ... }
+
+            byte flg = in.readByte();
+            int id = in.readInt();
+            List<FillContext> fillContexts = new ArrayList<>();
+            in.readParcelableList(fillContexts, FillContext.class.getClassLoader());
+            Bundle clientState = (flg & 0x4) == 0 ? null : in.readBundle();
+            int flags = in.readInt();
+            return new FillRequest(
+                    id,
+                    fillContexts,
+                    clientState,
+                    flags);
+        }
     };
+
+    @DataClass.Generated(
+            time = 1565152134349L,
+            codegenVersion = "1.0.0",
+            sourceFile = "frameworks/base/core/java/android/service/autofill/FillRequest.java",
+            inputSignatures = "public static final @android.service.autofill.FillRequest.RequestFlags int FLAG_MANUAL_REQUEST\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_COMPATIBILITY_MODE_REQUEST\npublic static final  int INVALID_REQUEST_ID\nprivate final  int mId\nprivate final @android.annotation.NonNull java.util.List<android.service.autofill.FillContext> mFillContexts\nprivate final @android.annotation.Nullable android.os.Bundle mClientState\nprivate final @android.service.autofill.FillRequest.RequestFlags int mFlags\nprivate  void onConstructed()\nclass FillRequest extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genHiddenConstructor=true, genHiddenConstDefs=true)")
+    @Deprecated
+    private void __metadata() {}
+
 }
diff --git a/core/java/android/service/notification/NotificationAssistantService.java b/core/java/android/service/notification/NotificationAssistantService.java
index 12d3228..da40254 100644
--- a/core/java/android/service/notification/NotificationAssistantService.java
+++ b/core/java/android/service/notification/NotificationAssistantService.java
@@ -293,6 +293,11 @@
                 Log.w(TAG, "onNotificationEnqueued: Error receiving StatusBarNotification", e);
                 return;
             }
+            if (sbn == null) {
+                Log.w(TAG, "onNotificationEnqueuedWithChannel: "
+                        + "Error receiving StatusBarNotification");
+                return;
+            }
 
             SomeArgs args = SomeArgs.obtain();
             args.arg1 = sbn;
@@ -311,6 +316,10 @@
                 Log.w(TAG, "onNotificationSnoozed: Error receiving StatusBarNotification", e);
                 return;
             }
+            if (sbn == null) {
+                Log.w(TAG, "onNotificationSnoozed: Error receiving StatusBarNotification");
+                return;
+            }
 
             SomeArgs args = SomeArgs.obtain();
             args.arg1 = sbn;
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index b44c9d5..78e30ab 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -1272,6 +1272,10 @@
                 Log.w(TAG, "onNotificationPosted: Error receiving StatusBarNotification", e);
                 return;
             }
+            if (sbn == null) {
+                Log.w(TAG, "onNotificationPosted: Error receiving StatusBarNotification");
+                return;
+            }
 
             try {
                 // convert icon metadata to legacy format for older clients
@@ -1313,6 +1317,10 @@
                 Log.w(TAG, "onNotificationRemoved: Error receiving StatusBarNotification", e);
                 return;
             }
+            if (sbn == null) {
+                Log.w(TAG, "onNotificationRemoved: Error receiving StatusBarNotification");
+                return;
+            }
             // protect subclass from concurrent modifications of (@link mNotificationKeys}.
             synchronized (mLock) {
                 applyUpdateLocked(update);
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index 60dbf84..e784ad3 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -196,7 +196,6 @@
         final WindowManager.LayoutParams mLayout
                 = new WindowManager.LayoutParams();
         IWindowSession mSession;
-        InputChannel mInputChannel;
 
         final Object mLock = new Object();
         boolean mOffsetMessageEnqueued;
@@ -819,11 +818,11 @@
                         mLayout.setTitle(WallpaperService.this.getClass().getName());
                         mLayout.windowAnimations =
                                 com.android.internal.R.style.Animation_Wallpaper;
-                        mInputChannel = new InputChannel();
+                        InputChannel inputChannel = new InputChannel();
 
                         if (mSession.addToDisplay(mWindow, mWindow.mSeq, mLayout, View.VISIBLE,
                                 mDisplay.getDisplayId(), mWinFrame, mContentInsets, mStableInsets,
-                                mOutsets, mDisplayCutout, mInputChannel,
+                                mOutsets, mDisplayCutout, inputChannel,
                                 mInsetsState) < 0) {
                             Log.w(TAG, "Failed to add window while updating wallpaper surface.");
                             return;
@@ -831,7 +830,7 @@
                         mCreated = true;
 
                         mInputEventReceiver = new WallpaperInputEventReceiver(
-                                mInputChannel, Looper.myLooper());
+                                inputChannel, Looper.myLooper());
                     }
 
                     mSurfaceHolder.mSurfaceLock.lock();
@@ -1267,13 +1266,6 @@
                 }
                 mSurfaceHolder.mSurface.release();
                 mCreated = false;
-
-                // Dispose the input channel after removing the window so the Window Manager
-                // doesn't interpret the input channel being closed as an abnormal termination.
-                if (mInputChannel != null) {
-                    mInputChannel.dispose();
-                    mInputChannel = null;
-                }
             }
         }
 
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index 6aef5a5..b66764e 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -41,13 +41,14 @@
     public static final String SCREENRECORD_LONG_PRESS = "settings_screenrecord_long_press";
     public static final String DYNAMIC_SYSTEM = "settings_dynamic_system";
     public static final String SETTINGS_WIFITRACKER2 = "settings_wifitracker2";
+    public static final String USE_BUGREPORT_API = "settings_use_bugreport_api";
 
     private static final Map<String, String> DEFAULT_FLAGS;
 
     static {
         DEFAULT_FLAGS = new HashMap<>();
         DEFAULT_FLAGS.put("settings_audio_switcher", "true");
-        DEFAULT_FLAGS.put("settings_call_bugreport_api", "false");
+        DEFAULT_FLAGS.put("settings_use_bugreport_api", "true");
         DEFAULT_FLAGS.put("settings_mobile_network_v2", "true");
         DEFAULT_FLAGS.put("settings_network_and_internet_v2", "true");
         DEFAULT_FLAGS.put("settings_systemui_theme", "true");
diff --git a/core/java/android/util/LruCache.java b/core/java/android/util/LruCache.java
index f04e7cb..3cbf727d 100644
--- a/core/java/android/util/LruCache.java
+++ b/core/java/android/util/LruCache.java
@@ -17,6 +17,7 @@
 package android.util;
 
 import android.annotation.UnsupportedAppUsage;
+
 import java.util.LinkedHashMap;
 import java.util.Map;
 
@@ -260,7 +261,7 @@
      * @param evicted true if the entry is being removed to make space, false
      *     if the removal was caused by a {@link #put} or {@link #remove}.
      * @param newValue the new value for {@code key}, if it exists. If non-null,
-     *     this removal was caused by a {@link #put}. Otherwise it was caused by
+     *     this removal was caused by a {@link #put} or a {@link #get}. Otherwise it was caused by
      *     an eviction or a {@link #remove}.
      */
     protected void entryRemoved(boolean evicted, K key, V oldValue, V newValue) {}
diff --git a/core/java/android/view/FrameMetrics.java b/core/java/android/view/FrameMetrics.java
index dcdef3e..ea66656 100644
--- a/core/java/android/view/FrameMetrics.java
+++ b/core/java/android/view/FrameMetrics.java
@@ -220,7 +220,7 @@
         int SWAP_BUFFERS = 12;
         int FRAME_COMPLETED = 13;
 
-        int FRAME_STATS_COUNT = 16; // must always be last
+        int FRAME_STATS_COUNT = 17; // must always be last
     }
 
     /*
diff --git a/core/java/android/view/ISystemGestureExclusionListener.aidl b/core/java/android/view/ISystemGestureExclusionListener.aidl
index a032625..9c2f9a6 100644
--- a/core/java/android/view/ISystemGestureExclusionListener.aidl
+++ b/core/java/android/view/ISystemGestureExclusionListener.aidl
@@ -28,7 +28,14 @@
      * Called when the system gesture exclusion for the given display changed.
      * @param displayId the display whose system gesture exclusion changed
      * @param systemGestureExclusion a {@code Region} where the app would like priority over the
-     *                               system gestures, in display coordinates.
+     *                               system gestures, in display coordinates. Certain restrictions
+     *                               might be applied such that apps don't get all the exclusions
+     *                               they request.
+     * @param systemGestureExclusionUnrestricted a {@code Region} where the app would like priority
+     *                               over the system gestures, in display coordinates, without
+     *                               any restrictions applied. Null if no restrictions have been
+     *                               applied.
      */
-    void onSystemGestureExclusionChanged(int displayId, in Region systemGestureExclusion);
+    void onSystemGestureExclusionChanged(int displayId, in Region systemGestureExclusion,
+            in Region systemGestureExclusionUnrestricted);
 }
\ No newline at end of file
diff --git a/core/java/android/view/InputEventReceiver.java b/core/java/android/view/InputEventReceiver.java
index 7260a65..ed8492e 100644
--- a/core/java/android/view/InputEventReceiver.java
+++ b/core/java/android/view/InputEventReceiver.java
@@ -102,7 +102,11 @@
             nativeDispose(mReceiverPtr);
             mReceiverPtr = 0;
         }
-        mInputChannel = null;
+
+        if (mInputChannel != null) {
+            mInputChannel.dispose();
+            mInputChannel = null;
+        }
         mMessageQueue = null;
     }
 
diff --git a/core/java/android/view/RemoteAnimationAdapter.java b/core/java/android/view/RemoteAnimationAdapter.java
index bc2fe54..c686440 100644
--- a/core/java/android/view/RemoteAnimationAdapter.java
+++ b/core/java/android/view/RemoteAnimationAdapter.java
@@ -55,6 +55,7 @@
 
     /** @see #getCallingPid */
     private int mCallingPid;
+    private int mCallingUid;
 
     /**
      * @param runner The interface that gets notified when we actually need to start the animation.
@@ -103,10 +104,11 @@
     }
 
     /**
-     * To be called by system_server to keep track which pid is running this animation.
+     * To be called by system_server to keep track which pid and uid is running this animation.
      */
-    public void setCallingPid(int pid) {
+    public void setCallingPidUid(int pid, int uid) {
         mCallingPid = pid;
+        mCallingUid = uid;
     }
 
     /**
@@ -116,6 +118,13 @@
         return mCallingPid;
     }
 
+    /**
+     * @return The uid of the process running the animation.
+     */
+    public int getCallingUid() {
+        return mCallingUid;
+    }
+
     @Override
     public int describeContents() {
         return 0;
diff --git a/core/java/android/view/RemoteAnimationDefinition.java b/core/java/android/view/RemoteAnimationDefinition.java
index 884cae4..da599ef 100644
--- a/core/java/android/view/RemoteAnimationDefinition.java
+++ b/core/java/android/view/RemoteAnimationDefinition.java
@@ -118,9 +118,9 @@
      * To be called by system_server to keep track which pid is running the remote animations inside
      * this definition.
      */
-    public void setCallingPid(int pid) {
+    public void setCallingPidUid(int pid, int uid) {
         for (int i = mTransitionAnimationMap.size() - 1; i >= 0; i--) {
-            mTransitionAnimationMap.valueAt(i).adapter.setCallingPid(pid);
+            mTransitionAnimationMap.valueAt(i).adapter.setCallingPidUid(pid, uid);
         }
     }
 
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 1a66898..90e69f3 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -38,6 +38,7 @@
 import android.os.SystemClock;
 import android.util.AttributeSet;
 import android.util.Log;
+import android.view.SurfaceControl.Transaction;
 
 import com.android.internal.view.SurfaceCallbackHelper;
 
@@ -118,7 +119,7 @@
     boolean mDrawFinished = false;
 
     final Rect mScreenRect = new Rect();
-    SurfaceSession mSurfaceSession;
+    private final SurfaceSession mSurfaceSession = new SurfaceSession();
 
     SurfaceControl mSurfaceControl;
     // In the case of format changes we switch out the surface in-place
@@ -193,6 +194,7 @@
 
     private SurfaceControl.Transaction mRtTransaction = new SurfaceControl.Transaction();
     private SurfaceControl.Transaction mTmpTransaction = new SurfaceControl.Transaction();
+    private int mParentSurfaceGenerationId;
 
     public SurfaceView(Context context) {
         this(context, null);
@@ -644,13 +646,12 @@
         }
     }
 
-    private void updateBackgroundVisibilityInTransaction(SurfaceControl viewRoot) {
+    private void updateBackgroundVisibilityInTransaction() {
         if (mBackgroundControl == null) {
             return;
         }
         if ((mSubLayer < 0) && ((mSurfaceFlags & SurfaceControl.OPAQUE) != 0)) {
             mBackgroundControl.show();
-            mBackgroundControl.setRelativeLayer(viewRoot, Integer.MIN_VALUE);
         } else {
             mBackgroundControl.hide();
         }
@@ -742,11 +743,24 @@
                 mScreenRect.offset(surfaceInsets.left, surfaceInsets.top);
 
                 if (creating) {
-                    viewRoot.createBoundsSurface(mSubLayer);
-                    mSurfaceSession = new SurfaceSession();
                     mDeferredDestroySurfaceControl = mSurfaceControl;
 
                     updateOpaqueFlag();
+                    // SurfaceView hierarchy
+                    // ViewRootImpl surface
+                    //   - bounds layer (crops all child surfaces to parent surface insets)
+                    //     - SurfaceView surface (drawn relative to ViewRootImpl surface)
+                    //     - Background color layer (drawn behind all SurfaceView surfaces)
+                    //
+                    // The bounds layer is used to crop the surface view so it does not draw into
+                    // the parent surface inset region. Since there can be multiple surface views
+                    // below or above the parent surface, one option is to create multiple bounds
+                    // layer for each z order. The other option, the one implement is to create
+                    // a single bounds layer and set z order for each child surface relative to the
+                    // parent surface.
+                    // When creating the surface view, we parent it to the bounds layer and then
+                    // set the relative z order. When the parent surface changes, we have to
+                    // make sure to update the relative z via ViewRootImpl.SurfaceChangedCallback.
                     final String name = "SurfaceView - " + viewRoot.getTitle().toString();
 
                     mSurfaceControl = new SurfaceControl.Builder(mSurfaceSession)
@@ -754,7 +768,7 @@
                         .setOpaque((mSurfaceFlags & SurfaceControl.OPAQUE) != 0)
                         .setBufferSize(mSurfaceWidth, mSurfaceHeight)
                         .setFormat(mFormat)
-                        .setParent(viewRoot.getSurfaceControl())
+                        .setParent(viewRoot.getBoundsLayer())
                         .setFlags(mSurfaceFlags)
                         .build();
                     mBackgroundControl = new SurfaceControl.Builder(mSurfaceSession)
@@ -779,14 +793,23 @@
 
                     SurfaceControl.openTransaction();
                     try {
-                        mSurfaceControl.setLayer(mSubLayer);
+                        // If we are creating the surface control or the parent surface has not
+                        // changed, then set relative z. Otherwise allow the parent
+                        // SurfaceChangedCallback to update the relative z. This is needed so that
+                        // we do not change the relative z before the server is ready to swap the
+                        // parent surface.
+                        if (creating || (mParentSurfaceGenerationId
+                                == viewRoot.mSurface.getGenerationId())) {
+                            SurfaceControl.mergeToGlobalTransaction(updateRelativeZ());
+                        }
+                        mParentSurfaceGenerationId = viewRoot.mSurface.getGenerationId();
 
                         if (mViewVisibility) {
                             mSurfaceControl.show();
                         } else {
                             mSurfaceControl.hide();
                         }
-                        updateBackgroundVisibilityInTransaction(viewRoot.getSurfaceControl());
+                        updateBackgroundVisibilityInTransaction();
                         if (mUseAlpha) {
                             mSurfaceControl.setAlpha(alpha);
                             mSurfaceAlpha = alpha;
@@ -1369,11 +1392,22 @@
     }
 
     /**
-     * Called when a valid ViewRootImpl surface is replaced by another valid surface.
+     * Called when a valid ViewRootImpl surface is replaced by another valid surface. In this
+     * case update relative z to the new parent surface.
      * @hide
      */
     @Override
-    public void surfaceReplaced(SurfaceControl.Transaction t) {
+    public void surfaceReplaced(Transaction t) {
+        if (mSurfaceControl != null && mBackgroundControl != null) {
+            t.merge(updateRelativeZ());
+        }
+    }
 
+    private Transaction updateRelativeZ() {
+        Transaction t = new Transaction();
+        SurfaceControl viewRoot = getViewRootImpl().getSurfaceControl();
+        t.setRelativeLayer(mBackgroundControl, viewRoot, Integer.MIN_VALUE);
+        t.setRelativeLayer(mSurfaceControl, viewRoot, mSubLayer);
+        return t;
     }
 }
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 1779a80..6d4128b 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -13386,10 +13386,10 @@
 
         if ((mPrivateFlags2 & PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED) == 0) {
             mPrivateFlags2 |= PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED;
-            if (mParent != null) {
+            if (mParent != null && mParent instanceof View) {
                 try {
                     mParent.notifySubtreeAccessibilityStateChanged(
-                            this, this, AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE);
+                            this, (View) mParent, AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE);
                 } catch (AbstractMethodError e) {
                     Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() +
                             " does not fully implement ViewParent", e);
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 82a5fa9..7ee8865 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -5144,7 +5144,7 @@
         }
 
         if (child.getVisibility() != View.GONE) {
-            notifySubtreeAccessibilityStateChangedIfNeeded();
+            child.notifySubtreeAccessibilityStateChangedIfNeeded();
         }
 
         if (mTransientIndices != null) {
@@ -5432,7 +5432,7 @@
         dispatchViewRemoved(view);
 
         if (view.getVisibility() != View.GONE) {
-            notifySubtreeAccessibilityStateChangedIfNeeded();
+            view.notifySubtreeAccessibilityStateChangedIfNeeded();
         }
 
         int transientCount = mTransientIndices == null ? 0 : mTransientIndices.size();
@@ -5740,7 +5740,7 @@
         }
         dispatchVisibilityAggregated(isAttachedToWindow() && getWindowVisibility() == VISIBLE
                 && isShown());
-        notifySubtreeAccessibilityStateChangedIfNeeded();
+        child.notifySubtreeAccessibilityStateChangedIfNeeded();
     }
 
     /**
@@ -6146,7 +6146,8 @@
         if (invalidate) {
             invalidateViewProperty(false, false);
         }
-        notifySubtreeAccessibilityStateChangedIfNeeded();
+        notifySubtreeAccessibilityStateChanged(
+                this, this, AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE);
     }
 
     @Override
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 354cc96..3a51eaa 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -399,7 +399,6 @@
 
     @UnsupportedAppUsage
     final View.AttachInfo mAttachInfo;
-    InputChannel mInputChannel;
     InputQueue.Callback mInputQueueCallback;
     InputQueue mInputQueue;
     @UnsupportedAppUsage
@@ -484,15 +483,13 @@
      */
     private final Transaction mSurfaceChangedTransaction = new Transaction();
     /**
-     * Child surface of {@code mSurface} with the same bounds as its parent, and crop bounds
-     * are set to the parent's bounds adjusted for surface insets. This surface is created when
-     * {@link ViewRootImpl#createBoundsSurface(int)} is called.
-     * By parenting to this bounds surface, child surfaces can ensure they do not draw into the
-     * surface inset regions set by the parent window.
+     * Child container layer of {@code mSurface} with the same bounds as its parent, and cropped to
+     * the surface insets. This surface is created only if a client requests it via {@link
+     * #getBoundsLayer()}. By parenting to this bounds surface, child surfaces can ensure they do
+     * not draw into the surface inset region set by the parent window.
      */
-    public final Surface mBoundsSurface = new Surface();
-    private SurfaceSession mSurfaceSession;
-    private SurfaceControl mBoundsSurfaceControl;
+    private SurfaceControl mBoundsLayer;
+    private final SurfaceSession mSurfaceSession = new SurfaceSession();
     private final Transaction mTransaction = new Transaction();
 
     @UnsupportedAppUsage
@@ -884,9 +881,10 @@
                 // manager, to make sure we do the relayout before receiving
                 // any other events from the system.
                 requestLayout();
+                InputChannel inputChannel = null;
                 if ((mWindowAttributes.inputFeatures
                         & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
-                    mInputChannel = new InputChannel();
+                    inputChannel = new InputChannel();
                 }
                 mForceDecorViewVisibility = (mWindowAttributes.privateFlags
                         & PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY) != 0;
@@ -897,14 +895,14 @@
                     res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                             getHostVisibility(), mDisplay.getDisplayId(), mTmpFrame,
                             mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
-                            mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel,
+                            mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, inputChannel,
                             mTempInsets);
                     setFrame(mTmpFrame);
                 } catch (RemoteException e) {
                     mAdded = false;
                     mView = null;
                     mAttachInfo.mRootView = null;
-                    mInputChannel = null;
+                    inputChannel = null;
                     mFallbackEventHandler.setView(null);
                     unscheduleTraversals();
                     setAccessibilityFocus(null, null);
@@ -980,12 +978,12 @@
                     mInputQueueCallback =
                         ((RootViewSurfaceTaker)view).willYouTakeTheInputQueue();
                 }
-                if (mInputChannel != null) {
+                if (inputChannel != null) {
                     if (mInputQueueCallback != null) {
                         mInputQueue = new InputQueue();
                         mInputQueueCallback.onInputQueueCreated(mInputQueue);
                     }
-                    mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,
+                    mInputEventReceiver = new WindowInputEventReceiver(inputChannel,
                             Looper.myLooper());
                 }
 
@@ -1614,66 +1612,55 @@
         }
     }
 
-
     /**
-     * Creates a surface as a child of {@code mSurface} with the same bounds as its parent and
-     * crop bounds set to the parent's bounds adjusted for surface insets.
+     * @return child layer with the same bounds as its parent {@code mSurface} and cropped to the
+     * surface insets. If the layer does not exist, it is created.
      *
-     * @param zOrderLayer Z order relative to the parent surface.
+     * <p>Parenting to this layer will ensure that its children are cropped by the view's surface
+     * insets.
      */
-    public void createBoundsSurface(int zOrderLayer) {
-        if (mSurfaceSession == null) {
-            mSurfaceSession = new SurfaceSession();
+    public SurfaceControl getBoundsLayer() {
+        if (mBoundsLayer == null) {
+            mBoundsLayer = new SurfaceControl.Builder(mSurfaceSession)
+                    .setContainerLayer()
+                    .setName("Bounds for - " + getTitle().toString())
+                    .setParent(mSurfaceControl)
+                    .build();
+            setBoundsLayerCrop();
+            mTransaction.show(mBoundsLayer).apply();
         }
-        if (mBoundsSurfaceControl != null && mBoundsSurface.isValid()) {
-            return; // surface control for bounds surface already exists.
-        }
-
-        mBoundsSurfaceControl = new SurfaceControl.Builder(mSurfaceSession)
-                .setName("Bounds for - " + getTitle().toString())
-                .setParent(mSurfaceControl)
-                .build();
-
-        setBoundsSurfaceCrop();
-        mTransaction.setLayer(mBoundsSurfaceControl, zOrderLayer)
-                    .show(mBoundsSurfaceControl)
-                    .apply();
-        mBoundsSurface.copyFrom(mBoundsSurfaceControl);
+        return mBoundsLayer;
     }
 
-    private void setBoundsSurfaceCrop() {
+    private void setBoundsLayerCrop() {
         // mWinFrame is already adjusted for surface insets. So offset it and use it as
         // the cropping bounds.
         mTempBoundsRect.set(mWinFrame);
         mTempBoundsRect.offsetTo(mWindowAttributes.surfaceInsets.left,
                 mWindowAttributes.surfaceInsets.top);
-        mTransaction.setWindowCrop(mBoundsSurfaceControl, mTempBoundsRect);
+        mTransaction.setWindowCrop(mBoundsLayer, mTempBoundsRect);
     }
 
     /**
-     * Called after window layout to update the bounds surface. If the surface insets have
-     * changed or the surface has resized, update the bounds surface.
+     * Called after window layout to update the bounds surface. If the surface insets have changed
+     * or the surface has resized, update the bounds surface.
      */
-    private void updateBoundsSurface() {
-        if (mBoundsSurfaceControl != null && mSurface.isValid()) {
-            setBoundsSurfaceCrop();
-            mTransaction.deferTransactionUntilSurface(mBoundsSurfaceControl,
+    private void updateBoundsLayer() {
+        if (mBoundsLayer != null) {
+            setBoundsLayerCrop();
+            mTransaction.deferTransactionUntilSurface(mBoundsLayer,
                     mSurface, mSurface.getNextFrameNumber())
                     .apply();
         }
     }
 
     private void destroySurface() {
+        if (mBoundsLayer != null) {
+            mBoundsLayer.release();
+            mBoundsLayer = null;
+        }
         mSurface.release();
         mSurfaceControl.release();
-
-        mSurfaceSession = null;
-
-        if (mBoundsSurfaceControl != null) {
-            mTransaction.remove(mBoundsSurfaceControl).apply();
-            mBoundsSurface.release();
-            mBoundsSurfaceControl = null;
-        }
     }
 
     /**
@@ -2649,8 +2636,8 @@
             maybeHandleWindowMove(frame);
         }
 
-        if (surfaceSizeChanged) {
-            updateBoundsSurface();
+        if (surfaceSizeChanged || surfaceReplaced || surfaceCreated || windowAttributesChanged) {
+            updateBoundsLayer();
         }
 
         final boolean didLayout = layoutRequested && (!mStopped || mReportNextDraw);
@@ -4388,13 +4375,6 @@
         } catch (RemoteException e) {
         }
 
-        // Dispose the input channel after removing the window so the Window Manager
-        // doesn't interpret the input channel being closed as an abnormal termination.
-        if (mInputChannel != null) {
-            mInputChannel.dispose();
-            mInputChannel = null;
-        }
-
         mDisplayManager.unregisterDisplayListener(mDisplayListener);
 
         unscheduleTraversals();
diff --git a/core/java/android/widget/AbsSeekBar.java b/core/java/android/widget/AbsSeekBar.java
index c3e08fc..bbcba2e 100644
--- a/core/java/android/widget/AbsSeekBar.java
+++ b/core/java/android/widget/AbsSeekBar.java
@@ -91,6 +91,7 @@
     @UnsupportedAppUsage
     private float mDisabledAlpha;
 
+    private int mThumbExclusionMaxSize;
     private int mScaledTouchSlop;
     private float mTouchDownX;
     @UnsupportedAppUsage
@@ -171,6 +172,8 @@
         applyTickMarkTint();
 
         mScaledTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
+        mThumbExclusionMaxSize = getResources().getDimensionPixelSize(
+                com.android.internal.R.dimen.seekbar_thumb_exclusion_max_size);
     }
 
     /**
@@ -763,12 +766,30 @@
         }
         mGestureExclusionRects.clear();
         thumb.copyBounds(mThumbRect);
+        mThumbRect.offset(mPaddingLeft - mThumbOffset, mPaddingTop);
+        growRectTo(mThumbRect, Math.min(getHeight(), mThumbExclusionMaxSize));
         mGestureExclusionRects.add(mThumbRect);
         mGestureExclusionRects.addAll(mUserGestureExclusionRects);
         super.setSystemGestureExclusionRects(mGestureExclusionRects);
     }
 
     /**
+     * Grows {@code r} from its center such that each dimension is at least {@code minimumSize}.
+     */
+    private void growRectTo(Rect r, int minimumSize) {
+        int dy = (minimumSize - r.height()) / 2;
+        if (dy > 0) {
+            r.top -= dy;
+            r.bottom += dy;
+        }
+        int dx = (minimumSize - r.width()) / 2;
+        if (dx > 0) {
+            r.left -= dx;
+            r.right += dx;
+        }
+    }
+
+    /**
      * @hide
      */
     @Override
diff --git a/core/java/android/widget/AdapterView.java b/core/java/android/widget/AdapterView.java
index c55f7d6..5359e27 100644
--- a/core/java/android/widget/AdapterView.java
+++ b/core/java/android/widget/AdapterView.java
@@ -1106,7 +1106,8 @@
             checkSelectionChanged();
         }
 
-        notifySubtreeAccessibilityStateChangedIfNeeded();
+        notifySubtreeAccessibilityStateChanged(
+                this, this, AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE);
     }
 
     /**
diff --git a/core/java/android/widget/TabHost.java b/core/java/android/widget/TabHost.java
index 90cb1c8..45e635ebe 100644
--- a/core/java/android/widget/TabHost.java
+++ b/core/java/android/widget/TabHost.java
@@ -59,13 +59,21 @@
     private static final int TABWIDGET_LOCATION_BOTTOM = 3;
     private TabWidget mTabWidget;
     private FrameLayout mTabContent;
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(trackingBug = 137825207, maxTargetSdk = Build.VERSION_CODES.Q,
+            publicAlternatives = "Use {@code androidx.viewpager.widget.ViewPager} and "
+                    + "{@code com.google.android.material.tabs.TabLayout} instead.\n"
+                    + "See <a href=\"{@docRoot}guide/navigation/navigation-swipe-view"
+                    + "\">TabLayout and ViewPager</a>")
     private List<TabSpec> mTabSpecs = new ArrayList<TabSpec>(2);
     /**
      * This field should be made private, so it is hidden from the SDK.
      * {@hide}
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(trackingBug = 137825207, maxTargetSdk = Build.VERSION_CODES.Q,
+            publicAlternatives = "Use {@code androidx.viewpager.widget.ViewPager} and "
+                    + "{@code com.google.android.material.tabs.TabLayout} instead.\n"
+                    + "See <a href=\"{@docRoot}guide/navigation/navigation-swipe-view"
+                    + "\">TabLayout and ViewPager</a>")
     protected int mCurrentTab = -1;
     private View mCurrentView = null;
     /**
@@ -73,7 +81,11 @@
      * {@hide}
      */
     protected LocalActivityManager mLocalActivityManager = null;
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(trackingBug = 137825207, maxTargetSdk = Build.VERSION_CODES.Q,
+            publicAlternatives = "Use {@code androidx.viewpager.widget.ViewPager} and "
+                    + "{@code com.google.android.material.tabs.TabLayout} instead.\n"
+                    + "See <a href=\"{@docRoot}guide/navigation/navigation-swipe-view"
+                    + "\">TabLayout and ViewPager</a>")
     private OnTabChangeListener mOnTabChangeListener;
     private OnKeyListener mTabKeyListener;
 
@@ -514,9 +526,17 @@
 
         private final @NonNull String mTag;
 
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(trackingBug = 137825207, maxTargetSdk = Build.VERSION_CODES.Q,
+                publicAlternatives = "Use {@code androidx.viewpager.widget.ViewPager} and "
+                        + "{@code com.google.android.material.tabs.TabLayout} instead.\n"
+                        + "See <a href=\"{@docRoot}guide/navigation/navigation-swipe-view"
+                        + "\">TabLayout and ViewPager</a>")
         private IndicatorStrategy mIndicatorStrategy;
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(trackingBug = 137825207, maxTargetSdk = Build.VERSION_CODES.Q,
+                publicAlternatives = "Use {@code androidx.viewpager.widget.ViewPager} and "
+                        + "{@code com.google.android.material.tabs.TabLayout} instead.\n"
+                        + "See <a href=\"{@docRoot}guide/navigation/navigation-swipe-view"
+                        + "\">TabLayout and ViewPager</a>")
         private ContentStrategy mContentStrategy;
 
         /**
@@ -779,7 +799,11 @@
             mIntent = intent;
         }
 
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(trackingBug = 137825207, maxTargetSdk = Build.VERSION_CODES.Q,
+                publicAlternatives = "Use {@code androidx.viewpager.widget.ViewPager} and "
+                        + "{@code com.google.android.material.tabs.TabLayout} instead.\n"
+                        + "See <a href=\"{@docRoot}guide/navigation/navigation-swipe-view"
+                        + "\">TabLayout and ViewPager</a>")
         public View getContentView() {
             if (mLocalActivityManager == null) {
                 throw new IllegalStateException("Did you forget to call 'public void setup(LocalActivityManager activityGroup)'?");
@@ -809,7 +833,11 @@
             return mLaunchedView;
         }
 
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(trackingBug = 137825207, maxTargetSdk = Build.VERSION_CODES.Q,
+                publicAlternatives = "Use {@code androidx.viewpager.widget.ViewPager} and "
+                        + "{@code com.google.android.material.tabs.TabLayout} instead.\n"
+                        + "See <a href=\"{@docRoot}guide/navigation/navigation-swipe-view"
+                        + "\">TabLayout and ViewPager</a>")
         public void tabClosed() {
             if (mLaunchedView != null) {
                 mLaunchedView.setVisibility(View.GONE);
diff --git a/core/java/android/widget/TabWidget.java b/core/java/android/widget/TabWidget.java
index 434a799..bd0d039 100644
--- a/core/java/android/widget/TabWidget.java
+++ b/core/java/android/widget/TabWidget.java
@@ -65,7 +65,11 @@
     private OnTabSelectionChanged mSelectionChangedListener;
 
     // This value will be set to 0 as soon as the first tab is added to TabHost.
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(trackingBug = 137825207, maxTargetSdk = Build.VERSION_CODES.Q,
+            publicAlternatives = "Use {@code androidx.viewpager.widget.ViewPager} and "
+                    + "{@code com.google.android.material.tabs.TabLayout} instead.\n"
+                    + "See <a href=\"{@docRoot}guide/navigation/navigation-swipe-view"
+                    + "\">TabLayout and ViewPager</a>")
     private int mSelectedTab = -1;
 
     @Nullable
@@ -74,7 +78,11 @@
     @Nullable
     private Drawable mRightStrip;
 
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(trackingBug = 137825207, maxTargetSdk = Build.VERSION_CODES.Q,
+            publicAlternatives = "Use {@code androidx.viewpager.widget.ViewPager} and "
+                    + "{@code com.google.android.material.tabs.TabLayout} instead.\n"
+                    + "See <a href=\"{@docRoot}guide/navigation/navigation-swipe-view"
+                    + "\">TabLayout and ViewPager</a>")
     private boolean mDrawBottomStrips = true;
     private boolean mStripMoved;
 
@@ -551,7 +559,11 @@
      * Provides a way for {@link TabHost} to be notified that the user clicked
      * on a tab indicator.
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(trackingBug = 137825207, maxTargetSdk = Build.VERSION_CODES.Q,
+            publicAlternatives = "Use {@code androidx.viewpager.widget.ViewPager} and "
+                    + "{@code com.google.android.material.tabs.TabLayout} instead.\n"
+                    + "See <a href=\"{@docRoot}guide/navigation/navigation-swipe-view"
+                    + "\">TabLayout and ViewPager</a>")
     void setTabSelectionListener(OnTabSelectionChanged listener) {
         mSelectionChangedListener = listener;
     }
diff --git a/core/java/com/android/internal/app/AssistUtils.java b/core/java/com/android/internal/app/AssistUtils.java
index efcdb9a..f848309 100644
--- a/core/java/com/android/internal/app/AssistUtils.java
+++ b/core/java/com/android/internal/app/AssistUtils.java
@@ -195,7 +195,7 @@
         return applicationInfo.isSystemApp() || applicationInfo.isUpdatedSystemApp();
     }
 
-    private static boolean isDisclosureEnabled(Context context) {
+    public static boolean isDisclosureEnabled(Context context) {
         return Settings.Secure.getInt(context.getContentResolver(),
                 Settings.Secure.ASSIST_DISCLOSURE_ENABLED, 0) != 0;
     }
diff --git a/core/java/com/android/internal/colorextraction/ColorExtractor.java b/core/java/com/android/internal/colorextraction/ColorExtractor.java
index 3003ce8..f0da0d5 100644
--- a/core/java/com/android/internal/colorextraction/ColorExtractor.java
+++ b/core/java/com/android/internal/colorextraction/ColorExtractor.java
@@ -73,8 +73,10 @@
         }
 
         mOnColorsChangedListeners = new ArrayList<>();
-        wallpaperManager.addOnColorsChangedListener(this, null /* handler */);
-        initExtractColors(wallpaperManager, immediately);
+        if (wallpaperManager.isWallpaperSupported()) {
+            wallpaperManager.addOnColorsChangedListener(this, null /* handler */);
+            initExtractColors(wallpaperManager, immediately);
+        }
     }
 
     private void initExtractColors(WallpaperManager wallpaperManager, boolean immediately) {
diff --git a/core/java/com/android/internal/content/PackageHelper.java b/core/java/com/android/internal/content/PackageHelper.java
index ad1ff90..1d81c59 100644
--- a/core/java/com/android/internal/content/PackageHelper.java
+++ b/core/java/com/android/internal/content/PackageHelper.java
@@ -261,8 +261,21 @@
     public static boolean fitsOnInternal(Context context, SessionParams params) throws IOException {
         final StorageManager storage = context.getSystemService(StorageManager.class);
         final UUID target = storage.getUuidForPath(Environment.getDataDirectory());
-        return (params.sizeBytes <= storage.getAllocatableBytes(target,
-                translateAllocateFlags(params.installFlags)));
+        final int flags = translateAllocateFlags(params.installFlags);
+
+        final long allocateableBytes = storage.getAllocatableBytes(target,
+                flags | StorageManager.FLAG_ALLOCATE_NON_CACHE_ONLY);
+
+        // If we fit on internal storage without including freeable cache space, don't bother
+        // checking to determine how much space is taken up by the cache.
+        if (params.sizeBytes <= allocateableBytes) {
+            return true;
+        }
+
+        final long cacheClearable = storage.getAllocatableBytes(target,
+                flags | StorageManager.FLAG_ALLOCATE_CACHE_ONLY);
+
+        return params.sizeBytes <= allocateableBytes + cacheClearable;
     }
 
     public static boolean fitsOnExternal(Context context, SessionParams params) {
diff --git a/core/java/com/android/internal/os/ZygoteArguments.java b/core/java/com/android/internal/os/ZygoteArguments.java
index 6d40266..abc4160 100644
--- a/core/java/com/android/internal/os/ZygoteArguments.java
+++ b/core/java/com/android/internal/os/ZygoteArguments.java
@@ -187,6 +187,11 @@
     boolean mPidQuery;
 
     /**
+     * Whether the current arguments constitute a notification that boot completed.
+     */
+    boolean mBootCompleted;
+
+    /**
      * Exemptions from API blacklisting. These are sent to the pre-forked zygote at boot time, or
      * when they change, via --set-api-blacklist-exemptions.
      */
@@ -361,6 +366,8 @@
                 mAbiListQuery = true;
             } else if (arg.equals("--get-pid")) {
                 mPidQuery = true;
+            } else if (arg.equals("--boot-completed")) {
+                mBootCompleted = true;
             } else if (arg.startsWith("--instruction-set=")) {
                 mInstructionSet = getAssignmentValue(arg);
             } else if (arg.startsWith("--app-data-dir=")) {
@@ -417,7 +424,11 @@
             }
         }
 
-        if (mAbiListQuery || mPidQuery) {
+        if (mBootCompleted) {
+            if (args.length - curArg > 0) {
+                throw new IllegalArgumentException("Unexpected arguments after --boot-completed");
+            }
+        } else if (mAbiListQuery || mPidQuery) {
             if (args.length - curArg > 0) {
                 throw new IllegalArgumentException("Unexpected arguments after --query-abi-list.");
             }
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index 06a14f0..b3ec5f5 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -140,6 +140,11 @@
 
         ZygoteArguments parsedArgs = new ZygoteArguments(args);
 
+        if (parsedArgs.mBootCompleted) {
+            handleBootCompleted();
+            return null;
+        }
+
         if (parsedArgs.mAbiListQuery) {
             handleAbiListQuery();
             return null;
@@ -300,6 +305,10 @@
         }
     }
 
+    private void handleBootCompleted() {
+        VMRuntime.bootCompleted();
+    }
+
     /**
      * Preloads resources if the zygote is in lazily preload mode. Writes the result of the
      * preload operation; {@code 0} when a preload was initiated due to this request and {@code 1}
diff --git a/core/java/com/android/internal/util/ArrayUtils.java b/core/java/com/android/internal/util/ArrayUtils.java
index e3264a0..821022f 100644
--- a/core/java/com/android/internal/util/ArrayUtils.java
+++ b/core/java/com/android/internal/util/ArrayUtils.java
@@ -335,18 +335,12 @@
         }
 
         int totalLength = 0;
-        int maxLength = 0;
-        T[] maxLengthArray = arrays[0];
         for (T[] item : arrays) {
             if (item == null) {
                 continue;
             }
 
             totalLength += item.length;
-            if (item.length > maxLength) {
-                maxLengthArray = item;
-                maxLength = item.length;
-            }
         }
 
         // Optimization for entirely empty arrays.
diff --git a/core/java/com/android/internal/util/DataClass.java b/core/java/com/android/internal/util/DataClass.java
index 146f546..43539c7 100644
--- a/core/java/com/android/internal/util/DataClass.java
+++ b/core/java/com/android/internal/util/DataClass.java
@@ -65,11 +65,21 @@
     boolean genGetters() default true;
 
     /**
+     * {@link #genGetters} with @hide
+     */
+    boolean genHiddenGetters() default false;
+
+    /**
      * Generates setters for each field.
      */
     boolean genSetters() default false;
 
     /**
+     * {@link #genSetters} with @hide
+     */
+    boolean genHiddenSetters() default false;
+
+    /**
      * Generates a public constructor with each field initialized from a parameter and optionally
      * some user-defined state validation at the end.
      *
@@ -85,6 +95,11 @@
     boolean genConstructor() default true;
 
     /**
+     * {@link #genConstructor} with @hide
+     */
+    boolean genHiddenConstructor() default false;
+
+    /**
      * Generates a Builder for your class.
      *
      * Uses a package-private constructor under the hood, so same rules hold as for
@@ -93,6 +108,11 @@
     boolean genBuilder() default false;
 
     /**
+     * {@link #genBuilder} with @hide
+     */
+    boolean genHiddenBuilder() default false;
+
+    /**
      * Generates a structural {@link Object#equals} + {@link Object#hashCode}.
      *
      * You can customize individual fields' logic by declaring methods like:
@@ -126,6 +146,11 @@
     boolean genCopyConstructor() default false;
 
     /**
+     * {@link #genCopyConstructor} with @hide
+     */
+    boolean genHiddenCopyConstructor() default false;
+
+    /**
      * Generates constant annotations({@link IntDef}/{@link StringDef}) for any constant groups
      * with common prefix.
      * The annotation names are based on the common prefix.
@@ -146,6 +171,11 @@
      */
     boolean genConstDefs() default true;
 
+    /**
+     * {@link #genConstDefs} with @hide
+     */
+    boolean genHiddenConstDefs() default false;
+
 
     /**
      * Allows specifying custom parcelling logic based on reusable
@@ -177,11 +207,10 @@
 
     /**
      * @deprecated to be used by code generator exclusively
-     * @hide
      */
     @Deprecated
     @Retention(RetentionPolicy.SOURCE)
-    @Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE, ANNOTATION_TYPE, CONSTRUCTOR, TYPE})
+    @Target({METHOD})
     @interface Generated {
         long time();
         String codegenVersion();
@@ -190,7 +219,6 @@
 
         /**
          * @deprecated to be used by code generator exclusively
-         * @hide
          */
         @Deprecated
         @Retention(RetentionPolicy.SOURCE)
@@ -199,6 +227,22 @@
     }
 
     /**
+     * Opt out of generating {@link #genConstDefs IntDef/StringDef}s for annotated constant
+     */
+    @Retention(RetentionPolicy.SOURCE)
+    @Target({FIELD})
+    @interface SuppressConstDefsGeneration {}
+
+    /**
+     * A class-level annotation to suppress methods' generation by name
+     */
+    @Retention(RetentionPolicy.SOURCE)
+    @Target({TYPE})
+    @interface Suppress {
+        String[] value();
+    }
+
+    /**
      * Callback used by {@link #genForEachField}.
      *
      * @param <THIS> The enclosing data class instance.
diff --git a/core/java/com/android/internal/util/Parcelling.java b/core/java/com/android/internal/util/Parcelling.java
index 63530dc..390c596 100644
--- a/core/java/com/android/internal/util/Parcelling.java
+++ b/core/java/com/android/internal/util/Parcelling.java
@@ -24,6 +24,8 @@
 /**
  * Describes a 2-way parcelling contract of type {@code T} into/out of a {@link Parcel}
  *
+ * Implementations should be stateless.
+ *
  * @param <T> the type being [un]parcelled
  */
 public interface Parcelling<T> {
@@ -69,6 +71,7 @@
          * instance or reflectively creating one.
          */
         public static <P extends Parcelling<?>> P getOrCreate(Class<P> clazz) {
+            // No synchronization - creating an extra instance in a race case is ok
             P cached = get(clazz);
             if (cached != null) {
                 return cached;
diff --git a/core/java/com/android/internal/util/StatLogger.java b/core/java/com/android/internal/util/StatLogger.java
index 1dac136..ca6acd6 100644
--- a/core/java/com/android/internal/util/StatLogger.java
+++ b/core/java/com/android/internal/util/StatLogger.java
@@ -163,6 +163,9 @@
                 proto.write(Event.LABEL, mLabels[i]);
                 proto.write(Event.COUNT, mCountStats[i]);
                 proto.write(Event.TOTAL_DURATION_MICROS, mDurationStats[i]);
+                proto.write(Event.MAX_CALLS_PER_SECOND, mMaxCallsPerSecond[i]);
+                proto.write(Event.MAX_DURATION_PER_SECOND_MICROS, mMaxDurationPerSecond[i]);
+                proto.write(Event.MAX_DURATION_STATS_MICROS, mMaxDurationStats[i]);
 
                 proto.end(inner);
             }
diff --git a/core/java/com/android/internal/util/XmlUtils.java b/core/java/com/android/internal/util/XmlUtils.java
index 344d7ef..8799e3d 100644
--- a/core/java/com/android/internal/util/XmlUtils.java
+++ b/core/java/com/android/internal/util/XmlUtils.java
@@ -26,6 +26,8 @@
 import android.util.Base64;
 import android.util.Xml;
 
+import libcore.util.HexEncoding;
+
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 import org.xmlpull.v1.XmlSerializer;
@@ -396,16 +398,7 @@
         final int N = val.length;
         out.attribute(null, "num", Integer.toString(N));
 
-        StringBuilder sb = new StringBuilder(val.length*2);
-        for (int i=0; i<N; i++) {
-            int b = val[i];
-            int h = (b >> 4) & 0x0f;
-            sb.append((char)(h >= 10 ? ('a'+h-10) : ('0'+h)));
-            h = b & 0x0f;
-            sb.append((char)(h >= 10 ? ('a'+h-10) : ('0'+h)));
-        }
-
-        out.text(sb.toString());
+        out.text(HexEncoding.encodeToString(val).toLowerCase());
 
         out.endTag(null, "byte-array");
     }
@@ -1032,7 +1025,9 @@
                     "Not a number in num attribute in byte-array");
         }
 
-        byte[] array = new byte[num];
+        // 0 len byte array does not have a text in the XML tag. So, initialize to 0 len array.
+        // For all other array lens, HexEncoding.decode() below overrides the array.
+        byte[] array = new byte[0];
 
         int eventType = parser.getEventType();
         do {
@@ -1043,16 +1038,7 @@
                         throw new XmlPullParserException(
                                 "Invalid value found in byte-array: " + values);
                     }
-                    // This is ugly, but keeping it to mirror the logic in #writeByteArrayXml.
-                    for (int i = 0; i < num; i ++) {
-                        char nibbleHighChar = values.charAt(2 * i);
-                        char nibbleLowChar = values.charAt(2 * i + 1);
-                        int nibbleHigh = nibbleHighChar > 'a' ? (nibbleHighChar - 'a' + 10)
-                                : (nibbleHighChar - '0');
-                        int nibbleLow = nibbleLowChar > 'a' ? (nibbleLowChar - 'a' + 10)
-                                : (nibbleLowChar - '0');
-                        array[i] = (byte) ((nibbleHigh & 0x0F) << 4 | (nibbleLow & 0x0F));
-                    }
+                    array = HexEncoding.decode(values);
                 }
             } else if (eventType == parser.END_TAG) {
                 if (parser.getName().equals(endTag)) {
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index dc45f78..32867a8 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -558,7 +558,7 @@
 
     /**
      * Returns the password history hash factor, needed to check new password against password
-     * history with {@link #checkPasswordHistory(String, byte[], int)}
+     * history with {@link #checkPasswordHistory(byte[], byte[], int)}
      */
     public byte[] getPasswordHistoryHashFactor(byte[] currentPassword, int userId) {
         try {
@@ -1242,23 +1242,6 @@
         return res;
     }
 
-    /**
-     * Transform a pattern byte array to base zero form.
-     * @param bytes pattern byte array.
-     * @return The pattern in base zero form.
-     */
-    public static byte[] patternByteArrayToBaseZero(byte[] bytes) {
-        if (bytes == null) {
-            return new byte[0];
-        }
-        final int patternSize = bytes.length;
-        byte[] res = new byte[patternSize];
-        for (int i = 0; i < patternSize; i++) {
-            res[i] = (byte) (bytes[i] - '1');
-        }
-        return res;
-    }
-
     /*
      * Generate an SHA-1 hash for the pattern. Not the most secure, but it is
      * at least a second level of protection. First level is that the file
diff --git a/core/java/com/android/internal/widget/MediaNotificationView.java b/core/java/com/android/internal/widget/MediaNotificationView.java
index e7d240a..9bb4501 100644
--- a/core/java/com/android/internal/widget/MediaNotificationView.java
+++ b/core/java/com/android/internal/widget/MediaNotificationView.java
@@ -26,6 +26,8 @@
 import android.widget.ImageView;
 import android.widget.RemoteViews;
 
+import java.util.ArrayList;
+
 /**
  * A TextView that can float around an image on the end.
  *
@@ -42,6 +44,7 @@
     private View mMainColumn;
     private View mMediaContent;
     private int mImagePushIn;
+    private ArrayList<VisibilityChangeListener> mListeners;
 
     public MediaNotificationView(Context context) {
         this(context, null);
@@ -168,4 +171,50 @@
         mMainColumn = findViewById(com.android.internal.R.id.notification_main_column);
         mMediaContent = findViewById(com.android.internal.R.id.notification_media_content);
     }
+
+    @Override
+    public void onVisibilityAggregated(boolean isVisible) {
+        super.onVisibilityAggregated(isVisible);
+        if (mListeners != null) {
+            for (int i = 0; i < mListeners.size(); i++) {
+                mListeners.get(i).onAggregatedVisibilityChanged(isVisible);
+            }
+        }
+    }
+
+    /**
+     * Add a listener to receive updates on the visibility of this view
+     *
+     * @param listener The listener to add.
+     */
+    public void addVisibilityListener(VisibilityChangeListener listener) {
+        if (mListeners == null) {
+            mListeners = new ArrayList<>();
+        }
+        if (!mListeners.contains(listener)) {
+            mListeners.add(listener);
+        }
+    }
+
+    /**
+     * Remove the specified listener
+     *
+     * @param listener The listener to remove.
+     */
+    public void removeVisibilityListener(VisibilityChangeListener listener) {
+        if (mListeners != null) {
+            mListeners.remove(listener);
+        }
+    }
+
+    /**
+     * Interface for receiving updates when the view's visibility changes
+     */
+    public interface VisibilityChangeListener {
+        /**
+         * Method called when the visibility of this view has changed
+         * @param isVisible true if the view is now visible
+         */
+        void onAggregatedVisibilityChanged(boolean isVisible);
+    }
 }
diff --git a/core/java/com/android/internal/widget/PointerLocationView.java b/core/java/com/android/internal/widget/PointerLocationView.java
index 9084f62..d48034b 100644
--- a/core/java/com/android/internal/widget/PointerLocationView.java
+++ b/core/java/com/android/internal/widget/PointerLocationView.java
@@ -53,6 +53,12 @@
     // to plot alongside the default one.  Useful for testing and comparison purposes.
     private static final String ALT_STRATEGY_PROPERY_KEY = "debug.velocitytracker.alt";
 
+    /**
+     * If set to a positive value between 1-255, shows an overlay with the approved (red) and
+     * rejected (blue) exclusions.
+     */
+    private static final String GESTURE_EXCLUSION_PROP = "debug.pointerlocation.showexclusion";
+
     public static class PointerState {
         // Trace of previous points.
         private float[] mTraceX = new float[32];
@@ -138,8 +144,10 @@
     private final PointerCoords mTempCoords = new PointerCoords();
 
     private final Region mSystemGestureExclusion = new Region();
+    private final Region mSystemGestureExclusionRejected = new Region();
     private final Path mSystemGestureExclusionPath = new Path();
     private final Paint mSystemGestureExclusionPaint;
+    private final Paint mSystemGestureExclusionRejectedPaint;
 
     private final VelocityTracker mVelocity;
     private final VelocityTracker mAltVelocity;
@@ -190,6 +198,10 @@
         mSystemGestureExclusionPaint.setARGB(25, 255, 0, 0);
         mSystemGestureExclusionPaint.setStyle(Paint.Style.FILL_AND_STROKE);
 
+        mSystemGestureExclusionRejectedPaint = new Paint();
+        mSystemGestureExclusionRejectedPaint.setARGB(25, 0, 0, 255);
+        mSystemGestureExclusionRejectedPaint.setStyle(Paint.Style.FILL_AND_STROKE);
+
         PointerState ps = new PointerState();
         mPointers.add(ps);
         mActivePointerId = 0;
@@ -263,6 +275,12 @@
             canvas.drawPath(mSystemGestureExclusionPath, mSystemGestureExclusionPaint);
         }
 
+        if (!mSystemGestureExclusionRejected.isEmpty()) {
+            mSystemGestureExclusionPath.reset();
+            mSystemGestureExclusionRejected.getBoundaryPath(mSystemGestureExclusionPath);
+            canvas.drawPath(mSystemGestureExclusionPath, mSystemGestureExclusionRejectedPaint);
+        }
+
         // Labels
         if (mActivePointerId >= 0) {
             final PointerState ps = mPointers.get(mActivePointerId);
@@ -754,6 +772,9 @@
             } catch (RemoteException e) {
                 throw e.rethrowFromSystemServer();
             }
+            final int alpha = systemGestureExclusionOpacity();
+            mSystemGestureExclusionPaint.setAlpha(alpha);
+            mSystemGestureExclusionRejectedPaint.setAlpha(alpha);
         } else {
             mSystemGestureExclusion.setEmpty();
         }
@@ -805,7 +826,12 @@
     }
 
     private static boolean shouldShowSystemGestureExclusion() {
-        return SystemProperties.getBoolean("debug.pointerlocation.showexclusion", false);
+        return systemGestureExclusionOpacity() > 0;
+    }
+
+    private static int systemGestureExclusionOpacity() {
+        int x = SystemProperties.getInt(GESTURE_EXCLUSION_PROP, 0);
+        return x >= 0 && x <= 255 ? x : 0;
     }
 
     // HACK
@@ -928,12 +954,19 @@
     private ISystemGestureExclusionListener mSystemGestureExclusionListener =
             new ISystemGestureExclusionListener.Stub() {
         @Override
-        public void onSystemGestureExclusionChanged(int displayId, Region systemGestureExclusion) {
+        public void onSystemGestureExclusionChanged(int displayId, Region systemGestureExclusion,
+                Region systemGestureExclusionUnrestricted) {
             Region exclusion = Region.obtain(systemGestureExclusion);
+            Region rejected = Region.obtain();
+            if (systemGestureExclusionUnrestricted != null) {
+                rejected.set(systemGestureExclusionUnrestricted);
+                rejected.op(exclusion, Region.Op.DIFFERENCE);
+            }
             Handler handler = getHandler();
             if (handler != null) {
                 handler.post(() -> {
                     mSystemGestureExclusion.set(exclusion);
+                    mSystemGestureExclusionRejected.set(rejected);
                     exclusion.recycle();
                     invalidate();
                 });
diff --git a/core/java/com/android/server/job/JobSchedulerInternal.java b/core/java/com/android/server/job/JobSchedulerInternal.java
index dbf3b98..eefb9fa 100644
--- a/core/java/com/android/server/job/JobSchedulerInternal.java
+++ b/core/java/com/android/server/job/JobSchedulerInternal.java
@@ -17,6 +17,7 @@
 package com.android.server.job;
 
 import android.app.job.JobInfo;
+import android.util.proto.ProtoOutputStream;
 
 import java.util.List;
 
@@ -89,5 +90,30 @@
                     + countSystemServerJobsSaved + "/"
                     + countSystemSyncManagerJobsSaved;
         }
+
+        /**
+         * Write the persist stats to the specified field.
+         */
+        public void writeToProto(ProtoOutputStream proto, long fieldId) {
+            final long token = proto.start(fieldId);
+
+            final long flToken = proto.start(JobStorePersistStatsProto.FIRST_LOAD);
+            proto.write(JobStorePersistStatsProto.Stats.NUM_TOTAL_JOBS, countAllJobsLoaded);
+            proto.write(JobStorePersistStatsProto.Stats.NUM_SYSTEM_SERVER_JOBS,
+                    countSystemServerJobsLoaded);
+            proto.write(JobStorePersistStatsProto.Stats.NUM_SYSTEM_SYNC_MANAGER_JOBS,
+                    countSystemSyncManagerJobsLoaded);
+            proto.end(flToken);
+
+            final long lsToken = proto.start(JobStorePersistStatsProto.LAST_SAVE);
+            proto.write(JobStorePersistStatsProto.Stats.NUM_TOTAL_JOBS, countAllJobsSaved);
+            proto.write(JobStorePersistStatsProto.Stats.NUM_SYSTEM_SERVER_JOBS,
+                    countSystemServerJobsSaved);
+            proto.write(JobStorePersistStatsProto.Stats.NUM_SYSTEM_SYNC_MANAGER_JOBS,
+                    countSystemSyncManagerJobsSaved);
+            proto.end(lsToken);
+
+            proto.end(token);
+        }
     }
 }
diff --git a/core/jni/android_app_ActivityThread.cpp b/core/jni/android_app_ActivityThread.cpp
index 3a08148..5f83038 100644
--- a/core/jni/android_app_ActivityThread.cpp
+++ b/core/jni/android_app_ActivityThread.cpp
@@ -36,7 +36,6 @@
 android_app_ActivityThread_dumpGraphics(JNIEnv* env, jobject clazz, jobject javaFileDescriptor) {
     int fd = jniGetFDFromFileDescriptor(env, javaFileDescriptor);
     android::uirenderer::renderthread::RenderProxy::dumpGraphicsMemory(fd);
-    minikin::Layout::dumpMinikinStats(fd);
 }
 
 static void android_app_ActivityThread_initZygoteChildHeapProfiling(JNIEnv* env, jobject clazz) {
diff --git a/core/jni/android_view_RenderNode.cpp b/core/jni/android_view_RenderNode.cpp
index 9450bc9..222a873 100644
--- a/core/jni/android_view_RenderNode.cpp
+++ b/core/jni/android_view_RenderNode.cpp
@@ -16,9 +16,6 @@
 
 #define LOG_TAG "OpenGLRenderer"
 #define ATRACE_TAG ATRACE_TAG_VIEW
-#ifdef __ANDROID__ // Layoutlib does not support EGL
-#include <EGL/egl.h>
-#endif
 #include "jni.h"
 #include "GraphicsJNI.h"
 #include <nativehelper/JNIHelp.h>
diff --git a/core/proto/android/server/alarmmanagerservice.proto b/core/proto/android/server/alarmmanagerservice.proto
index 490f729..b008fa9 100644
--- a/core/proto/android/server/alarmmanagerservice.proto
+++ b/core/proto/android/server/alarmmanagerservice.proto
@@ -20,7 +20,7 @@
 import "frameworks/base/core/proto/android/app/pendingintent.proto";
 import "frameworks/base/core/proto/android/internal/locallog.proto";
 import "frameworks/base/core/proto/android/os/worksource.proto";
-import "frameworks/base/core/proto/android/server/forceappstandbytracker.proto";
+import "frameworks/base/core/proto/android/server/appstatetracker.proto";
 import "frameworks/base/core/proto/android/privacy.proto";
 
 package com.android.server;
@@ -38,8 +38,8 @@
     // Current settings
     optional ConstantsProto settings = 5;
 
-    // Dump from ForceAppStandbyTracker.
-    optional ForceAppStandbyTrackerProto force_app_standby_tracker = 6;
+    // Dump from AppStateTracker.
+    optional AppStateTrackerProto app_state_tracker = 6;
 
     optional bool is_interactive = 7;
     // Only valid if is_interactive is false.
diff --git a/core/proto/android/server/forceappstandbytracker.proto b/core/proto/android/server/appstatetracker.proto
similarity index 91%
rename from core/proto/android/server/forceappstandbytracker.proto
rename to core/proto/android/server/appstatetracker.proto
index 89424bc..51e8845 100644
--- a/core/proto/android/server/forceappstandbytracker.proto
+++ b/core/proto/android/server/appstatetracker.proto
@@ -23,12 +23,15 @@
 
 option java_multiple_files = true;
 
-// Dump from com.android.server.ForceAppStandbyTracker.
+// Dump from com.android.server.AppStateTracker.
 //
-// Next ID: 13
-message ForceAppStandbyTrackerProto {
+// Next ID: 14
+message AppStateTrackerProto {
     option (.android.msg_privacy).dest = DEST_AUTOMATIC;
 
+    //  True if the forced app standby feature is enabled in settings.
+    optional bool forced_app_standby_feature_enabled = 13;
+
     // Whether all apps are forced standby or not.
     optional bool force_all_apps_standby = 1;
 
diff --git a/core/proto/android/server/jobscheduler.proto b/core/proto/android/server/jobscheduler.proto
index 5d4be55..aac144c 100644
--- a/core/proto/android/server/jobscheduler.proto
+++ b/core/proto/android/server/jobscheduler.proto
@@ -28,8 +28,9 @@
 import "frameworks/base/core/proto/android/net/networkrequest.proto";
 import "frameworks/base/core/proto/android/os/bundle.proto";
 import "frameworks/base/core/proto/android/os/persistablebundle.proto";
-import "frameworks/base/core/proto/android/server/forceappstandbytracker.proto";
+import "frameworks/base/core/proto/android/server/appstatetracker.proto";
 import "frameworks/base/core/proto/android/server/job/enums.proto";
+import "frameworks/base/core/proto/android/server/statlogger.proto";
 import "frameworks/base/core/proto/android/privacy.proto";
 
 // Next tag: 21
@@ -53,18 +54,22 @@
         optional JobStatusShortInfoProto info = 1;
         optional JobStatusDumpProto dump = 2;
 
+        optional bool is_job_ready_to_be_executed = 10;
         // A job is ready to be executed if:
-        // is_job_ready && is_user_started && !is_job_pending &&
+        // is_job_ready && are_users_started && !is_job_thermal_constrained && !is_job_pending &&
         // !is_job_currently_active && !is_uid_backing_up &&
-        // is_component_present.
+        // is_component_usable.
         optional bool is_job_ready = 3;
-        optional bool is_user_started = 4;
+        optional bool are_users_started = 4;
+        optional bool is_job_thermal_constrained = 11;
         optional bool is_job_pending = 5;
         optional bool is_job_currently_active = 6;
         optional bool is_uid_backing_up = 7;
-        optional bool is_component_present = 8;
+        optional bool is_component_usable = 8;
 
         reserved 9; // last_run_heartbeat
+
+        // Next tag: 12
     }
     repeated RegisteredJob registered_jobs = 3;
 
@@ -95,7 +100,7 @@
         optional JobStatusDumpProto dump = 2;
         optional sint32 evaluated_priority = 3;
         // How long this job has been pending.
-        optional int64 enqueued_duration_ms = 4;
+        optional int64 pending_duration_ms = 4;
     }
     repeated PendingJob pending_jobs = 9;
 
@@ -123,7 +128,7 @@
             optional sint32 evaluated_priority = 5;
 
             optional int64 time_since_made_active_ms = 6;
-            // How long this job has been pending.
+            // How long this job was pending before it became active.
             optional int64 pending_duration_ms = 7;
         }
         oneof job {
@@ -144,6 +149,8 @@
 
     // Dump from JobConcurrencyManager.
     optional JobConcurrencyManagerProto concurrency_manager = 20;
+
+    optional JobStorePersistStatsProto persist_stats = 21;
 }
 
 // A com.android.server.job.JobSchedulerService.Constants object.
@@ -347,7 +354,7 @@
     message BackgroundJobsController {
         option (.android.msg_privacy).dest = DEST_AUTOMATIC;
 
-        optional com.android.server.ForceAppStandbyTrackerProto force_app_standby_tracker = 1;
+        optional com.android.server.AppStateTrackerProto app_state_tracker = 1;
 
         message TrackedJob {
             option (.android.msg_privacy).dest = DEST_AUTOMATIC;
@@ -386,7 +393,7 @@
     message ConnectivityController {
         option (.android.msg_privacy).dest = DEST_AUTOMATIC;
 
-        optional bool is_connected = 1;
+        reserved 1; // is_connected
 
         message TrackedJob {
             option (.android.msg_privacy).dest = DEST_AUTOMATIC;
@@ -396,6 +403,12 @@
             optional .android.net.NetworkRequestProto required_network = 3;
         }
         repeated TrackedJob tracked_jobs = 2;
+
+        // List of the UIDs that ConnectivityController has requested that NetworkPolicyManager
+        // grant an exception to in the app standby chain.
+        repeated int32 requested_standby_exception_uids = 3;
+
+        repeated .android.net.NetworkProto available_networks = 4;
     }
     message ContentObserverController {
         option (.android.msg_privacy).dest = DEST_AUTOMATIC;
@@ -480,6 +493,31 @@
             optional int32 source_uid = 2;
         }
         repeated TrackedJob tracked_jobs = 2;
+
+        message IdlenessTracker {
+            option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
+            message CarIdlenessTracker {
+                option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
+                optional bool is_idle = 1;
+                optional bool is_garage_mode_on = 2;
+            }
+
+            message DeviceIdlenessTracker {
+                option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
+                optional bool is_idle = 1;
+                optional bool is_screen_on = 2;
+                optional bool is_dock_idle = 3;
+            }
+
+            oneof active_tracker {
+                DeviceIdlenessTracker device_idleness_tracker = 1;
+                CarIdlenessTracker car_idleness_tracker = 2;
+            }
+        }
+        optional IdlenessTracker idleness_tracker = 3;
     }
     message QuotaController {
         option (.android.msg_privacy).dest = DEST_AUTOMATIC;
@@ -623,6 +661,17 @@
             optional AlarmListener in_quota_alarm_listener = 5;
         }
         repeated PackageStats package_stats = 5;
+
+        // Set of package names for each UID.
+        message UidPackageMapping {
+            option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
+            optional int32 uid = 1;
+            repeated string package_names = 2;
+        }
+        repeated UidPackageMapping uid_to_package_cache = 7;
+
+        // Next tag: 8
     }
     message StorageController {
         option (.android.msg_privacy).dest = DEST_AUTOMATIC;
@@ -937,10 +986,15 @@
     optional sint64 time_until_earliest_runtime_ms = 19;
     // Can be negative if the latest runtime deadline has passed.
     optional sint64 time_until_latest_runtime_ms = 20;
+    // The original latest runtime value, in the elapsed realtime timebase. Valid only for periodic
+    // jobs.
+    optional uint64 original_latest_runtime_elapsed = 30;
 
     optional int32 num_failures = 21;
 
+    // Last time a job finished successfully for a periodic job, in currentTimeMillis time.
     optional int64 last_successful_run_time = 22;
+    // Last time a job finished unsuccessfully, in currentTimeMillis time.
     optional int64 last_failed_run_time = 23;
 
     optional int64 internal_flags = 24;
@@ -953,7 +1007,7 @@
     // was no attempt.
     optional int64 time_since_first_force_batch_attempt_ms = 29;
 
-    // Next tag: 30
+    // Next tag: 31
 }
 
 // Dump from com.android.server.job.JobConcurrencyManager.
@@ -962,9 +1016,9 @@
     option (.android.msg_privacy).dest = DEST_AUTOMATIC;
 
     // Whether the device is interactive (== screen on) now or not.
-    optional bool current_interactive = 1;
-    // Similar to current_interactive, screen on or not, but it takes into account the off timeout.
-    optional bool effective_interactive = 2;
+    optional bool current_interactive_state = 1;
+    // Similar to current_interactive_state, screen on or not, but it takes into account the off timeout.
+    optional bool effective_interactive_state = 2;
     // How many milliseconds have passed since the last screen on. (i.e. 1000 == 1 sec ago)
     optional int64 time_since_last_screen_on_ms = 3;
     // How many milliseconds have passed since the last screen off. (i.e. 1000 == 1 sec ago)
@@ -973,6 +1027,8 @@
     optional JobCountTrackerProto job_count_tracker = 5;
     // Current memory trim level.
     optional int32 memory_trim_level = 6;
+    // Performance stats.
+    optional StatLoggerProto stats = 7;
 }
 
 // Dump from com.android.server.job.JobConcurrencyManager.JobCountTracker.
@@ -997,4 +1053,23 @@
     optional int32 num_pending_fg_jobs = 6;
     // Number of pending background jobs.
     optional int32 num_pending_bg_jobs = 7;
+
+    optional int32 num_actual_max_fg_jobs = 8;
+    optional int32 num_actual_max_bg_jobs = 9;
+
+    optional int32 num_reserved_for_bg = 10;
+
+    optional int32 num_starting_fg_jobs = 11;
+    optional int32 num_starting_bg_jobs = 12;
+}
+
+message JobStorePersistStatsProto {
+    message Stats {
+        optional int32 num_total_jobs = 1;
+        optional int32 num_system_server_jobs = 2;
+        optional int32 num_system_sync_manager_jobs = 3;
+    }
+
+    optional Stats first_load = 1;
+    optional Stats last_save = 2;
 }
diff --git a/core/proto/android/server/statlogger.proto b/core/proto/android/server/statlogger.proto
index 8593da8..c995599 100644
--- a/core/proto/android/server/statlogger.proto
+++ b/core/proto/android/server/statlogger.proto
@@ -34,6 +34,9 @@
         optional string label = 2;
         optional int32 count = 3;
         optional int64 total_duration_micros = 4;
+        optional int32 max_calls_per_second = 5;
+        optional int64 max_duration_per_second_micros = 6;
+        optional int64 max_duration_stats_micros = 7;
     }
 
     repeated Event events = 1;
diff --git a/core/proto/android/service/graphicsstats.proto b/core/proto/android/service/graphicsstats.proto
index 11f0467..557075c 100644
--- a/core/proto/android/service/graphicsstats.proto
+++ b/core/proto/android/service/graphicsstats.proto
@@ -51,6 +51,9 @@
 
     // The frame time histogram for the package.
     repeated GraphicsStatsHistogramBucketProto histogram = 6;
+
+    // The gpu frame time histogram for the package
+    repeated GraphicsStatsHistogramBucketProto gpu_histogram = 7;
 }
 
 message GraphicsStatsJankSummaryProto {
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 7a0d475..878cda1 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Stemboodskappe"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi-oproepe"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"SIM-status"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Hoëprioriteit-SIM-status"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Ander party het TTY-modus VOL versoek"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Ander party het TTY-modus GOD versoek"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Ander party het TTY-modus SOD versoek"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 11ab44d..f5ef6ca 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"የድምጽ መልዕክቶች"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"የWi-Fi ጥሪ"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"የሲም ሁኔታ"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"ከፍተኛ ቅድሚያ ተሰጪ የሲም ኹናቴ"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"ቢጤ መልዕክት መጻጻፊያ ስልክ ሁነታ FULL ጠይቋል"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"ቢጤ መልዕክት መጻጻፊያ ስልክ ሁነታ HCO ጠይቋል"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"ቢጤ መልዕክት መጻጻፊያ ስልክ ሁነታ VCO ጠይቋል"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 6edc933..217c3cf 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -99,6 +99,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"رسائل البريد الصوتي"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"‏الاتصال عبر Wi-Fi"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"‏حالة شريحة SIM"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"‏حالة شريحة SIM ذات أولوية"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"‏طلب النظير وضع TTY الكامل"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"‏طلب النظير وضع TTY على HCO"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"‏طلب النظير وضع TTY على VCO"</string>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index 3660403..6ea6a52 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"ভইচমেইলৰ বাৰ্তাসমূহ"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"ৱাই-ফাই কলিং"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"ছিমৰ স্থিতি"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"উচ্চ অগ্ৰাধিকাৰযুক্ত ছিমৰ স্থিতি"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"নেটৱৰ্ক পীয়েৰে TTY ম\'ড FULLলৈ সলনি কৰিবলৈ অনুৰোধ কৰিছে"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"নেটৱৰ্ক পীয়েৰে TTY ম\'ড HCOলৈ সলনি কৰিবলৈ অনুৰোধ কৰিছে"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"নেটৱৰ্ক পীয়েৰে TTY ম\'ড VCO লৈ সলনি কৰিবলৈ অনুৰোধ কৰিছে"</string>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index e2b3998..47572bc87 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Səsli e-poçt mesajları"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi zəngi"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"SIM status"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Yüksək Prioritetli SIM statusu"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Eskpert TTY Rejimi FULL-u sorğuladı"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Ekspert TTY Rejimi HCO-nu sorğuladı"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Ekspert TTY Rejimi VCO-nu sorğuladı"</string>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index 821b730..9bd9e93 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -96,6 +96,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Poruke govorne pošte"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Pozivanje preko Wi-Fi mreže"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"Status SIM-a"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Obaveštenja SIM kartice sa statusom „visok prioritet“"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Korisnik zahteva POTPUN režim TTY"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Korisnik zahteva PRENOS ZVUKA za režim TTY"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Korisnik zahteva PRENOS GLASA za režim TTY"</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index d573202..2b5d8c9 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -97,6 +97,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Паведамленні галасавой пошты"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi-тэлефанія"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"Статус SIM-карты"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Стан SIM-карты з высокім прыярытэтам"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Аднарангавая прылада запытала рэжым TTY FULL"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Аднарангавая прылада запытала рэжым TTY НСО"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Аднарангавая прылада запытала рэжым TTY VCO"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index e073b7d..c9220a0 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Съобщения в гласовата поща"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Обаждания през Wi-Fi"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"Състояние на SIM картата"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Състояние на SIM картата с висок приоритет"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Отсрещният потребител заяви пълен TTY режим (FULL)"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Отсрещният потребител заяви TTY режим с пренос на слух (HCO)"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Отсрещният потребител заяви TTY режим с пренос на глас (VCО)"</string>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index 368ff90..b6a9240 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"ভয়েসমেল মেসেজ"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"ওয়াই-ফাই কলিং"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"সিম কার্ডের স্টাটাস"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"উচ্চ প্রায়রিটি সিম স্ট্যাটাস"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"পির TTY মোড FULL অনুরোধ করেছে"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"পির TTY মোড HCO অনুরোধ করেছে"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"পির TTY মোড VCO অনুরোধ করেছে"</string>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index ce852b6..02d65e3 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -96,6 +96,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Poruke govorne pošte"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Pozivanje putem WiFi-ja"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"Status SIM-a"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Status visokog prioriteta SIM-a"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Ravnopravni uređaj zatražio načina rada TTY FULL"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Ravnopravni uređaj zatražio načina rada TTY HCO"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Ravnopravni uređaj zatražio načina rada TTY VCO"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index bbf1736..0ec04b6 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Missatges de veu"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Trucades per Wi-Fi"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"Estat de la SIM"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Estat de la SIM d\'alta prioritat"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"L\'altre dispositiu ha sol·licitat el mode TTY COMPLET."</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"L\'altre dispositiu ha sol·licitat el mode TTY HCO."</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"L\'altre dispositiu ha sol·licitat el mode TTY VCO."</string>
@@ -573,9 +574,9 @@
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"Torna a registrar la teva cara."</string>
     <string name="face_acquired_too_different" msgid="7663983770123789694">"Ja no es reconeix la teva cara. Torna-ho a provar."</string>
     <string name="face_acquired_too_similar" msgid="1508776858407646460">"És massa semblant; canvia de postura."</string>
-    <string name="face_acquired_pan_too_extreme" msgid="4581629343077288178">"Inclina el cap una mica menys."</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="4019954263012496468">"Inclina el cap una mica menys."</string>
-    <string name="face_acquired_roll_too_extreme" msgid="6312973147689664409">"No inclinis tant el cap."</string>
+    <string name="face_acquired_pan_too_extreme" msgid="4581629343077288178">"No giris tant el cap."</string>
+    <string name="face_acquired_tilt_too_extreme" msgid="4019954263012496468">"No inclinis tant el cap."</string>
+    <string name="face_acquired_roll_too_extreme" msgid="6312973147689664409">"No giris tant el cap."</string>
     <string name="face_acquired_obscured" msgid="5357207702967893283">"Suprimeix qualsevol cosa que amagui la teva cara."</string>
     <string name="face_acquired_sensor_dirty" msgid="7905138627046865579">"Neteja la part superior de la pantalla, inclosa la barra negra"</string>
   <string-array name="face_acquired_vendor">
@@ -1483,7 +1484,7 @@
     <string name="back_button_label" msgid="2300470004503343439">"Enrere"</string>
     <string name="next_button_label" msgid="1080555104677992408">"Següent"</string>
     <string name="skip_button_label" msgid="1275362299471631819">"Omet"</string>
-    <string name="no_matches" msgid="8129421908915840737">"Cap coincidència"</string>
+    <string name="no_matches" msgid="8129421908915840737">"No s\'ha trobat cap coincidència"</string>
     <string name="find_on_page" msgid="1946799233822820384">"Troba-ho a la pàgina"</string>
     <plurals name="matches_found" formatted="false" msgid="1210884353962081884">
       <item quantity="other"><xliff:g id="INDEX">%d</xliff:g> de <xliff:g id="TOTAL">%d</xliff:g></item>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 4171a8b..3a77e9c 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -97,6 +97,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Hlasové zprávy"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Volání přes Wi-Fi"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"Stav SIM karty"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Stav SIM karty: vysoká priorita"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Partner požádal o přechod na režim TTY FULL"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Partner požádal o přechod na režim TTY HCO"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Partner požádal o přechod na režim TTY VCO"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index b6cb874..c10680e 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Talebeskeder"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi-opkald"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"SIM-status"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"SIM-kort med høj prioritet"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Den anden enhed har skiftet til FULD TTY-tilstand"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Den anden enhed har skiftet til TTY-tilstanden HCO"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Den anden enhed har skiftet til TTY-tilstanden VCO"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 114d801..933741a 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Mailboxnachrichten"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"WLAN-Telefonie"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"Status der SIM-Karte"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Benachrichtigungen mit hoher Priorität von der SIM-Karte"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Peer hat TTY-Modus \"Vollständig\" angefordert."</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Peer hat TTY-Modus \"HCO\" angefordert."</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Peer hat TTY-Modus \"VC\" angefordert."</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 44357ff..e5ff8a8 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Μηνύματα αυτόματου τηλεφωνητή"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Κλήση Wi-Fi"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"Κατάσταση SIM"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Κατάσταση SIM υψηλής προτεραιότητας"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Αίτημα peer για TTY ΠΛΗΡΗΣ Λειτουργία"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Αίτημα peer για TTY Λειτουργία HCO"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Αίτημα peer για TTY Λειτουργία VCO"</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index cc389f3..4f0ebc5 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Voicemail messages"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi Calling"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"SIM status"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"High priority SIM status"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Peer requested TTY Mode FULL"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Peer requested TTY Mode HCO"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Peer requested TTY Mode VCO"</string>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index 0e6d49c..d1ac6dc 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Voicemail messages"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi Calling"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"SIM status"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"High priority SIM status"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Peer requested TTY Mode FULL"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Peer requested TTY Mode HCO"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Peer requested TTY Mode VCO"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index cc389f3..4f0ebc5 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Voicemail messages"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi Calling"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"SIM status"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"High priority SIM status"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Peer requested TTY Mode FULL"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Peer requested TTY Mode HCO"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Peer requested TTY Mode VCO"</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index cc389f3..4f0ebc5 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Voicemail messages"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi Calling"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"SIM status"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"High priority SIM status"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Peer requested TTY Mode FULL"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Peer requested TTY Mode HCO"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Peer requested TTY Mode VCO"</string>
diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml
index dade85e..66aa946 100644
--- a/core/res/res/values-en-rXC/strings.xml
+++ b/core/res/res/values-en-rXC/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‏‎‏‏‎‏‏‏‏‏‏‏‎‎‏‎‎‎‎‏‏‏‏‎‎‏‏‏‏‏‏‏‏‏‏‎‏‎‏‎‎‏‏‏‏‏‎‏‏‏‏‎‏‎‏‏‏‏‎Voicemail messages‎‏‎‎‏‎"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‎‏‏‎‎‏‎‎‏‎‎‎‏‎‎‎‎‏‏‎‎‏‎‏‎‏‏‏‏‏‎‏‎‏‏‎‎‏‏‏‎‏‏‎‎‏‎‏‎‎‏‏‎‏‎‎‎‏‎Wi-Fi calling‎‏‎‎‏‎"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‎‏‏‏‏‎‏‏‎‎‎‎‏‏‏‏‏‏‏‎‎‎‏‏‎‎‏‎‎‎‏‎‎‎‎‏‏‎‏‎‏‎‏‎‎‎SIM status‎‏‎‎‏‎"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‎‏‏‎‎‏‏‏‏‎‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‏‏‏‏‎‏‏‎‎‏‎‏‎‎‎‏‏‏‏‏‎‎‏‎‎‎‎‎‏‏‏‎High priority SIM status‎‏‎‎‏‎"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‎‏‏‎‎‎‏‏‏‏‏‎‏‏‏‎‏‎‏‏‎‎‏‎‎‏‏‎‎‏‏‏‏‎‏‏‏‎‎‎‏‎‏‎‎‏‏‎‎‎‎‎‏‎‏‏‎‏‎Peer requested TTY Mode FULL‎‏‎‎‏‎"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‏‏‏‎‎‎‎‎‎‎‎‎‎‏‎‏‎‏‎‏‎‏‎‎‎‎‎‏‎‎‏‏‏‎‎‎‏‏‏‎‎‏‎‏‎‏‎‎‎‎‎‎‎‏‎‎‎‎‎Peer requested TTY Mode HCO‎‏‎‎‏‎"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‎‎‎‏‎‏‏‏‎‎‏‎‎‎‏‎‎‎‎‎‏‏‎‎‎‏‎‏‏‎‎‎‏‎‏‏‏‏‎‏‏‏‎‏‏‎‎‎‏‎‏‎‎‎‎‎‏‎Peer requested TTY Mode VCO‎‏‎‎‏‎"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 3a2ea3e..68604d9 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Mensajes del buzón de voz"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Llamada con Wi-Fi"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"Estado de SIM"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Notificaciones de prioridad alta sobre el estado de la SIM"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"El dispositivo del mismo nivel solicitó el modo TTY FULL."</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"El dispositivo del mismo nivel solicitó el modo TTY HCO."</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"El dispositivo del mismo nivel solicitó el modo TTY VCO."</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 633759b..f290fae 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Mensajes de voz"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Llamada por Wi-Fi"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"Estado de la tarjeta SIM"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Estado de SIM de alta prioridad"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Un dispositivo ha solicitado el modo TTY FULL"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Un dispositivo ha solicitado el modo TTY HCO"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Un dispositivo ha solicitado el modo TTY VCO"</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 86843c7..8e07555 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Kõnepostisõnumid"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"WiFi-kõned"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"SIM-kaardi olek"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Kõrge prioriteediga SIM-i olek"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Partner taotles TTY-režiimi TÄIELIK"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Partner taotles TTY-režiimi HCO"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Partner taotles TTY-režiimi VCO"</string>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index d25fe8c..7303406 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Erantzungailuko mezuak"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi bidezko deiak"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"SIMaren egoera"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"SIM txartelaren lehentasun handiko jakinarazpenak"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Beste gailuak TTY osagarria FULL moduan erabiltzea eskatu du"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Beste gailuak TTY osagarria HCO moduan erabiltzea eskatu du"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Beste gailuak TTY osagarria VCO moduan erabiltzea eskatu du"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 48cdafc..44428dc 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"پیام‌های پست صوتی"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"‏تماس ازطریق Wi-Fi"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"وضعیت سیم‌کارت"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"وضعیت سیم با اولویت بالا"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"‏دستگاه مرتبط درخواست TTY حالت FULL کرد"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"‏دستگاه مرتبط درخواست TTY حالت HCO کرد"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"‏دستگاه مرتبط درخواست TTY حالت VCO کرد"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index cd9a711..ccc9d33 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Vastaajaviestit"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi-puhelut"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"SIM-kortin tila"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Tärkeät SIM-ilmoitukset"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Toinen käyttäjä vaihtoi TTY-tilaksi TÄYSI"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Toinen käyttäjä vaihtoi TTY-tilaksi HCO"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Toinen käyttäjä vaihtoi TTY-tilaksi VCO"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 2bfef39..99f874d 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Messages vocaux"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Appels Wi-Fi"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"État de la carte SIM"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"État SIM de priorité élevée"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Mode TTY COMPLET demandé par un pair"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Mode TTY HCO demandé par un pair"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Mode TTY VCO demandé par un pair"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 041668f..bac6066 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Messages vocaux"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Appels Wi-Fi"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"État de la carte SIM"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Notifications prioritaires de la carte SIM"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Mode TTY demandé par l\'interlocuteur : COMPLET"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Mode TTY demandé par l\'interlocuteur : HCO"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Mode TTY demandé par l\'interlocuteur : VCO"</string>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index b3eed4a..40c1ed2 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Mensaxes de correo de voz"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Chamadas por wifi"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"Estado da SIM"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Estado da SIM con prioridade alta"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Outro dispositivo solicitou o modo TTY COMPLETO"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Outro dispositivo solicitou o modo TTY HCO"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Outro dispositivo solicitou o modo TTY VCO"</string>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index 1b96172..bbb344b 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"વૉઇસમેઇલ સંદેશા"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"વાઇ-ફાઇ કૉલિંગ"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"સિમનું સ્ટેટસ"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"સિમ કાર્ડનું ઉચ્ચ પ્રાધાન્યતાનું સ્ટેટસ"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"પીઅરે TTY મોડ પૂર્ણની વિનંતી કરી"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"પીઅરે TTY મોડ HCO ની વિનંતી કરી"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"પીઅરે TTY મોડ VCO ની વિનંતી કરી"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index fd063c4..f130e01 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"वॉइसमेल संदेश"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"वाई-फ़ाई कॉलिंग"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"सिम की स्थिति"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"सिम की ज़रूरी सूचनाओं की स्थिति"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"पीयर ने टेलीटाइपराइटर (TTY) मोड फ़ुल का अनुरोध किया"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"पीयर ने टेलीटाइपराइटर (TTY) मोड एचसीओ (HCO) का अनुरोध किया"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"पीयर ने टेलीटाइपराइटर (TTY) मोड वीसीओ (VCO) का अनुरोध किया"</string>
@@ -451,7 +452,7 @@
     <string name="permdesc_readPhoneNumbers" msgid="8559488833662272354">"ऐप को डिवाइस के फ़ोन नंबर का इस्तेमाल करने देती है."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"टैबलेट को सोने (कम बैटरी मोड) से रोकें"</string>
     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"टीवी को सोने (कम बैटरी मोड) से रोकें"</string>
-    <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"टीवी को सोने (कम बैटरी मोड) से रोकें"</string>
+    <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"फ़ोन को सोने (कम बैटरी मोड) से रोकें"</string>
     <string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"ऐप्स  को टैबलेट को प्रयोग में नहीं हो जाने से रोकता है."</string>
     <string name="permdesc_wakeLock" product="tv" msgid="3208534859208996974">"ऐप को टीवी को सोने (कम बैटरी मोड) से रोकने की अनुमति देता है."</string>
     <string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"ऐप्स  को फ़ोन को प्रयोग में नहीं होने से रोकता है."</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 21fdc2f..38bd8a3 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -96,6 +96,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Poruke govorne pošte"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi pozivi"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"Status SIM-a"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Status SIM-a visokog prioriteta"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Način TTY FULL koji zahtijeva paralelni uređaj"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Način TTY HCO koji zahtijeva paralelni uređaj"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Način TTY VCO koji zahtijeva paralelni uređaj"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 1198610..d146ca7 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Hangpostaüzenetek"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi-hívás"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"SIM-kártya állapota"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Elsődleges SIM-kártya állapota"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Partner által kért TTY-mód: FULL"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Partner által kért TTY-mód: HCO"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Partner által kért TTY-mód: VCO"</string>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index 7165df9..91d2552 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Ձայնային փոստի հաղորդագրություններ"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Զանգեր Wi-Fi-ի միջոցով"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"SIM քարտի կարգավիճակը"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"SIM քարտի բարձր առաջնահերթության ծանուցումներ"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Բաժանորդի սարքում ընտրված է հեռատիպի ԲՈԼՈՐԸ ռեժիմը"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Բաժանորդի սարքում ընտրված է հեռատիպի HCO ռեժիմը"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Բաժանորդի սարքում ընտրված է հեռատիպի VCO ռեժիմը"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index ca369eb..4a8723b 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Notifikasi pesan suara"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Panggilan Wi-Fi"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"Status SIM"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Status SIM prioritas tinggi"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Rekan meminta Mode TTY PENUH"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Rekan meminta Mode TTY HCO"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Rekan meminta Mode TTY VCO"</string>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index 572313a..16bcd27 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Talhólfsskilaboð"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi símtöl"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"Staða SIM-korts"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Áríðandi staða SIM-korts"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Jafningi bað um FULLA stillingu fjarrita"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Jafningi bað um HCO-stillingu fjarrita"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Jafningi bað um VCO-stillingu fjarrita"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 6c579b8..8581eca 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Messaggi vocali"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Chiamate Wi-Fi"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"Stato SIM"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Stato SIM con priorità elevata"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Peer ha richiesto la modalità TTY FULL"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Peer ha richiesto la modalità TTY HCO"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Peer ha richiesto la modalità TTY VCO"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 437b31b..dc108b4 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -97,6 +97,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"הודעות קוליות"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"‏שיחות Wi-Fi"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"‏סטטוס SIM"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"‏סטטוס התראות SIM בעדיפות גבוהה"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"‏העמית ביקש TTY במצב FULL"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"‏העמית ביקש TTY במצב HCO"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"‏העמית ביקש TTY במצב VCO"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 471c666..5180ab2 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"ボイスメール メッセージ"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi 通話"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"SIM のステータス"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"高優先度: SIM のステータス"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"ピアから、TTY モードを FULL にするようリクエストされました"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"ピアから、TTYモードをHCOにするようリクエストされました"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"ピアから、TTYモードをVCOにするようリクエストされました"</string>
@@ -551,11 +552,11 @@
   <string-array name="fingerprint_error_vendor">
   </string-array>
     <string name="fingerprint_icon_content_description" msgid="2340202869968465936">"指紋アイコン"</string>
-    <string name="permlab_manageFace" msgid="7262837876352591553">"フェイスアンロック ハードウェアの管理"</string>
+    <string name="permlab_manageFace" msgid="7262837876352591553">"顔認証ハードウェアの管理"</string>
     <string name="permdesc_manageFace" msgid="8919637120670185330">"使用する顔テンプレートの追加や削除を行うメソッドの呼び出しをアプリに許可します。"</string>
-    <string name="permlab_useFaceAuthentication" msgid="2565716575739037572">"フェイスアンロック ハードウェアの使用"</string>
-    <string name="permdesc_useFaceAuthentication" msgid="4712947955047607722">"フェイスアンロック ハードウェアを認証に使用することをアプリに許可します"</string>
-    <string name="face_recalibrate_notification_name" msgid="1913676850645544352">"フェイスアンロック"</string>
+    <string name="permlab_useFaceAuthentication" msgid="2565716575739037572">"顔認証ハードウェアの使用"</string>
+    <string name="permdesc_useFaceAuthentication" msgid="4712947955047607722">"顔認証ハードウェアを認証に使用することをアプリに許可します"</string>
+    <string name="face_recalibrate_notification_name" msgid="1913676850645544352">"顔認証"</string>
     <string name="face_recalibrate_notification_title" msgid="4087620069451499365">"顔の再登録"</string>
     <string name="face_recalibrate_notification_content" msgid="5530308842361499835">"認識を改善するには、顔を再登録してください"</string>
     <string name="face_acquired_insufficient" msgid="2767330364802375742">"顔を認識できませんでした。もう一度お試しください。"</string>
@@ -581,15 +582,15 @@
   <string-array name="face_acquired_vendor">
   </string-array>
     <string name="face_error_hw_not_available" msgid="396883585636963908">"顔を確認できません。ハードウェアを利用できません。"</string>
-    <string name="face_error_timeout" msgid="981512090365729465">"フェイスアンロックをもう一度お試しください。"</string>
+    <string name="face_error_timeout" msgid="981512090365729465">"顔認証をもう一度お試しください。"</string>
     <string name="face_error_no_space" msgid="2712120617457553825">"新しい顔データを保存できません。古いデータを削除してください。"</string>
     <string name="face_error_canceled" msgid="283945501061931023">"顔の操作をキャンセルしました。"</string>
-    <string name="face_error_user_canceled" msgid="5317030072349668946">"フェイスアンロックはユーザーによりキャンセルされました。"</string>
+    <string name="face_error_user_canceled" msgid="5317030072349668946">"顔認証はユーザーによりキャンセルされました。"</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"試行回数の上限です。後でもう一度お試しください。"</string>
-    <string name="face_error_lockout_permanent" msgid="4723594314443097159">"試行回数が上限を超えました。フェイスアンロックを無効にしました。"</string>
+    <string name="face_error_lockout_permanent" msgid="4723594314443097159">"試行回数が上限を超えたため、顔認証を無効にしました。"</string>
     <string name="face_error_unable_to_process" msgid="4940944939691171539">"顔を確認できません。もう一度お試しください。"</string>
-    <string name="face_error_not_enrolled" msgid="4016937174832839540">"フェイスアンロックを設定していません。"</string>
-    <string name="face_error_hw_not_present" msgid="8302690289757559738">"このデバイスでは、フェイスアンロックはご利用いただけません。"</string>
+    <string name="face_error_not_enrolled" msgid="4016937174832839540">"顔認証を設定していません。"</string>
+    <string name="face_error_hw_not_present" msgid="8302690289757559738">"このデバイスでは、顔認証はご利用いただけません。"</string>
     <string name="face_name_template" msgid="7004562145809595384">"顔 <xliff:g id="FACEID">%d</xliff:g>"</string>
   <string-array name="face_error_vendor">
   </string-array>
@@ -818,7 +819,7 @@
     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"もう一度お試しください"</string>
     <string name="lockscreen_password_wrong" msgid="5737815393253165301">"もう一度お試しください"</string>
     <string name="lockscreen_storage_locked" msgid="9167551160010625200">"すべての機能とデータを利用するにはロック解除"</string>
-    <string name="faceunlock_multiple_failures" msgid="754137583022792429">"フェイスアンロックの最大試行回数を超えました"</string>
+    <string name="faceunlock_multiple_failures" msgid="754137583022792429">"顔認証の最大試行回数を超えました"</string>
     <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"SIMカードが挿入されていません"</string>
     <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"タブレット内にSIMカードがありません。"</string>
     <string name="lockscreen_missing_sim_message" product="tv" msgid="1943633865476989599">"テレビにSIMカードが挿入されていません。"</string>
@@ -888,7 +889,7 @@
     <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"ロック解除エリアを拡大します。"</string>
     <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"スライドロックを解除します。"</string>
     <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"パターンロックを解除します。"</string>
-    <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"フェイスアンロックを行います。"</string>
+    <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"顔認証を行います。"</string>
     <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"PINロックを解除します。"</string>
     <string name="keyguard_accessibility_sim_pin_unlock" msgid="9149698847116962307">"SIM PIN のロックを解除します。"</string>
     <string name="keyguard_accessibility_sim_puk_unlock" msgid="9106899279724723341">"SIM PUK のロックを解除します。"</string>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index 3570d4c..2bba8cb 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"ხმოვანი ფოსტის შეტყობინებები"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"დარეკვა Wi-Fi-ს მეშვეობით"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"SIM სტატუსი"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"მაღალპრიორიტეტული SIM სტატუსი"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"მოთხოვნილია კვანძი TTY რეჟიმი FULL"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"მოთხოვნილია კვანძი TTY რეჟიმი HCO"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"მოთხოვნილია კვანძი TTY რეჟიმი VCO"</string>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index 2ed1e5b..ec0ab3e 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Дауыстық пошта хабарлары"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi қоңыраулары"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"SIM күйі"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"SIM картасы туралы маңызды хабарландырулар"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Пир TTY режимі ТОЛЫҚ сұрады"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Пир TTY режимінің HCO сұрады"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Пир TTY режимінің VCO сұрады"</string>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index 02c6ba8..e9a140c 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"សារ​ជា​សំឡេង"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"ការហៅ​ទូរសព្ទ​តាម Wi-Fi"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"ស្ថានភាព​ស៊ីម"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"ស្ថានភាពស៊ីម​ដែលមាន​អាទិភាព​ខ្ពស់"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"ម៉ាស៊ីនកូនបានស្នើ TTY Mode FULL"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"ម៉ាស៊ីនកូនបានស្នើ TTY Mode HCO"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"ម៉ាស៊ីនកូនបានស្នើ TTY Mode VCO"</string>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index 875ecd4..e82d54b 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"ಧ್ವನಿಮೇಲ್ ಸಂದೇಶಗಳು"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"ವೈ-ಫೈ ಕರೆ ಮಾಡುವಿಕೆ"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"ಸಿಮ್‌ ಸ್ಥಿತಿ"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"ಹೆಚ್ಚಿನ ಆದ್ಯತೆಯ ಸಿಮ್ ಸ್ಥಿತಿ"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"ಪೀರ್ ವಿನಂತಿಸಿಕೊಂಡ TTY ಮೋಡ್ ಪೂರ್ಣಗೊಂಡಿದೆ"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"ಪೀರ್ ವಿನಂತಿಸಿಕೊಂಡ TTY ಮೋಡ್ HCO"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"ಪೀರ್ ವಿನಂತಿಸಿಕೊಂಡ TTY ಮೋಡ್ VCO"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 9077145..4be4bd2 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"음성사서함 메시지"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi 통화"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"SIM 상태"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"우선순위가 높은 SIM 상태"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"피어가 TTY 모드 FULL을 요청했습니다."</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"피어가 TTY 모드 HCO를 요청했습니다."</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"피어가 TTY 모드 VCO를 요청했습니다."</string>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index 8cac363..6607242 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Үн почтасынын билдирүүлөрү"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi аркылуу чалуу"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"SIM-картанын абалы"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"SIM картадагы өтө маанилүү билдирмелер"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Peer TTY режимин FULL кылууну суранды"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Peer TTY режимин HCO кылууну суранды"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Peer TTY режимин VCO кылууну суранды"</string>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index 47b0fe4..684adc3 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"ຂໍ້ຄວາມສຽງ"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"ການ​ໂທ Wi-Fi"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"ສະຖານະ SIM"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"ສະຖານະ SIM ຄວາມສຳຄັນສູງ"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"ໂໝດ TTY ທີ່​ເພື່ອນ​ຂໍ​ນັ້ນ​ເຕັມ​ແລ້ວ"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"ໂໝດ TTY ທີ່​ເພື່ອນ​ຂໍ HCO"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"ໂໝດ TTY ທີ່​ເພື່ອນ​ຂໍ VCO"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 6f8e2df..5283f27 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -97,6 +97,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Balso pašto pranešimai"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"„Wi-Fi“ skambinimas"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"SIM būsena"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Didelio prioriteto SIM kortelės būsena"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Lygiavertis naudotojas pateikė užklausą dėl TTY režimo FULL"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Lygiavertis naudotojas pateikė užklausą dėl TTY režimo HCO"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Lygiavertis naudotojas pateikė užklausą dėl TTY režimo VCO"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 253ff72..c93ae1f 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -96,6 +96,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Balss pasta ziņojumi"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi zvani"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"SIM kartes statuss"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Augstas prioritātes SIM kartes statuss"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Vienādranga ierīce pieprasīja teksta tālruņa režīmu FULL"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Vienādranga ierīce pieprasīja teksta tālruņa režīmu HCO"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Vienādranga ierīce pieprasīja teksta tālruņa režīmu VCO"</string>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index 19c1c85..70ee0ae 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Пораки од говорна пошта"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Повикување преку Wi-Fi"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"Статус на SIM-картичка"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Статус на SIM-известувања со висок приоритет"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Рамноправен уред го побара режимот на TTY „FULL“"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Рамноправен уред го побара режимот на TTY „HCO“"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Рамноправен уред го побара режимот на TTY „VCO“"</string>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index b2e9b64..3fb844d 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"വോയ്‌സ്‌മെയിൽ സന്ദേശങ്ങൾ"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"വൈഫൈ കോളിംഗ്"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"സിം നില"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"ഉയർന്ന മുൻഗണനയുള്ള സിം നില"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"പിയർ അഭ്യർത്ഥിച്ച TTY മോഡ് \'ഫുൾ\'"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"പിയർ അഭ്യർത്ഥിച്ച TTY മോഡ് HCO"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"പിയർ അഭ്യർത്ഥിച്ച TTY മോഡ് VCO"</string>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index a229713..254bb0e 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Дуут шуудангийн мессеж"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi дуудлага"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"SIM статус"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Өндөр ач холбогдолтой SIM-н статус"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Хандлагын цэгт хүсэлт тавьсан TTY Mode FULL"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Хандлагын цэгт хүсэлт тавьсан TTY Mode HCO"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Хандлагын цэгт хүсэлт тавьсан TTY Mode VCO"</string>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index a86caa5..5fc2310 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"व्हॉइसमेल मेसेज"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"वाय-फाय कॉलिंग"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"सिम स्थिती"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"उच्च प्राधान्य सिम स्थिती"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"समवयस्क व्यक्तीने TTY मोड पूर्ण ची विनंती केली"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"समवयस्क व्यक्तीने TTY मोड HCO ची विनंती केली"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"समवयस्क व्यक्तीने TTY मोड VCO ची विनंती केली"</string>
@@ -302,8 +303,8 @@
     <string name="permgroupdesc_activityRecognition" msgid="6949472038320473478">"शारीरिक अ‍ॅक्टिव्हिटी अ‍ॅक्सेस करा"</string>
     <string name="permgrouprequest_activityRecognition" msgid="7626438016904799383">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ला तुमची शारीरिक अ‍ॅक्टिव्हिटी अ‍ॅक्सेस करण्याची अनुमती द्यायची का?"</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"कॅमेरा"</string>
-    <string name="permgroupdesc_camera" msgid="3250611594678347720">"चित्रे घेण्याची आणि व्हिडिओ रेकॉर्ड"</string>
-    <string name="permgrouprequest_camera" msgid="1299833592069671756">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ला फोटो घेऊ आणि व्हिडिओ रेकॉर्ड करू द्यायचे?"</string>
+    <string name="permgroupdesc_camera" msgid="3250611594678347720">"चित्रे काढण्याची आणि व्हिडिओ रेकॉर्ड करण्याची"</string>
+    <string name="permgrouprequest_camera" msgid="1299833592069671756">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ला फोटो काढू आणि व्हिडिओ रेकॉर्ड करू द्यायचे?"</string>
     <string name="permgrouplab_calllog" msgid="8798646184930388160">"कॉल लॉग"</string>
     <string name="permgroupdesc_calllog" msgid="3006237336748283775">"फोन कॉल लॉग वाचा आणि लिहा"</string>
     <string name="permgrouprequest_calllog" msgid="8487355309583773267">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ला तुमचे फोन कॉल लॉग अ‍ॅक्सेस करण्याची अनुमती द्यायची का?"</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index c18e078..7d1b76c 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Mesej mel suara"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Panggilan Wi-Fi"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"Status SIM"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Status SIM keutamaan tinggi"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Rakan meminta Mod TTY PENUH"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Rakan meminta Mod TTY HCO"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Rakan meminta Mod TTY VCO"</string>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index 55e7b01..e037b70 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"အသံမေးလ် မက်ဆေ့ဂျ်များ"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi ခေါ်ဆိုမှု"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"ဆင်းမ်ကဒ် အခြေအနေ"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"အထူးဦးစားပေး ဆင်းမ်ကတ်အခြေအနေ"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"အခြားစက်မှ TTY မုဒ် FULL ပြုရန် တောင်းဆို၏"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"အခြားစက်မှ TTY မုဒ် HCO ပြုရန် တောင်းဆို၏"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"TTY မုဒ် VCO ပြုရန် အခြားစက်မှ တောင်းဆို၏"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index a589389..c75c8d1 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Talepostmeldinger"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi-anrop"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"SIM-status"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"SIM-status er satt til høy prioritet"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Motpart ba om TTY-modus FULL"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Motpart ba om TTY-modus HCO"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Motpart ba om TTY-modus VCO"</string>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index 89e75b4..1422caa 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"भ्वाइस मेल सन्देशहरू"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi कल"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"SIM को स्थिति"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"उच्च प्राथमिकता रहेको SIM को स्थिति"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"सहकर्मी अनुरोध गरियो। TTY मोड पूर्ण"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"सहकर्मी अनुरोध गरियो। TTY मोड HCO"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"सहकर्मी अनुरोध गरियो। TTY मोड VCO"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 4194eb1..c668abe 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Voicemailberichten"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Bellen via wifi"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"Simkaartstatus"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Meldingen met hoge prioriteit voor de simkaartstatus"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Door peer aangevraagde TTY-modus VOL"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Door peer aangevraagde TTY-modus HCO"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Door peer aangevraagde TTY-modus VCO"</string>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index df874bc..940fdc16 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"ଭଏସମେଲ୍‍ ମେସେଜ୍‍"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"ୱାଇ-ଫାଇ କଲିଙ୍ଗ"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"SIM ଷ୍ଟାଟସ୍"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"ଉଚ୍ଚ ପ୍ରାଥମିକତା SIM ସ୍ଥିତି"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"ପୀଆର୍‌ ଅନୁରୋଧ କରିଥିବା TTY ମୋଡ୍‍ FULL ଅଟେ"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"ପୀଅର୍‌ ଅନୁରୋଧ କରିଥିବା TTY ମୋଡ୍‍ HCO ଅଟେ"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"ପୀଅର୍‌ ଅନୁରୋଧ କରିଥିବା TTY ମୋଡ୍‍ VCO ଅଟେ"</string>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index 8245546..ddf2fc1 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"ਵੌਇਸਮੇਲ ਸੁਨੇਹੇ"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"ਵਾਈ-ਫਾਈ ਕਾਲਿੰਗ"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"ਸਿਮ ਅਵਸਥਾ"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"ਉੱਚ ਤਰਜੀਹੀ ਸਿਮ ਸਥਿਤੀ"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"ਪੀਅਰ ਨੇ TTY Mode FULL ਦੀ ਬੇਨਤੀ ਕੀਤੀ"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"ਪੀਅਰ ਨੇ TTY Mode HCO ਦੀ ਬੇਨਤੀ ਕੀਤੀ"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"ਪੀਅਰ ਨੇ TTY Mode VCO ਦੀ ਬੇਨਤੀ ਕੀਤੀ"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 054a456..69fc0e6 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -97,6 +97,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Wiadomości poczty głosowej"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Połączenia przez Wi-Fi"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"Stan karty SIM"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Stan karty SIM – wysoki priorytet"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Drugie urządzenie zażądało trybu „TTY pełny”"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Drugie urządzenie zażądało trybu „TTY HCO”"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Drugie urządzenie zażądało trybu „TTY VCO”"</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index 742fa81..f29ea42 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Mensagens do correio de voz"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Chamadas por Wi-Fi"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"Status do chip"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Status de prioridade alta do chip"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"TTD modo COMPLETO solicitado"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"TTD modo HCO solicitado"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"TTD modo VCO solicitado"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 85fb7fd..696f2f1 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Mensagens de correio de voz"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Chamadas Wi-Fi"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"Estado do SIM"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Estado do SIM de elevada prioridade"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"O par solicitou o modo COMPLETO de teletipo"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"O par solicitou o modo HCO de teletipo"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"O par solicitou o modo VCO de teletipo"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 742fa81..f29ea42 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Mensagens do correio de voz"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Chamadas por Wi-Fi"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"Status do chip"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Status de prioridade alta do chip"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"TTD modo COMPLETO solicitado"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"TTD modo HCO solicitado"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"TTD modo VCO solicitado"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 2f464e9..d80a7ba 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -96,6 +96,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Mesaje din mesageria vocală"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Apelare prin Wi-Fi"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"Starea cardului SIM"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Notificări de la SIM cu prioritate ridicată"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Cealaltă persoană a solicitat modul TTY cu setarea COMPLET"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Cealaltă persoană a solicitat modul TTY cu setarea HCO"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Cealaltă persoană a solicitat modul TTY cu setarea VCO"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index c4b61b2..410f4b9 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -97,6 +97,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Голосовые сообщения"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Звонки по Wi-Fi"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"Статус SIM-карты"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Важные уведомления SIM-карты"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"На устройстве абонента выбран режим телетайпа \"ВСЕ\""</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"На устройстве абонента выбран режим телетайпа HCO"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"На устройстве абонента выбран режим телетайпа VCO"</string>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index ddeb94b..a39cb6e 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"හඬ තැපැල් පණිවිඩ"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi ඇමතීම"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"SIM තත්ත්වය"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"ඉහළ ප්‍රමුඛතා SIM තත්ත්වය"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"සම ඉල්ලීම් කළ TTY ප්‍රකාරය පූර්ණයි"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"සම ඉල්ලීම් කළ TTY ප්‍රකාරය HCO"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"සම ඉල්ලීම් කළ TTY ප්‍රකාරය VCO"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 4d19308..d8a7561 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -97,6 +97,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Správy hlasovej schránky"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Volanie cez Wi‑Fi"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"Stav SIM karty"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Stav SIM karty: vysoká priorita"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Používateľ, s ktorým komunikujete, požiadal o režim FULL textového telefónu"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Používateľ, s ktorým komunikujete, požiadal o režim HCO textového telefónu"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Používateľ, s ktorým komunikujete, požiadal o režim VCO textového telefónu"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index b2b3109..7e12c2c 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -97,6 +97,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Sporočila v odzivniku"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Klicanje prek Wi-Fi-ja"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"Stanje kartice SIM"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Stanje kartice SIM z visoko stopnjo prednosti"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Enakovredna naprava je zahtevala način TTY FULL"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Enakovredna naprava je zahtevala način TTY HCO"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Enakovredna naprava je zahtevala način TTY VCO"</string>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index afed336..a958d1b 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Mesazhet e postës zanore"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Telefonata me Wi-Fi"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"Statusi i kartës SIM"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Statusi i kartës SIM me përparësi të lartë"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Homologu yt kërkoi modalitet \"TTY\" të plotë"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Homologu kërkoi modalitet \"TTY\" të llojit \"HCO\""</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Homologu yt kërkoi modalitet \"TTY\" të llojit \"VCO\""</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 110b31d..1adede3 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -96,6 +96,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Поруке говорне поште"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Позивање преко Wi-Fi мреже"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"Статус SIM-а"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Обавештења SIM картице са статусом „висок приоритет“"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Корисник захтева ПОТПУН режим TTY"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Корисник захтева ПРЕНОС ЗВУКА за режим TTY"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Корисник захтева ПРЕНОС ГЛАСА за режим TTY"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index bc1752e..434f36a 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Röstmeddelanden"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi-samtal"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"Status för SIM-kort"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"SIM-aviseringar med hög prioritet"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Peer-enheten begärde texttelefonläget FULL"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Peer-enheten begärde texttelefonläget HCO"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Peer-enheten begärde texttelefonläget VCO"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 92510ea..8f18ceb 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Ujumbe wa sauti"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Kupiga simu kupitia Wi-Fi"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"Hali ya SIM"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Hali ya SIM ya kipaumbele cha juu"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Hali ya TTY iliyoombwa na mtandao mwenza KAMILI"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Hali ya TTY iliyoombwa na mtandao mwenza HCO"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Hali ya TTY iliyoombwa na mtandao mwenza VCO"</string>
@@ -364,7 +365,7 @@
     <string name="permlab_enableCarMode" msgid="5684504058192921098">"Wezesha mtindo wa gari"</string>
     <string name="permdesc_enableCarMode" msgid="4853187425751419467">"Inaruhusu programu kuwawezesha mtindo wa gari."</string>
     <string name="permlab_killBackgroundProcesses" msgid="3914026687420177202">"funga programu zingine"</string>
-    <string name="permdesc_killBackgroundProcesses" msgid="4593353235959733119">"Inaruhusu programu kukamilisha michakato ya usuli ya programu nyingine. Hii inaweza kusababisha programu nyingine kukoma kufanyakazi."</string>
+    <string name="permdesc_killBackgroundProcesses" msgid="4593353235959733119">"Huruhusu programu kukamilisha michakato ya chinichini ya programu nyingine. Hii inaweza kusababisha programu nyingine kuacha kufanya kazi."</string>
     <string name="permlab_systemAlertWindow" msgid="7238805243128138690">"Programu hii inaweza kuonekana juu ya programu zingine"</string>
     <string name="permdesc_systemAlertWindow" msgid="2393776099672266188">"Programu hii inaweza kuonekana juu ya programu zingine au sehemu zingine za skrini. Hii huenda ikaathiri matumizi ya kawaida ya programu na kubadilisha jinsi ambavyo programu zingine zinavyoonekana."</string>
     <string name="permlab_runInBackground" msgid="7365290743781858803">"tumia chini chini"</string>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index ab3446f..d211e90 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"குரலஞ்சல் செய்திகள்"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"வைஃபை அழைப்பு"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"சிம் நிலை"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"அதிக முன்னுரிமையுடைய சிம்மின் நிலை"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"TTY Mode FULLஐ இணைச் செயல்பாடு கோரியது"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"TTY Mode HCOஐ இணைச் செயல்பாடு கோரியது"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"TTY Mode VCOஐ இணைச் செயல்பாடு கோரியது"</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 649e17c..e6a3daf 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"వాయిస్ మెయిల్ సందేశాలు"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi కాలింగ్"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"SIM స్థితి"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"అధిక ప్రాధాన్యత గల SIM స్థితి"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"అవతలి వారు FULL TTY మోడ్‌ని అభ్యర్థించారు"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"అవతలి వారు HCO TTY మోడ్‌ని అభ్యర్థించారు"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"అవతలి వారు VCO TTY మోడ్‌ని అభ్యర్థించారు"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 4e69430..045ea3e 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"ข้อความเสียง"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"การโทรผ่าน Wi-Fi"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"สถานะซิม"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"สถานะซิมลำดับความสำคัญสูง"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"อีกฝั่งหนึ่งขอโหมด TTY เป็น \"เต็ม\""</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"อีกฝั่งหนึ่งขอโหมด TTY เป็น \"HCO\""</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"อีกฝั่งหนึ่งขอโหมด TTY เป็น \"VCO\""</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 6843528..6dcc40c 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Mga mensahe sa voicemail"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Pagtawag gamit ang Wi-Fi"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"Status ng SIM"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"High priority na status ng SIM"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Hiniling ng peer ang TTY Mode FULL"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Hiniling ng peer ang TTY Mode HCO"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Hiniling ng peer ang TTY Mode VCO"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 3592df9..c0303ac 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Sesli mesajlar"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Kablosuz çağrı"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"SIM durumu"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Yüksek öncelikli SIM durumu"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Karşı taraf TTY Modunu TAM yaptı"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Karşı taraf TTY Modunu HCO yaptı"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Karşı taraf TTY Modunu VCO yaptı"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 347c81f..3437b51 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -97,6 +97,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Повідомлення голосової пошти"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Дзвінки через Wi-Fi"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"Статус SIM-карти"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Високопріоритетні сповіщення із SIM-карти"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Пристрій змінив режим TTY на FULL"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Пристрій змінив режим TTY на HCO"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Пристрій змінив режим TTY на VCO"</string>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index 3fd6fe7..83c3199 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"صوتی میل پیغامات"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"‏Wi-Fi کالنگ"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"‏SIM کا اسٹیٹس"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"‏اعلی ترجیحی SIM کی صورتحال"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"‏ہمسر نے TTY وضع مکمل کی درخواست کی"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"‏ہمسر نے TTY وضع HCO کی درخواست کی"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"‏ہمسر نے TTY وضع VCO کی درخواست کی"</string>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index 85ebe00..0425010 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Ovozli xabarlar"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi chaqiruv"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"SIM karta holati"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"SIM kartadagi muhim bildirishnomalar"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Teng huquqli ishtirokchi teletayp rejimini FULL (to‘liq) qilib o‘zgartirdi"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Teng huquqli ishtirokchi teletayp rejimini HCO (eshitadi, gapirolmaydi) qilib o‘zgartirdi"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Teng huquqli ishtirokchi teletayp rejimini VCO (gapiradi, eshitolmaydi) qilib o‘zgartirdi"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 78c4290..4f7b4fe 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Thư thoại"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Gọi qua Wi-Fi"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"Trạng thái SIM"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Trạng thái SIM có mức ưu tiên cao"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"TTY theo yêu cầu của thiết bị ngang hàng ở chế độ ĐẦY ĐỦ"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"TTY theo yêu cầu của thiết bị ngang hàng ở chế độ HCO"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"TTY theo yêu cầu của thiết bị ngang hàng ở chế độ VCO"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 9893a0f..765e1db 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"语音邮件"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"WLAN 通话"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"SIM 卡状态"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"高优先顺序 SIM 卡状态"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"对方请求使用“TTY 完整”模式"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"对方请求使用“TTY HCO”模式"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"对方请求使用“TTY VCO”模式"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 884772e..4124079 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"留言訊息"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi 通話"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"SIM 卡狀態"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"重要 SIM 卡狀態"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"對方曾要求 TTY 完整模式"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"對方曾要求 TTY 模式 (HCO)"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"對方曾要求 TTY 模式 (VCO)"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 580a1dc..1f7b3e2 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"語音留言"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi 通話"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"SIM 卡狀態"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"高優先順序 SIM 卡狀態"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"通訊對象要求使用 TTY 的 FULL 模式"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"通訊對象要求使用 TTY 的 HCO 模式"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"通訊對象要求使用 TTY 的 VCO 模式"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index c4f8823..c58c77c 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -95,6 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Imilayezo yevoyisimeyili"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Ukushaya kwe-Wi-Fi"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"Isimo se-SIM"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Isimo se-SIM esiphezulu kakhulu"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Umngani ucele imodi ye-TTY ephelele"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Umngani ucele imodi ye-TTY HCO"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Umngani ucele imodi ye-TTY VCO"</string>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index b34c422..fa4e085 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1301,6 +1301,9 @@
     <!-- Whether to use the strict phone number matcher in Kazakhstan. -->
     <bool name="config_use_strict_phone_number_comparation_for_kazakhstan">true</bool>
 
+    <!-- The character count of the minimum match for comparison phone numbers -->
+    <integer name="config_phonenumber_compare_min_match">7</integer>
+
     <!-- Display low battery warning when battery level dips to this value.
          Also, the battery stats are flushed to disk when we hit this level.  -->
     <integer name="config_criticalBatteryWarningLevel">5</integer>
@@ -3480,6 +3483,9 @@
     <!-- True if home app should be pinned via Pinner Service -->
     <bool name="config_pinnerHomeApp">false</bool>
 
+    <!-- True if assistant app should be pinned via Pinner Service -->
+    <bool name="config_pinnerAssistantApp">false</bool>
+
     <!-- List of files pinned by the Pinner Service with the apex boot image b/119800099 -->
     <string-array translatable="false" name="config_apexBootImagePinnerServiceFiles">
     </string-array>
@@ -4264,6 +4270,10 @@
     (default 2MB) -->
     <integer name="config_notificationStripRemoteViewSizeBytes">2000000</integer>
 
+    <!-- Contains a blacklist of apps that should not get pre-installed carrier app permission
+         grants, even if the UICC claims that the app should be privileged. See b/138150105 -->
+    <string-array name="config_restrictedPreinstalledCarrierApps" translatable="false"/>
+
     <!-- Sharesheet: define a max number of targets per application for new shortcuts-based direct share introduced in Q -->
     <integer name="config_maxShortcutTargetsPerApp">3</integer>
 
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 6653879..609659b 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -748,6 +748,8 @@
     <!-- Line spacing modifier for the message field of the harmful app dialog -->
     <item name="harmful_app_message_line_spacing_modifier" type="dimen">1.22</item>
 
+    <dimen name="seekbar_thumb_exclusion_max_size">48dp</dimen>
+
     <!-- chooser (sharesheet) spacing -->
     <dimen name="chooser_corner_radius">8dp</dimen>
     <dimen name="chooser_row_text_option_translate">25dp</dimen>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 036d959..2067735 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2927,6 +2927,7 @@
     <public type="attr" name="enforceStatusBarContrast" id="0x01010604" />
     <public type="attr" name="enforceNavigationBarContrast" id="0x01010605" />
     <public type="attr" name="identifier" id="0x01010606" />
+    <public type="attr" name="forceQueryable" id="0x01010608" />
 
     <!-- @hide @SystemApi -->
     <public type="drawable" name="ic_info" id="0x010800b4" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 40f20ab..21bb9d7 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -370,7 +370,7 @@
     <!-- If MMS discovers there isn't much space left on the device, it will show a toast with this message. [CHAR LIMIT=TOAST] -->
     <string name="low_memory" product="watch">Watch storage is full. Delete some files to free space.</string>
     <!-- If MMS discovers there isn't much space left on the device, it will show a toast with this message. [CHAR LIMIT=TOAST] -->
-    <string name="low_memory" product="tv">TV storage is full. Delete some files to free space.</string>
+    <string name="low_memory" product="tv">Android TV device storage is full. Delete some files to free space.</string>
     <!-- If MMS discovers there isn't much space left on the device, it will show a toast with this message. [CHAR LIMIT=TOAST] -->
     <string name="low_memory" product="default">Phone storage is full. Delete some files to free space.</string>
 
@@ -430,7 +430,7 @@
     <!-- Title for the Phone Options dialog to lock the screen, turn off the phone etc. -->
     <string name="power_dialog" product="tablet">Tablet options</string>
     <!-- Title for the Phone Options dialog to lock the screen, turn off the phone etc. -->
-    <string name="power_dialog" product="tv">TV options</string>
+    <string name="power_dialog" product="tv">Android TV options</string>
     <!-- Title for the Phone Options dialog to lock the screen, turn off the phone etc. -->
     <string name="power_dialog" product="default">Phone options</string>
     <!-- Button to turn on silent mode, within the Phone Options dialog -->
@@ -468,7 +468,7 @@
     <string name="shutdown_confirm" product="tablet">Your tablet will shut down.</string>
     <!-- Shutdown Confirmation Dialog.  When the user chooses to power off the TV, there will
          be a confirmation dialog.  This is the message. -->
-    <string name="shutdown_confirm" product="tv">Your TV will shut down.</string>
+    <string name="shutdown_confirm" product="tv">Your Android TV device will shut down.</string>
     <!-- Shutdown Confirmation Dialog.  When the user chooses to power off the watch, there will
          be a confirmation dialog.  This is the message. -->
     <string name="shutdown_confirm" product="watch">Your watch will shut down.</string>
@@ -505,7 +505,7 @@
     <!-- Title of the Global Actions Dialog -->
     <string name="global_actions" product="tablet">Tablet options</string>
     <!-- Title of the Global Actions Dialog -->
-    <string name="global_actions" product="tv">TV options</string>
+    <string name="global_actions" product="tv">Android TV options</string>
     <!-- Title of the Global Actions Dialog -->
     <string name="global_actions" product="default">Phone options</string>
 
@@ -916,7 +916,7 @@
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_readSms" product="tablet">This app can read all SMS (text) messages stored on your tablet.</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_readSms" product="tv">This app can read all SMS (text) messages stored on your TV.</string>
+    <string name="permdesc_readSms" product="tv">This app can read all SMS (text) messages stored on your Android TV device.</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_readSms" product="default">This app can read all SMS (text) messages stored on your phone.</string>
 
@@ -979,7 +979,7 @@
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_persistentActivity" product="tablet">Allows the app to make parts of itself persistent in memory.  This can limit memory available to other apps slowing down the tablet.</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_persistentActivity" product="tv">Allows the app to make parts of itself persistent in memory.  This can limit memory available to other apps slowing down the TV.</string>
+    <string name="permdesc_persistentActivity" product="tv">Allows the app to make parts of itself persistent in memory.  This can limit memory available to other apps slowing down your Android TV device.</string>
     <string name="permdesc_persistentActivity" product="default">Allows the app to make parts of itself persistent in memory.  This can limit memory available to other apps slowing down the phone.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
@@ -1009,8 +1009,8 @@
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_receiveBootCompleted" product="tv">Allows the app to
         have itself started as soon as the system has finished booting.
-        This can make it take longer to start the TV and allow the
-        app to slow down the overall tablet by always running.</string>
+        This can make it take longer to start your Android TV device and allow the
+        app to slow down the overall device by always running.</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_receiveBootCompleted" product="default">Allows the app to
         have itself started as soon as the system has finished booting.
@@ -1027,7 +1027,7 @@
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_broadcastSticky" product="tv">Allows the app to
     send sticky broadcasts, which remain after the broadcast ends. Excessive use
-    may make the TV slow or unstable by causing it to use too much memory.
+    may make your Android TV device slow or unstable by causing it to use too much memory.
     </string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_broadcastSticky" product="default">Allows the app to
@@ -1046,7 +1046,7 @@
       knowledge.</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_readContacts" product="tv">Allows the app to read
-      data about your contacts stored on your TV, including the frequency
+      data about your contacts stored on your Android TV device, including the frequency
       with which you\'ve called, emailed, or communicated in other ways with
       specific individuals. This permission allows apps to save your contact
       data, and malicious apps may share contact data without your
@@ -1069,7 +1069,7 @@
       data.</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_writeContacts" product="tv">Allows the app to
-      modify the data about your contacts stored on your TV, including the
+      modify the data about your contacts stored on your Android TV device, including the
       frequency with which you\'ve called, emailed, or communicated in other ways
       with specific contacts. This permission allows apps to delete contact
       data.</string>
@@ -1091,7 +1091,7 @@
     <string name="permdesc_writeCallLog" product="tablet">Allows the app to modify your tablet\'s call log, including data about incoming and outgoing calls.
         Malicious apps may use this to erase or modify your call log.</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_writeCallLog" product="tv">Allows the app to modify your TV\'s call log, including data about incoming and outgoing calls.
+    <string name="permdesc_writeCallLog" product="tv">Allows the app to modify your Android TV device\'s call log, including data about incoming and outgoing calls.
         Malicious apps may use this to erase or modify your call log.</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_writeCallLog" product="default">Allows the app to modify your phone\'s call log, including data about incoming and outgoing calls.
@@ -1109,7 +1109,7 @@
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_readCalendar" product="tablet">This app can read all calendar events stored on your tablet and share or save your calendar data.</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_readCalendar" product="tv">This app can read all calendar events stored on your TV and share or save your calendar data.</string>
+    <string name="permdesc_readCalendar" product="tv">This app can read all calendar events stored on your Android TV device and share or save your calendar data.</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_readCalendar" product="default">This app can read all calendar events stored on your phone and share or save your calendar data.</string>
 
@@ -1118,7 +1118,7 @@
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_writeCalendar" product="tablet">This app can add, remove, or change calendar events on your tablet. This app can send messages that may appear to come from calendar owners, or change events without notifying their owners.</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_writeCalendar" product="tv">This app can add, remove, or change calendar events on your TV. This app can send messages that may appear to come from calendar owners, or change events without notifying their owners.</string>
+    <string name="permdesc_writeCalendar" product="tv">This app can add, remove, or change calendar events on your Android TV device. This app can send messages that may appear to come from calendar owners, or change events without notifying their owners.</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_writeCalendar" product="default">This app can add, remove, or change calendar events on your phone. This app can send messages that may appear to come from calendar owners, or change events without notifying their owners.</string>
 
@@ -1139,7 +1139,7 @@
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_accessCoarseLocation" product="tablet">This app can get your location based on network sources such as cell towers and Wi-Fi networks, but only when when the app is in the foreground. These location services must be turned on and available on your tablet for the app to be able to use them.</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_accessCoarseLocation" product="tv">This app can get your location based on network sources such as cell towers and Wi-Fi networks, but only when when the app is in the foreground. These location services must be turned on and available on your TV for the app to be able to use them.</string>
+    <string name="permdesc_accessCoarseLocation" product="tv">This app can get your location based on network sources such as cell towers and Wi-Fi networks, but only when when the app is in the foreground. These location services must be turned on and available on your Android TV device for the app to be able to use them.</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_accessCoarseLocation" product="default">This app can get your location based on network sources such as cell towers and Wi-Fi networks, but only when the app is in the foreground. These location services must be turned on and available on your phone for the app to be able to use them.</string>
 
@@ -1236,13 +1236,13 @@
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_wakeLock" product="tablet">prevent tablet from sleeping</string>
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_wakeLock" product="tv">prevent TV from sleeping</string>
+    <string name="permlab_wakeLock" product="tv">prevent your Android TV device from sleeping</string>
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_wakeLock" product="default">prevent phone from sleeping</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_wakeLock" product="tablet">Allows the app to prevent the tablet from going to sleep.</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_wakeLock" product="tv">Allows the app to prevent the TV from going to sleep.</string>
+    <string name="permdesc_wakeLock" product="tv">Allows the app to prevent your Android TV device from going to sleep.</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_wakeLock" product="default">Allows the app to prevent the phone from going to sleep.</string>
 
@@ -1251,7 +1251,7 @@
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_transmitIr" product="tablet">Allows the app to use the tablet\'s infrared transmitter.</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_transmitIr" product="tv">Allows the app to use the TV\'s infrared transmitter.</string>
+    <string name="permdesc_transmitIr" product="tv">Allows the app to use your Android TV device\'s infrared transmitter.</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_transmitIr" product="default">Allows the app to use the phone\'s infrared transmitter.</string>
 
@@ -1270,7 +1270,7 @@
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_setTimeZone" product="tablet">Allows the app to change the tablet\'s time zone.</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_setTimeZone" product="tv">Allows the app to change the TV\'s time zone.</string>
+    <string name="permdesc_setTimeZone" product="tv">Allows the app to change your Android TV device\'s time zone.</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_setTimeZone" product="default">Allows the app to change the phone\'s time zone.</string>
 
@@ -1282,7 +1282,7 @@
       created by applications you have installed.</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_getAccounts" product="tv">Allows the app to get
-      the list of accounts known by the TV.  This may include any accounts
+      the list of accounts known by your Android TV device.  This may include any accounts
       created by applications you have installed.</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_getAccounts" product="default">Allows the app to get
@@ -1337,7 +1337,7 @@
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_changeWifiMulticastState" product="tv">Allows the app to receive
       packets sent to all devices on a Wi-Fi network using multicast addresses,
-      not just your TV.  It uses more power than the non-multicast mode.</string>
+      not just your Android TV device.  It uses more power than the non-multicast mode.</string>
     <string name="permdesc_changeWifiMulticastState" product="default">Allows the app to receive
       packets sent to all devices on a Wi-Fi network using multicast addresses,
       not just your phone.  It uses more power than the non-multicast mode.</string>
@@ -1350,7 +1350,7 @@
       devices.</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_bluetoothAdmin" product="tv">Allows the app to
-      configure the local Bluetooth TV, and to discover and pair with remote
+      configure Bluetooth on your Android TV device, and to discover and pair with remote
       devices.</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_bluetoothAdmin" product="default">Allows the app to configure
@@ -1365,7 +1365,7 @@
     <string name="permdesc_changeWimaxState" product="tablet">Allows the app to
       connect the tablet to and disconnect the tablet from WiMAX networks.</string>
     <string name="permdesc_changeWimaxState" product="tv">Allows the app to
-      connect the TV to and disconnect the TV from WiMAX networks.</string>
+      connect your Android TV device to and disconnect your Android TV device from WiMAX networks.</string>
     <string name="permdesc_changeWimaxState" product="default">Allows the app to
       connect the phone to and disconnect the phone from WiMAX networks.</string>
 
@@ -1377,7 +1377,7 @@
       connections with paired devices.</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_bluetooth" product="tv">Allows the app to view the
-      configuration of Bluetooth on the TV, and to make and accept
+      configuration of Bluetooth on your Android TV device, and to make and accept
       connections with paired devices.</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_bluetooth" product="default">Allows the app to view the
@@ -1753,8 +1753,8 @@
     typed when unlocking the screen, and lock the tablet or erase all the tablet\'s
     data if too many incorrect passwords are typed.</string>
     <!-- Description of policy access to watch user login attempts -->
-    <string name="policydesc_watchLogin" product="TV">Monitor the number of incorrect passwords
-    typed when unlocking the screen, and lock the TV or erase all the TV\'s
+    <string name="policydesc_watchLogin" product="tv">Monitor the number of incorrect passwords
+    typed when unlocking the screen, and lock your Android TV device or erase all your Android TV device\'s
     data if too many incorrect passwords are typed.</string>
     <!-- Description of policy access to watch user login attempts -->
     <string name="policydesc_watchLogin" product="default">Monitor the number of incorrect passwords
@@ -1763,8 +1763,8 @@
     <string name="policydesc_watchLogin_secondaryUser" product="tablet">Monitor the number of incorrect passwords
     typed when unlocking the screen, and lock the tablet or erase all this user\'s data
     if too many incorrect passwords are typed.</string>
-    <string name="policydesc_watchLogin_secondaryUser" product="TV">Monitor the number of incorrect passwords
-    typed when unlocking the screen, and lock the TV or erase all this user\'s data
+    <string name="policydesc_watchLogin_secondaryUser" product="tv">Monitor the number of incorrect passwords
+    typed when unlocking the screen, and lock your Android TV device or erase all this user\'s data
     if too many incorrect passwords are typed.</string>
     <string name="policydesc_watchLogin_secondaryUser" product="default">Monitor the number of incorrect passwords
     typed when unlocking the screen, and lock the phone or erase all this user\'s data
@@ -1782,7 +1782,7 @@
     <!-- Description of policy access to wipe the user's data -->
     <string name="policydesc_wipeData" product="tablet">Erase the tablet\'s data without warning by performing a factory data reset.</string>
     <!-- Description of policy access to wipe the user's data -->
-    <string name="policydesc_wipeData" product="tv">Erase the TV\'s data without warning by performing a factory data reset.</string>
+    <string name="policydesc_wipeData" product="tv">Erase your Android TV device\'s data without warning by performing a factory data reset.</string>
     <!-- Description of policy access to wipe the user's data -->
     <string name="policydesc_wipeData" product="default">Erase the phone\'s data without warning by performing a factory data reset.</string>
     <!-- Title of policy access to wipe secondary user's data -->
@@ -1790,7 +1790,7 @@
     <!-- Description of policy access to wipe the user's data -->
     <string name="policydesc_wipeData_secondaryUser" product="tablet">Erase this user\'s data on this tablet without warning.</string>
     <!-- Description of policy access to wipe the user's data -->
-    <string name="policydesc_wipeData_secondaryUser" product="tv">Erase this user\'s data on this TV without warning.</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tv">Erase this user\'s data on this Android TV device without warning.</string>
     <!-- Description of policy access to wipe the user's data -->
     <string name="policydesc_wipeData_secondaryUser" product="default">Erase this user\'s data on this phone without warning.</string>
     <!-- Title of policy access to set global proxy -->
@@ -2103,7 +2103,7 @@
     <!-- Shown in the lock screen when there is no SIM card. -->
     <string name="lockscreen_missing_sim_message" product="tablet">No SIM card in tablet.</string>
     <!-- Shown in the lock screen when there is no SIM card. -->
-    <string name="lockscreen_missing_sim_message" product="tv">No SIM card in TV.</string>
+    <string name="lockscreen_missing_sim_message" product="tv">No SIM card in your Android TV device.</string>
     <!-- Shown in the lock screen when there is no SIM card. -->
     <string name="lockscreen_missing_sim_message" product="default">No SIM card in phone.</string>
     <!-- Shown in the lock screen to ask the user to insert a SIM card. -->
@@ -2188,7 +2188,7 @@
     <string name="lockscreen_failed_attempts_almost_glogin" product="tv">
         You have incorrectly drawn your unlock pattern <xliff:g id="number">%1$d</xliff:g> times.
        After <xliff:g id="number">%2$d</xliff:g> more unsuccessful attempts,
-       you will be asked to unlock your TV using your Google signin.\n\n
+       you will be asked to unlock your Android TV device using your Google signin.\n\n
        Try again in <xliff:g id="number">%3$d</xliff:g> seconds.
     </string>
 
@@ -2212,9 +2212,9 @@
     <!-- For the unlock screen, informational message shown in dialog when user is almost at the limit
          where the device will be wiped. -->
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="tv">
-       You have incorrectly attempted to unlock the TV <xliff:g id="number">%1$d</xliff:g> times.
+       You have incorrectly attempted to unlock your Android TV device <xliff:g id="number">%1$d</xliff:g> times.
        After <xliff:g id="number">%2$d</xliff:g> more unsuccessful attempts,
-       the TV will be reset to factory default and all user data will be lost.
+       your Android TV device will be reset to factory default and all user data will be lost.
     </string>
 
     <!-- For the unlock screen, informational message shown in dialog when user is almost at the limit
@@ -2235,8 +2235,8 @@
     <!-- For the unlock screen, informational message shown in dialog when user has exceeded the
         maximum attempts and the device will now be wiped -->
     <string name="lockscreen_failed_attempts_now_wiping" product="tv">
-       You have incorrectly attempted to unlock the TV <xliff:g id="number">%d</xliff:g> times.
-       The TV will now be reset to factory default.
+       You have incorrectly attempted to unlock your Android TV device <xliff:g id="number">%d</xliff:g> times.
+       Your Android TV device will now be reset to factory default.
     </string>
 
     <!-- For the unlock screen, informational message shown in dialog when user has exceeded the
@@ -2603,7 +2603,7 @@
     <!-- Description of an application permission, listed so the user can choose whether
         they want to allow the application to do this. -->
     <string name="permdesc_writeHistoryBookmarks" product="tv">Allows the
-        app to modify the Browser\'s history or bookmarks stored on your TV.
+        app to modify the Browser\'s history or bookmarks stored on your Android TV device.
         This may allow the app to erase or modify Browser data.  Note: this
         permission may note be enforced by third-party browsers or other
         applications with web browsing capabilities.</string>
@@ -3506,7 +3506,7 @@
     <string name="wifi_p2p_show_pin_message">PIN: </string>
 
     <string name="wifi_p2p_frequency_conflict_message" product="tablet">The tablet will temporarily disconnect from Wi-Fi while it\'s connected to <xliff:g id="device_name">%1$s</xliff:g></string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tv">The TV will temporarily disconnect from Wi-Fi while it\'s connected to <xliff:g id="device_name">%1$s</xliff:g></string>
+    <string name="wifi_p2p_frequency_conflict_message" product="tv">Your Android TV device will temporarily disconnect from Wi-Fi while it\'s connected to <xliff:g id="device_name">%1$s</xliff:g></string>
     <string name="wifi_p2p_frequency_conflict_message" product="default">The phone will temporarily disconnect from Wi-Fi while it\'s connected to <xliff:g id="device_name">%1$s</xliff:g></string>
 
     <!-- Name of the dialog that lets the user choose an accented character to insert -->
@@ -4404,9 +4404,9 @@
     </string>
     <!-- Message shown when user is almost at the limit of password attempts where the device will be wiped. -->
     <string name="kg_failed_attempts_almost_at_wipe" product="tv">
-       You have incorrectly attempted to unlock the TV <xliff:g id="number">%1$d</xliff:g> times.
+       You have incorrectly attempted to unlock your Android TV device <xliff:g id="number">%1$d</xliff:g> times.
        After <xliff:g id="number">%2$d</xliff:g> more unsuccessful attempts,
-       the TV will be reset to factory default and all user data will be lost.
+       your Android TV device will be reset to factory default and all user data will be lost.
     </string>
     <!-- Message shown when user is almost at the limit of password attempts where the device will be wiped. -->
     <string name="kg_failed_attempts_almost_at_wipe" product="default">
@@ -4421,8 +4421,8 @@
     </string>
     <!-- Message shown in dialog when user has exceeded the maximum attempts and the device will now be wiped -->
     <string name="kg_failed_attempts_now_wiping" product="tv">
-       You have incorrectly attempted to unlock the TV <xliff:g id="number">%d</xliff:g> times.
-       The TV will now be reset to factory default.
+       You have incorrectly attempted to unlock your Android TV device <xliff:g id="number">%d</xliff:g> times.
+       Your Android TV device will now be reset to factory default.
     </string>
     <!-- Message shown in dialog when user has exceeded the maximum attempts and the device will now be wiped -->
     <string name="kg_failed_attempts_now_wiping" product="default">
@@ -4442,7 +4442,7 @@
     <string name="kg_failed_attempts_almost_at_login" product="tv">
        You have incorrectly drawn your unlock pattern <xliff:g id="number">%1$d</xliff:g> times.
        After <xliff:g id="number">%2$d</xliff:g> more unsuccessful attempts,
-       you will be asked to unlock your TV using an email account.\n\n
+       you will be asked to unlock your Android TV device using an email account.\n\n
        Try again in <xliff:g id="number">%3$d</xliff:g> seconds.
     </string>
     <!-- Message shown in dialog when user is almost at the limit where they will be
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index ac32c95..f7ae453 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -320,6 +320,7 @@
   <java-symbol type="bool" name="config_use_strict_phone_number_comparation" />
   <java-symbol type="bool" name="config_use_strict_phone_number_comparation_for_russia" />
   <java-symbol type="bool" name="config_use_strict_phone_number_comparation_for_kazakhstan" />
+  <java-symbol type="integer" name="config_phonenumber_compare_min_match" />
   <java-symbol type="bool" name="config_single_volume" />
   <java-symbol type="bool" name="config_voice_capable" />
   <java-symbol type="bool" name="config_requireCallCapableAccountForHandle" />
@@ -3117,6 +3118,7 @@
   <java-symbol type="array" name="config_defaultPinnerServiceFiles" />
   <java-symbol type="bool" name="config_pinnerCameraApp" />
   <java-symbol type="bool" name="config_pinnerHomeApp" />
+  <java-symbol type="bool" name="config_pinnerAssistantApp" />
   <java-symbol type="array" name="config_apexBootImagePinnerServiceFiles" />
 
   <java-symbol type="string" name="config_doubleTouchGestureEnableFile" />
@@ -3824,6 +3826,7 @@
   <java-symbol type="color" name="chooser_gradient_highlight" />
   <java-symbol type="drawable" name="chooser_direct_share_label_placeholder" />
   <java-symbol type="dimen" name="chooser_direct_share_label_placeholder_max_width" />
+  <java-symbol type="dimen" name="seekbar_thumb_exclusion_max_size" />
   <java-symbol type="layout" name="chooser_az_label_row" />
   <java-symbol type="string" name="chooser_all_apps_button_label" />
   <java-symbol type="anim" name="resolver_launch_anim" />
@@ -3833,6 +3836,7 @@
 
   <java-symbol type="string" name="config_defaultSupervisionProfileOwnerComponent" />
   <java-symbol type="bool" name="config_inflateSignalStrength" />
+  <java-symbol type="array" name="config_restrictedPreinstalledCarrierApps" />
 
   <java-symbol type="drawable" name="android_logotype" />
   <java-symbol type="layout" name="platlogo_layout" />
diff --git a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/StartProgramListUpdatesFanoutTest.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/StartProgramListUpdatesFanoutTest.java
index 6e65df1..3d9a1d9 100644
--- a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/StartProgramListUpdatesFanoutTest.java
+++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/StartProgramListUpdatesFanoutTest.java
@@ -250,6 +250,29 @@
         verify(mHalTunerSessionMock).stopProgramListUpdates();
     }
 
+    @Test
+    public void testNullAidlFilter() throws RemoteException {
+        openAidlClients(1);
+        mTunerSessions[0].startProgramListUpdates(null);
+        verify(mHalTunerSessionMock, times(1)).startProgramListUpdates(any());
+
+        // Verify the AIDL client receives all types of updates (e.g. a new program, an update to
+        // that program, and a category).
+        updateHalProgramInfo(true, Arrays.asList(mAmFmInfo, mRdsInfo), null);
+        verifyAidlClientReceivedChunk(mAidlTunerCallbackMocks[0], true, Arrays.asList(
+                mAmFmInfo, mRdsInfo), null);
+        updateHalProgramInfo(false, Arrays.asList(mModifiedAmFmInfo), null);
+        verifyAidlClientReceivedChunk(mAidlTunerCallbackMocks[0], false,
+                Arrays.asList(mModifiedAmFmInfo), null);
+        updateHalProgramInfo(false, Arrays.asList(mDabEnsembleInfo), null);
+        verifyAidlClientReceivedChunk(mAidlTunerCallbackMocks[0], false,
+                Arrays.asList(mDabEnsembleInfo), null);
+
+        // Verify closing the AIDL session also stops HAL updates.
+        mTunerSessions[0].close();
+        verify(mHalTunerSessionMock).stopProgramListUpdates();
+    }
+
     private void openAidlClients(int numClients) throws RemoteException {
         mAidlTunerCallbackMocks = new android.hardware.radio.ITunerCallback[numClients];
         mTunerSessions = new TunerSession[numClients];
diff --git a/core/tests/coretests/Android.bp b/core/tests/coretests/Android.bp
index 833c734..1670d49 100644
--- a/core/tests/coretests/Android.bp
+++ b/core/tests/coretests/Android.bp
@@ -58,6 +58,8 @@
 
     resource_dirs: ["res"],
     resource_zips: [":FrameworksCoreTests_apks_as_resources"],
+
+    data: [":BstatsTestApp"],
 }
 
 // Rules to copy all the test apks to the intermediate raw resource directory
diff --git a/core/tests/coretests/BstatsTestApp/Android.bp b/core/tests/coretests/BstatsTestApp/Android.bp
index 424c71a..a89d728 100644
--- a/core/tests/coretests/BstatsTestApp/Android.bp
+++ b/core/tests/coretests/BstatsTestApp/Android.bp
@@ -15,10 +15,6 @@
 android_test_helper_app {
     name: "BstatsTestApp",
 
-    test_suites: [
-        "device-tests",
-    ],
-
     static_libs: ["coretests-aidl"],
 
     srcs: ["**/*.java"],
diff --git a/core/tests/coretests/src/android/content/ContentProviderOperationTest.java b/core/tests/coretests/src/android/content/ContentProviderOperationTest.java
index b142761..b1ce33a 100644
--- a/core/tests/coretests/src/android/content/ContentProviderOperationTest.java
+++ b/core/tests/coretests/src/android/content/ContentProviderOperationTest.java
@@ -26,11 +26,6 @@
 
 import junit.framework.TestCase;
 
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Field;
-import java.lang.reflect.InvocationTargetException;
-import java.util.HashMap;
-import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
 
@@ -39,11 +34,6 @@
     private final static Uri sTestUri1 = Uri.parse("content://authority/blah");
     private final static ContentValues sTestValues1;
 
-    private final static Class<ContentProviderOperation.Builder> CLASS_BUILDER =
-            ContentProviderOperation.Builder.class;
-    private final static Class<ContentProviderOperation> CLASS_OPERATION =
-            ContentProviderOperation.class;
-
     static {
         sTestValues1 = new ContentValues();
         sTestValues1.put("a", 1);
@@ -279,221 +269,6 @@
         assertEquals("a,103,101,b,102", TextUtils.join(",", s2));
     }
 
-    public void testParcelingOperation() throws NoSuchFieldException, IllegalAccessException,
-            NoSuchMethodException, InvocationTargetException, InstantiationException {
-        Parcel parcel = Parcel.obtain();
-        ContentProviderOperation op1;
-        ContentProviderOperation op2;
-
-        HashMap<Integer, Integer> selArgsBackRef = new HashMap<Integer, Integer>();
-        selArgsBackRef.put(1, 2);
-        selArgsBackRef.put(3, 4);
-
-        ContentValues values = new ContentValues();
-        values.put("v1", "val1");
-        values.put("v2", "43");
-
-        ContentValues valuesBackRef = new ContentValues();
-        values.put("v3", "val3");
-        values.put("v4", "44");
-
-        try {
-            ContentProviderOperation.Builder builder = ContentProviderOperation.newInsert(
-                    Uri.parse("content://goo/bar"));
-
-            builderSetExpectedCount(builder, 42);
-            builderSetSelection(builder, "selection");
-            builderSetSelectionArgs(builder, new String[]{"a", "b"});
-            builderSetSelectionArgsBackReferences(builder, selArgsBackRef);
-            builderSetValues(builder, values);
-            builderSetValuesBackReferences(builder, valuesBackRef);
-
-            op1 = newOperationFromBuilder(builder);
-            op1.writeToParcel(parcel, 0);
-            parcel.setDataPosition(0);
-            op2 = ContentProviderOperation.CREATOR.createFromParcel(parcel);
-
-            assertEquals(ContentProviderOperation.TYPE_INSERT, operationGetType(op2));
-            assertEquals("content://goo/bar", operationGetUri(op2).toString());
-            assertEquals(Integer.valueOf(42), operationGetExpectedCount(op2));
-            assertEquals("selection", operationGetSelection(op2));
-            assertEquals(2, operationGetSelectionArgs(op2).length);
-            assertEquals("a", operationGetSelectionArgs(op2)[0]);
-            assertEquals("b", operationGetSelectionArgs(op2)[1]);
-            assertEquals(values, operationGetValues(op2));
-            assertEquals(valuesBackRef, operationGetValuesBackReferences(op2));
-            assertEquals(2, operationGetSelectionArgsBackReferences(op2).size());
-            assertEquals(Integer.valueOf(2), operationGetSelectionArgsBackReferences(op2).get(1));
-            assertEquals(Integer.valueOf(4), operationGetSelectionArgsBackReferences(op2).get(3));
-        } finally {
-            parcel.recycle();
-        }
-
-        try {
-            ContentProviderOperation.Builder builder = ContentProviderOperation.newUpdate(
-                    Uri.parse("content://goo/bar"));
-
-            builderSetSelectionArgsBackReferences(builder, selArgsBackRef);
-
-            op1 = newOperationFromBuilder(builder);
-            op1.writeToParcel(parcel, 0);
-            parcel.setDataPosition(0);
-            op2 = ContentProviderOperation.CREATOR.createFromParcel(parcel);
-            assertEquals(ContentProviderOperation.TYPE_UPDATE, operationGetType(op2));
-            assertEquals("content://goo/bar", operationGetUri(op2).toString());
-            assertNull(operationGetExpectedCount(op2));
-            assertNull(operationGetSelection(op2));
-            assertNull(operationGetSelectionArgs(op2));
-            assertNull(operationGetValues(op2));
-            assertNull(operationGetValuesBackReferences(op2));
-            assertEquals(2, operationGetSelectionArgsBackReferences(op2).size());
-            assertEquals(Integer.valueOf(2), operationGetSelectionArgsBackReferences(op2).get(1));
-            assertEquals(Integer.valueOf(4), operationGetSelectionArgsBackReferences(op2).get(3));
-        } finally {
-            parcel.recycle();
-        }
-
-        try {
-            ContentProviderOperation.Builder builder = ContentProviderOperation.newDelete(
-                    Uri.parse("content://goo/bar"));
-
-            op1 = newOperationFromBuilder(builder);
-            op1.writeToParcel(parcel, 0);
-            parcel.setDataPosition(0);
-            op2 = ContentProviderOperation.CREATOR.createFromParcel(parcel);
-            assertEquals(ContentProviderOperation.TYPE_DELETE, operationGetType(op2));
-            assertEquals("content://goo/bar", operationGetUri(op2).toString());
-            assertNull(operationGetExpectedCount(op2));
-            assertNull(operationGetSelection(op2));
-            assertNull(operationGetSelectionArgs(op2));
-            assertNull(operationGetValues(op2));
-            assertNull(operationGetValuesBackReferences(op2));
-            assertNull(operationGetSelectionArgsBackReferences(op2));
-        } finally {
-            parcel.recycle();
-        }
-    }
-
-    private static ContentProviderOperation newOperationFromBuilder(
-            ContentProviderOperation.Builder builder)
-            throws NoSuchMethodException, InstantiationException, IllegalAccessException,
-            InvocationTargetException {
-        final Constructor constructor = CLASS_OPERATION.getDeclaredConstructor(CLASS_BUILDER);
-        constructor.setAccessible(true);
-        return (ContentProviderOperation) constructor.newInstance(builder);
-    }
-
-    private void builderSetSelectionArgsBackReferences(
-            ContentProviderOperation.Builder builder, HashMap<Integer, Integer> selArgsBackRef)
-            throws NoSuchFieldException, IllegalAccessException {
-        Field field;
-        field = CLASS_BUILDER.getDeclaredField("mSelectionArgsBackReferences");
-        field.setAccessible(true);
-        field.set(builder, selArgsBackRef);
-    }
-
-    private void builderSetValuesBackReferences(
-            ContentProviderOperation.Builder builder, ContentValues valuesBackReferences)
-            throws NoSuchFieldException, IllegalAccessException {
-        Field field;
-        field = CLASS_BUILDER.getDeclaredField("mValuesBackReferences");
-        field.setAccessible(true);
-        field.set(builder, valuesBackReferences);
-    }
-
-    private void builderSetSelection(
-            ContentProviderOperation.Builder builder, String selection)
-            throws NoSuchFieldException, IllegalAccessException {
-        Field field;
-        field = CLASS_BUILDER.getDeclaredField("mSelection");
-        field.setAccessible(true);
-        field.set(builder, selection);
-    }
-
-    private void builderSetSelectionArgs(
-            ContentProviderOperation.Builder builder, String[] selArgs)
-            throws NoSuchFieldException, IllegalAccessException {
-        Field field;
-        field = CLASS_BUILDER.getDeclaredField("mSelectionArgs");
-        field.setAccessible(true);
-        field.set(builder, selArgs);
-    }
-
-    private void builderSetValues(
-            ContentProviderOperation.Builder builder, ContentValues values)
-            throws NoSuchFieldException, IllegalAccessException {
-        Field field;
-        field = CLASS_BUILDER.getDeclaredField("mValues");
-        field.setAccessible(true);
-        field.set(builder, values);
-    }
-
-    private void builderSetExpectedCount(
-            ContentProviderOperation.Builder builder, Integer expectedCount)
-            throws NoSuchFieldException, IllegalAccessException {
-        Field field;
-        field = CLASS_BUILDER.getDeclaredField("mExpectedCount");
-        field.setAccessible(true);
-        field.set(builder, expectedCount);
-    }
-
-    private int operationGetType(ContentProviderOperation operation)
-            throws NoSuchFieldException, IllegalAccessException {
-        final Field field = CLASS_OPERATION.getDeclaredField("mType");
-        field.setAccessible(true);
-        return field.getInt(operation);
-    }
-
-    private Uri operationGetUri(ContentProviderOperation operation)
-            throws NoSuchFieldException, IllegalAccessException {
-        final Field field = CLASS_OPERATION.getDeclaredField("mUri");
-        field.setAccessible(true);
-        return (Uri) field.get(operation);
-    }
-
-    private String operationGetSelection(ContentProviderOperation operation)
-            throws NoSuchFieldException, IllegalAccessException {
-        final Field field = CLASS_OPERATION.getDeclaredField("mSelection");
-        field.setAccessible(true);
-        return (String) field.get(operation);
-    }
-
-    private String[] operationGetSelectionArgs(ContentProviderOperation operation)
-            throws NoSuchFieldException, IllegalAccessException {
-        final Field field = CLASS_OPERATION.getDeclaredField("mSelectionArgs");
-        field.setAccessible(true);
-        return (String[]) field.get(operation);
-    }
-
-    private ContentValues operationGetValues(ContentProviderOperation operation)
-            throws NoSuchFieldException, IllegalAccessException {
-        final Field field = CLASS_OPERATION.getDeclaredField("mValues");
-        field.setAccessible(true);
-        return (ContentValues) field.get(operation);
-    }
-
-    private Integer operationGetExpectedCount(ContentProviderOperation operation)
-            throws NoSuchFieldException, IllegalAccessException {
-        final Field field = CLASS_OPERATION.getDeclaredField("mExpectedCount");
-        field.setAccessible(true);
-        return (Integer) field.get(operation);
-    }
-
-    private ContentValues operationGetValuesBackReferences(ContentProviderOperation operation)
-            throws NoSuchFieldException, IllegalAccessException {
-        final Field field = CLASS_OPERATION.getDeclaredField("mValuesBackReferences");
-        field.setAccessible(true);
-        return (ContentValues) field.get(operation);
-    }
-
-    private Map<Integer, Integer> operationGetSelectionArgsBackReferences(
-            ContentProviderOperation operation)
-            throws NoSuchFieldException, IllegalAccessException {
-        final Field field = CLASS_OPERATION.getDeclaredField("mSelectionArgsBackReferences");
-        field.setAccessible(true);
-        return (Map<Integer, Integer>) field.get(operation);
-    }
-
     public void testParcelingResult() {
         Parcel parcel = Parcel.obtain();
         ContentProviderResult result1;
diff --git a/core/tests/coretests/src/android/content/pm/PackageParserTest.java b/core/tests/coretests/src/android/content/pm/PackageParserTest.java
index 58c43ac2..eb61e9c 100644
--- a/core/tests/coretests/src/android/content/pm/PackageParserTest.java
+++ b/core/tests/coretests/src/android/content/pm/PackageParserTest.java
@@ -428,6 +428,18 @@
                 "com.android.frameworks.coretests.install_complete_package_info.test_permission",
                 packageName, PermissionInfo.PROTECTION_NORMAL, p.permissions.get(0));
 
+        // Hidden "app details" activity is added to every package.
+        boolean foundAppDetailsActivity = false;
+        for (int i = 0; i < p.activities.size(); i++) {
+            if (p.activities.get(i).className.equals(
+                    PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME)) {
+                foundAppDetailsActivity = true;
+                p.activities.remove(i);
+                break;
+            }
+        }
+        assertTrue("Did not find app details activity", foundAppDetailsActivity);
+
         assertOneComponentOfEachType("com.android.frameworks.coretests.Test%s", p);
 
         assertMetadata(p.mAppMetaData,
diff --git a/core/tests/coretests/src/android/os/ParcelNullabilityTest.java b/core/tests/coretests/src/android/os/ParcelNullabilityTest.java
index a6b296d..b4e180c 100644
--- a/core/tests/coretests/src/android/os/ParcelNullabilityTest.java
+++ b/core/tests/coretests/src/android/os/ParcelNullabilityTest.java
@@ -327,8 +327,8 @@
         Parcel p = Parcel.obtain();
         p.writeParcelableList(null, 0);
 
-        List<Object> list = new ArrayList<>();
-        throughBytes(p).readParcelableList(null, null);
+        List<Parcelable> list = new ArrayList<>();
+        throughBytes(p).readParcelableList(list, null);
         assertTrue(list.isEmpty());
     }
 
diff --git a/core/tests/coretests/src/android/widget/AbsSeekBarTest.java b/core/tests/coretests/src/android/widget/AbsSeekBarTest.java
new file mode 100644
index 0000000..aec6096
--- /dev/null
+++ b/core/tests/coretests/src/android/widget/AbsSeekBarTest.java
@@ -0,0 +1,136 @@
+/*
+ * 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.widget;
+
+import static android.view.View.MeasureSpec.EXACTLY;
+import static android.view.View.MeasureSpec.makeMeasureSpec;
+
+import static org.hamcrest.Matchers.hasItem;
+import static org.hamcrest.Matchers.hasSize;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+
+import android.content.Context;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.graphics.drawable.ShapeDrawable;
+import android.graphics.drawable.shapes.RectShape;
+import android.platform.test.annotations.Presubmit;
+import android.view.View;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Arrays;
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+@Presubmit
+public class AbsSeekBarTest {
+
+    private Context mContext;
+    private AbsSeekBar mBar;
+
+    @Before
+    public void setUp() throws Exception {
+        mContext = InstrumentationRegistry.getInstrumentation().getContext();
+        mBar = new SeekBar(mContext);
+    }
+
+    @Test
+    public void testExclusionForThumb_limitedTo48dp() {
+        mBar.setPadding(10, 10, 10, 10);
+        mBar.setThumb(newThumb(dpToPx(20)));
+        mBar.setMin(0);
+        mBar.setMax(100);
+        mBar.setProgress(50);
+        measureAndLayout(dpToPx(200), dpToPx(100));
+        List<Rect> exclusions = mBar.getSystemGestureExclusionRects();
+
+        assertEquals("exclusions should be size 1, but was " + exclusions, 1, exclusions.size());
+        assertEquals("exclusion should be centered on thumb",
+                center(mBar), center(exclusions.get(0)));
+        assertEquals("exclusion should be 48dp high", dpToPx(48), exclusions.get(0).height());
+        assertEquals("exclusion should be 48dp wide", dpToPx(48), exclusions.get(0).width());
+    }
+
+    @Test
+    public void testExclusionForThumb_limitedToHeight() {
+        mBar.setPadding(10, 10, 10, 10);
+        mBar.setThumb(newThumb(dpToPx(20)));
+        mBar.setMin(0);
+        mBar.setMax(100);
+        mBar.setProgress(50);
+        measureAndLayout(dpToPx(200), dpToPx(32));
+        List<Rect> exclusions = mBar.getSystemGestureExclusionRects();
+
+        assertEquals("exclusions should be size 1, but was " + exclusions, 1, exclusions.size());
+        assertEquals("exclusion should be centered on thumb",
+                center(mBar), center(exclusions.get(0)));
+        assertEquals("exclusion should be 32dp high", dpToPx(32), exclusions.get(0).height());
+        assertEquals("exclusion should be 32dp wide", dpToPx(32), exclusions.get(0).width());
+    }
+
+    @Test
+    public void testExclusionForThumb_passesThroughUserExclusions() {
+        mBar.setSystemGestureExclusionRects(Arrays.asList(new Rect(1, 2, 3, 4)));
+
+        mBar.setPadding(10, 10, 10, 10);
+        mBar.setThumb(newThumb(dpToPx(20)));
+        mBar.setMin(0);
+        mBar.setMax(100);
+        mBar.setProgress(50);
+        measureAndLayout(dpToPx(200), dpToPx(32));
+
+        assertThat(mBar.getSystemGestureExclusionRects(), hasItem(new Rect(1, 2, 3, 4)));
+        assertThat(mBar.getSystemGestureExclusionRects(), hasSize(2));
+
+        mBar.setSystemGestureExclusionRects(Arrays.asList(new Rect(3, 4, 5, 6)));
+        assertThat(mBar.getSystemGestureExclusionRects(), hasItem(new Rect(3, 4, 5, 6)));
+        assertThat(mBar.getSystemGestureExclusionRects(), hasSize(2));
+    }
+
+    private Point center(Rect rect) {
+        return new Point(rect.centerX(), rect.centerY());
+    }
+
+    private Point center(View view) {
+        return center(new Rect(view.getLeft(), view.getTop(), view.getRight(), view.getBottom()));
+    }
+
+    private ShapeDrawable newThumb(int size) {
+        final ShapeDrawable thumb = new ShapeDrawable(new RectShape());
+        thumb.setIntrinsicWidth(size);
+        thumb.setIntrinsicHeight(size);
+        return thumb;
+    }
+
+    private void measureAndLayout(int wPx, int hPx) {
+        mBar.measure(makeMeasureSpec(wPx, EXACTLY), makeMeasureSpec(hPx, EXACTLY));
+        mBar.layout(0, 0, wPx, hPx);
+    }
+
+    private int dpToPx(int dp) {
+        return (int) (mContext.getResources().getDisplayMetrics().density * dp);
+    }
+}
diff --git a/core/tests/utiltests/src/com/android/internal/util/XmlUtilsTest.java b/core/tests/utiltests/src/com/android/internal/util/XmlUtilsTest.java
index 2596ece..27f3596 100644
--- a/core/tests/utiltests/src/com/android/internal/util/XmlUtilsTest.java
+++ b/core/tests/utiltests/src/com/android/internal/util/XmlUtilsTest.java
@@ -16,13 +16,22 @@
 
 package com.android.internal.util;
 
+import static org.junit.Assert.assertArrayEquals;
+
+import android.util.Xml;
+
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
 import java.util.HashMap;
 import java.util.Map;
+
 import junit.framework.TestCase;
 
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlSerializer;
+
 public class XmlUtilsTest extends TestCase {
 
     // https://code.google.com/p/android/issues/detail?id=63717
@@ -38,4 +47,23 @@
         assertEquals("nullValue", deserialized.get(null));
         assertEquals("fooValue", deserialized.get("foo"));
     }
+
+    public void testreadWriteXmlByteArrayValue() throws Exception {
+        byte[] testByteArray = {0x1 , 0xa, 0xb, 0x9, 0x34, (byte) 0xaa, (byte) 0xba, (byte) 0x99};
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
+        XmlSerializer serializer = new FastXmlSerializer();
+        serializer.setOutput(baos, StandardCharsets.UTF_8.name());
+        serializer.startDocument(null, true);
+        XmlUtils.writeValueXml(testByteArray,  "testByteArray", serializer);
+        serializer.endDocument();
+
+        InputStream bais = new ByteArrayInputStream(baos.toByteArray());
+        XmlPullParser pullParser = Xml.newPullParser();
+        pullParser.setInput(bais, StandardCharsets.UTF_8.name());
+        String[] name = new String[1];
+        byte[] testByteArrayDeserialized = (byte[]) XmlUtils.readValueXml(pullParser, name);
+        assertEquals("testByteArray", name[0]);
+        assertArrayEquals(testByteArray, testByteArrayDeserialized);
+    }
 }
diff --git a/graphics/java/android/graphics/FontFamily.java b/graphics/java/android/graphics/FontFamily.java
index 5af0da8..5ad93f4 100644
--- a/graphics/java/android/graphics/FontFamily.java
+++ b/graphics/java/android/graphics/FontFamily.java
@@ -21,7 +21,6 @@
 import android.content.res.AssetManager;
 import android.graphics.fonts.FontVariationAxis;
 import android.text.TextUtils;
-import android.util.Log;
 
 import dalvik.annotation.optimization.CriticalNative;
 
@@ -145,7 +144,6 @@
             }
             return nAddFont(mBuilderPtr, fontBuffer, ttcIndex, weight, italic);
         } catch (IOException e) {
-            Log.e(TAG, "Error mapping font file " + path);
             return false;
         }
     }
diff --git a/graphics/java/android/graphics/fonts/SystemFonts.java b/graphics/java/android/graphics/fonts/SystemFonts.java
index 4a9cf14..95a8417 100644
--- a/graphics/java/android/graphics/fonts/SystemFonts.java
+++ b/graphics/java/android/graphics/fonts/SystemFonts.java
@@ -105,7 +105,6 @@
             final long fontSize = fileChannel.size();
             return fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, fontSize);
         } catch (IOException e) {
-            Log.e(TAG, "Error mapping font file " + fullPath);
             return null;
         }
     }
diff --git a/keystore/java/android/security/AttestedKeyPair.java b/keystore/java/android/security/AttestedKeyPair.java
index c6bff5c..2debfee 100644
--- a/keystore/java/android/security/AttestedKeyPair.java
+++ b/keystore/java/android/security/AttestedKeyPair.java
@@ -16,6 +16,9 @@
 
 package android.security;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
 import java.security.KeyPair;
 import java.security.cert.Certificate;
 import java.util.ArrayList;
@@ -36,9 +39,12 @@
     private final Certificate[] mAttestationRecord;
 
     /**
-     * @hide Only created by the platform, no need to expose as public API.
+     * Public constructor for creating a new instance (useful for testing).
+     *
+     * @param keyPair the key pair associated with the attestation record.
+     * @param attestationRecord attestation record for the provided key pair.
      */
-    public AttestedKeyPair(KeyPair keyPair, Certificate[] attestationRecord) {
+    public AttestedKeyPair(@Nullable KeyPair keyPair, @Nullable Certificate[] attestationRecord) {
         mKeyPair = keyPair;
         mAttestationRecord = attestationRecord;
     }
@@ -47,7 +53,7 @@
      * Returns the generated key pair associated with the attestation record
      * in this instance.
      */
-    public KeyPair getKeyPair() {
+    public @Nullable KeyPair getKeyPair() {
         return mKeyPair;
     }
 
@@ -66,7 +72,7 @@
      * and  <a href="https://developer.android.com/training/articles/security-key-attestation.html">
      * Key Attestation</a> for the format of the attestation record inside the certificate.
      */
-    public List<Certificate> getAttestationRecord() {
+    public @NonNull List<Certificate> getAttestationRecord() {
         if (mAttestationRecord == null) {
             return new ArrayList();
         }
diff --git a/libs/hwui/DeviceInfo.cpp b/libs/hwui/DeviceInfo.cpp
index 0a9d965..a0d3ff9 100644
--- a/libs/hwui/DeviceInfo.cpp
+++ b/libs/hwui/DeviceInfo.cpp
@@ -18,7 +18,6 @@
 
 #include "Properties.h"
 
-#include <gui/ISurfaceComposer.h>
 #include <gui/SurfaceComposerClient.h>
 #include <ui/GraphicTypes.h>
 
diff --git a/libs/hwui/FrameInfo.cpp b/libs/hwui/FrameInfo.cpp
index 71cc9a8..0698775 100644
--- a/libs/hwui/FrameInfo.cpp
+++ b/libs/hwui/FrameInfo.cpp
@@ -37,13 +37,14 @@
         "FrameCompleted",
         "DequeueBufferDuration",
         "QueueBufferDuration",
+        "GpuCompleted",
 };
 
 static_assert((sizeof(FrameInfoNames) / sizeof(FrameInfoNames[0])) ==
                       static_cast<int>(FrameInfoIndex::NumIndexes),
               "size mismatch: FrameInfoNames doesn't match the enum!");
 
-static_assert(static_cast<int>(FrameInfoIndex::NumIndexes) == 16,
+static_assert(static_cast<int>(FrameInfoIndex::NumIndexes) == 17,
               "Must update value in FrameMetrics.java#FRAME_STATS_COUNT (and here)");
 
 void FrameInfo::importUiThreadInfo(int64_t* info) {
diff --git a/libs/hwui/FrameInfo.h b/libs/hwui/FrameInfo.h
index b75192f..51674fb 100644
--- a/libs/hwui/FrameInfo.h
+++ b/libs/hwui/FrameInfo.h
@@ -51,6 +51,8 @@
     DequeueBufferDuration,
     QueueBufferDuration,
 
+    GpuCompleted,
+
     // Must be the last value!
     // Also must be kept in sync with FrameMetrics.java#FRAME_STATS_COUNT
     NumIndexes
@@ -143,6 +145,13 @@
         return duration(FrameInfoIndex::IntendedVsync, FrameInfoIndex::FrameCompleted);
     }
 
+    inline int64_t gpuDrawTime() const {
+        // GPU start time is approximated to the moment before swapBuffer is invoked.
+        // We could add an EGLSyncKHR fence at the beginning of the frame, but that is an overhead.
+        int64_t endTime = get(FrameInfoIndex::GpuCompleted);
+        return endTime > 0 ? endTime - get(FrameInfoIndex::SwapBuffers) : -1;
+    }
+
     inline int64_t& set(FrameInfoIndex index) { return mFrameInfo[static_cast<int>(index)]; }
 
     inline int64_t get(FrameInfoIndex index) const {
diff --git a/libs/hwui/JankTracker.cpp b/libs/hwui/JankTracker.cpp
index 53c5ad8..eae3584 100644
--- a/libs/hwui/JankTracker.cpp
+++ b/libs/hwui/JankTracker.cpp
@@ -232,5 +232,13 @@
                                                     : FrameInfoIndex::IntendedVsync;
 }
 
+void JankTracker::finishGpuDraw(const FrameInfo& frame) {
+    int64_t totalGPUDrawTime = frame.gpuDrawTime();
+    if (totalGPUDrawTime >= 0) {
+        mData->reportGPUFrame(totalGPUDrawTime);
+        (*mGlobalData)->reportGPUFrame(totalGPUDrawTime);
+    }
+}
+
 } /* namespace uirenderer */
 } /* namespace android */
diff --git a/libs/hwui/JankTracker.h b/libs/hwui/JankTracker.h
index 110211e..08059268 100644
--- a/libs/hwui/JankTracker.h
+++ b/libs/hwui/JankTracker.h
@@ -58,6 +58,7 @@
 
     FrameInfo* startFrame() { return &mFrames.next(); }
     void finishFrame(const FrameInfo& frame);
+    void finishGpuDraw(const FrameInfo& frame);
 
     void dumpStats(int fd) { dumpData(fd, &mDescription, mData.get()); }
     void dumpFrames(int fd);
diff --git a/libs/hwui/ProfileData.cpp b/libs/hwui/ProfileData.cpp
index c7f9232..7921662 100644
--- a/libs/hwui/ProfileData.cpp
+++ b/libs/hwui/ProfileData.cpp
@@ -98,6 +98,10 @@
     if (mStatStartTime > other.mStatStartTime || mStatStartTime == 0) {
         mStatStartTime = other.mStatStartTime;
     }
+    for (size_t i = 0; i < other.mGPUFrameCounts.size(); i++) {
+        mGPUFrameCounts[i] >>= divider;
+        mGPUFrameCounts[i] += other.mGPUFrameCounts[i];
+    }
 }
 
 void ProfileData::dump(int fd) const {
@@ -117,6 +121,14 @@
     histogramForEach([fd](HistogramEntry entry) {
         dprintf(fd, " %ums=%u", entry.renderTimeMs, entry.frameCount);
     });
+    dprintf(fd, "\n50th gpu percentile: %ums", findGPUPercentile(50));
+    dprintf(fd, "\n90th gpu percentile: %ums", findGPUPercentile(90));
+    dprintf(fd, "\n95th gpu percentile: %ums", findGPUPercentile(95));
+    dprintf(fd, "\n99th gpu percentile: %ums", findGPUPercentile(99));
+    dprintf(fd, "\nGPU HISTOGRAM:");
+    histogramGPUForEach([fd](HistogramEntry entry) {
+        dprintf(fd, " %ums=%u", entry.renderTimeMs, entry.frameCount);
+    });
 }
 
 uint32_t ProfileData::findPercentile(int percentile) const {
@@ -140,6 +152,7 @@
 void ProfileData::reset() {
     mJankTypeCounts.fill(0);
     mFrameCounts.fill(0);
+    mGPUFrameCounts.fill(0);
     mSlowFrameCounts.fill(0);
     mTotalFrameCount = 0;
     mJankFrameCount = 0;
@@ -167,5 +180,40 @@
     }
 }
 
+uint32_t ProfileData::findGPUPercentile(int percentile) const {
+    uint32_t totalGPUFrameCount = 0;  // this is usually mTotalFrameCount - 3.
+    for (int i = mGPUFrameCounts.size() - 1; i >= 0; i--) {
+        totalGPUFrameCount += mGPUFrameCounts[i];
+    }
+    int pos = percentile * totalGPUFrameCount / 100;
+    int remaining = totalGPUFrameCount - pos;
+    for (int i = mGPUFrameCounts.size() - 1; i >= 0; i--) {
+        remaining -= mGPUFrameCounts[i];
+        if (remaining <= 0) {
+            return GPUFrameTimeForFrameCountIndex(i);
+        }
+    }
+    return 0;
+}
+
+uint32_t ProfileData::GPUFrameTimeForFrameCountIndex(uint32_t index) {
+    return index != 25 ? index + 1 : 4950;
+}
+
+void ProfileData::reportGPUFrame(int64_t duration) {
+    uint32_t index = static_cast<uint32_t>(ns2ms(duration));
+    if (index > 25) {
+        index = 25;
+    }
+
+    mGPUFrameCounts[index]++;
+}
+
+void ProfileData::histogramGPUForEach(const std::function<void(HistogramEntry)>& callback) const {
+    for (size_t i = 0; i < mGPUFrameCounts.size(); i++) {
+        callback(HistogramEntry{GPUFrameTimeForFrameCountIndex(i), mGPUFrameCounts[i]});
+    }
+}
+
 } /* namespace uirenderer */
 } /* namespace android */
\ No newline at end of file
diff --git a/libs/hwui/ProfileData.h b/libs/hwui/ProfileData.h
index 564920b..ccbffc6 100644
--- a/libs/hwui/ProfileData.h
+++ b/libs/hwui/ProfileData.h
@@ -54,8 +54,10 @@
     void mergeWith(const ProfileData& other);
     void dump(int fd) const;
     uint32_t findPercentile(int percentile) const;
+    uint32_t findGPUPercentile(int percentile) const;
 
     void reportFrame(int64_t duration);
+    void reportGPUFrame(int64_t duration);
     void reportJank() { mJankFrameCount++; }
     void reportJankType(JankType type) { mJankTypeCounts[static_cast<int>(type)]++; }
 
@@ -69,15 +71,21 @@
         uint32_t frameCount;
     };
     void histogramForEach(const std::function<void(HistogramEntry)>& callback) const;
+    void histogramGPUForEach(const std::function<void(HistogramEntry)>& callback) const;
 
     constexpr static int HistogramSize() {
         return std::tuple_size<decltype(ProfileData::mFrameCounts)>::value +
                std::tuple_size<decltype(ProfileData::mSlowFrameCounts)>::value;
     }
 
+    constexpr static int GPUHistogramSize() {
+        return std::tuple_size<decltype(ProfileData::mGPUFrameCounts)>::value;
+    }
+
     // Visible for testing
     static uint32_t frameTimeForFrameCountIndex(uint32_t index);
     static uint32_t frameTimeForSlowFrameCountIndex(uint32_t index);
+    static uint32_t GPUFrameTimeForFrameCountIndex(uint32_t index);
 
 private:
     // Open our guts up to unit tests
@@ -88,6 +96,9 @@
     std::array<uint32_t, 57> mFrameCounts;
     // Holds a histogram of frame times in 50ms increments from 150ms to 5s
     std::array<uint16_t, 97> mSlowFrameCounts;
+    // Holds a histogram of GPU draw times in 1ms increments. Frames longer than 25ms are placed in
+    // last bucket.
+    std::array<uint32_t, 26> mGPUFrameCounts;
 
     uint32_t mTotalFrameCount;
     uint32_t mJankFrameCount;
diff --git a/libs/hwui/protos/graphicsstats.proto b/libs/hwui/protos/graphicsstats.proto
index 1226d44..0cd5c62 100644
--- a/libs/hwui/protos/graphicsstats.proto
+++ b/libs/hwui/protos/graphicsstats.proto
@@ -46,6 +46,9 @@
 
     // The frame time histogram for the package
     repeated GraphicsStatsHistogramBucketProto histogram = 6;
+
+    // The gpu frame time histogram for the package
+    repeated GraphicsStatsHistogramBucketProto gpu_histogram = 7;
 }
 
 message GraphicsStatsJankSummaryProto {
diff --git a/libs/hwui/renderthread/CacheManager.cpp b/libs/hwui/renderthread/CacheManager.cpp
index 1b638c1..5469a68 100644
--- a/libs/hwui/renderthread/CacheManager.cpp
+++ b/libs/hwui/renderthread/CacheManager.cpp
@@ -28,7 +28,6 @@
 #include <SkExecutor.h>
 #include <SkGraphics.h>
 #include <SkMathPriv.h>
-#include <gui/Surface.h>
 #include <math.h>
 #include <set>
 
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index d19351b..88a0c6e 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -147,6 +147,7 @@
         mNativeSurface = new ReliableSurface{std::move(surface)};
         // TODO: Fix error handling & re-shorten timeout
         mNativeSurface->setDequeueTimeout(4000_ms);
+        mNativeSurface->enableFrameTimestamps(true);
     } else {
         mNativeSurface = nullptr;
     }
@@ -294,6 +295,7 @@
     // just keep using the previous frame's structure instead
     if (!wasSkipped(mCurrentFrameInfo)) {
         mCurrentFrameInfo = mJankTracker.startFrame();
+        mLast4FrameInfos.next().first = mCurrentFrameInfo;
     }
     mCurrentFrameInfo->importUiThreadInfo(uiFrameInfo);
     mCurrentFrameInfo->set(FrameInfoIndex::SyncQueued) = syncQueued;
@@ -445,7 +447,7 @@
                                       mContentDrawBounds, mOpaque, mLightInfo, mRenderNodes,
                                       &(profiler()));
 
-    int64_t frameCompleteNr = mFrameCompleteCallbacks.size() ? getFrameNumber() : -1;
+    int64_t frameCompleteNr = getFrameNumber();
 
     waitOnFences();
 
@@ -500,11 +502,13 @@
         }
         mCurrentFrameInfo->set(FrameInfoIndex::DequeueBufferDuration) = swap.dequeueDuration;
         mCurrentFrameInfo->set(FrameInfoIndex::QueueBufferDuration) = swap.queueDuration;
+        mLast4FrameInfos[-1].second = frameCompleteNr;
         mHaveNewSurface = false;
         mFrameNumber = -1;
     } else {
         mCurrentFrameInfo->set(FrameInfoIndex::DequeueBufferDuration) = 0;
         mCurrentFrameInfo->set(FrameInfoIndex::QueueBufferDuration) = 0;
+        mLast4FrameInfos[-1].second = -1;
     }
 
     // TODO: Use a fence for real completion?
@@ -537,6 +541,19 @@
         mFrameMetricsReporter->reportFrameMetrics(mCurrentFrameInfo->data());
     }
 
+    if (mLast4FrameInfos.size() == mLast4FrameInfos.capacity()) {
+        // By looking 4 frames back, we guarantee all SF stats are available. There are at
+        // most 3 buffers in BufferQueue. Surface object keeps stats for the last 8 frames.
+        FrameInfo* forthBehind = mLast4FrameInfos.front().first;
+        int64_t composedFrameId = mLast4FrameInfos.front().second;
+        nsecs_t acquireTime = -1;
+        mNativeSurface->getFrameTimestamps(composedFrameId, nullptr, &acquireTime, nullptr, nullptr,
+            nullptr, nullptr, nullptr, nullptr, nullptr);
+        // Ignore default -1, NATIVE_WINDOW_TIMESTAMP_INVALID and NATIVE_WINDOW_TIMESTAMP_PENDING
+        forthBehind->set(FrameInfoIndex::GpuCompleted) = acquireTime > 0 ? acquireTime : -1;
+        mJankTracker.finishGpuDraw(*forthBehind);
+    }
+
     GpuMemoryTracker::onFrameCompleted();
 }
 
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index f9b9310..8a76d6b 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -29,6 +29,7 @@
 #include "RenderNode.h"
 #include "renderthread/RenderTask.h"
 #include "renderthread/RenderThread.h"
+#include "utils/RingBuffer.h"
 
 #include <SkBitmap.h>
 #include <SkRect.h>
@@ -41,6 +42,7 @@
 #include <future>
 #include <set>
 #include <string>
+#include <utility>
 #include <vector>
 
 namespace android {
@@ -260,6 +262,7 @@
     std::vector<sp<RenderNode>> mRenderNodes;
 
     FrameInfo* mCurrentFrameInfo = nullptr;
+    RingBuffer<std::pair<FrameInfo*, int64_t>, 4> mLast4FrameInfos;
     std::string mName;
     JankTracker mJankTracker;
     FrameInfoVisualizer mProfiler;
diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp
index 159cf49..1202164 100644
--- a/libs/hwui/renderthread/EglManager.cpp
+++ b/libs/hwui/renderthread/EglManager.cpp
@@ -29,7 +29,6 @@
 #include <EGL/eglext.h>
 #include <GLES/gl.h>
 
-#include <gui/Surface.h>
 #include <system/window.h>
 #include <string>
 #include <vector>
@@ -289,6 +288,10 @@
     if (mPBufferSurface == EGL_NO_SURFACE && !EglExtensions.surfacelessContext) {
         EGLint attribs[] = {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE};
         mPBufferSurface = eglCreatePbufferSurface(mEglDisplay, mEglConfig, attribs);
+        LOG_ALWAYS_FATAL_IF(mPBufferSurface == EGL_NO_SURFACE,
+                            "Failed to create a pixel buffer display=%p, "
+                            "mEglConfig=%p, error=%s",
+                            mEglDisplay, mEglConfig, eglErrorString());
     }
 }
 
diff --git a/libs/hwui/renderthread/ReliableSurface.h b/libs/hwui/renderthread/ReliableSurface.h
index 41fc35e..7f1a078 100644
--- a/libs/hwui/renderthread/ReliableSurface.h
+++ b/libs/hwui/renderthread/ReliableSurface.h
@@ -49,6 +49,21 @@
         return ret;
     }
 
+    status_t getFrameTimestamps(uint64_t frameNumber,
+            nsecs_t* outRequestedPresentTime, nsecs_t* outAcquireTime,
+            nsecs_t* outLatchTime, nsecs_t* outFirstRefreshStartTime,
+            nsecs_t* outLastRefreshStartTime, nsecs_t* outGlCompositionDoneTime,
+            nsecs_t* outDisplayPresentTime, nsecs_t* outDequeueReadyTime,
+            nsecs_t* outReleaseTime) {
+        return mSurface->getFrameTimestamps(frameNumber, outRequestedPresentTime, outAcquireTime,
+            outLatchTime, outFirstRefreshStartTime, outLastRefreshStartTime,
+            outGlCompositionDoneTime, outDisplayPresentTime, outDequeueReadyTime, outReleaseTime);
+    }
+
+    void enableFrameTimestamps(bool enable) {
+        return mSurface->enableFrameTimestamps(enable);
+    }
+
 private:
     const sp<Surface> mSurface;
 
diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp
index 280f7d3..5100165 100644
--- a/libs/hwui/renderthread/VulkanManager.cpp
+++ b/libs/hwui/renderthread/VulkanManager.cpp
@@ -17,7 +17,8 @@
 #include "VulkanManager.h"
 
 #include <android/sync.h>
-#include <gui/Surface.h>
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
 
 #include "Properties.h"
 #include "RenderThread.h"
diff --git a/libs/hwui/service/GraphicsStatsService.cpp b/libs/hwui/service/GraphicsStatsService.cpp
index 8a16b20..8b5912b 100644
--- a/libs/hwui/service/GraphicsStatsService.cpp
+++ b/libs/hwui/service/GraphicsStatsService.cpp
@@ -40,6 +40,7 @@
 static_assert(sizeof(sCurrentFileVersion) == sHeaderSize, "Header size is wrong");
 
 constexpr int sHistogramSize = ProfileData::HistogramSize();
+constexpr int sGPUHistogramSize = ProfileData::GPUHistogramSize();
 
 static bool mergeProfileDataIntoProto(protos::GraphicsStatsProto* proto,
                                       const std::string& package, int64_t versionCode,
@@ -211,6 +212,37 @@
         bucket->set_frame_count(bucket->frame_count() + entry.frameCount);
         index++;
     });
+    if (hitMergeError) return false;
+    // fill in GPU frame time histogram
+    creatingHistogram = false;
+    if (proto->gpu_histogram_size() == 0) {
+        proto->mutable_gpu_histogram()->Reserve(sGPUHistogramSize);
+        creatingHistogram = true;
+    } else if (proto->gpu_histogram_size() != sGPUHistogramSize) {
+        ALOGE("GPU histogram size mismatch, proto is %d expected %d", proto->gpu_histogram_size(),
+              sGPUHistogramSize);
+        return false;
+    }
+    index = 0;
+    data->histogramGPUForEach([&](ProfileData::HistogramEntry entry) {
+        if (hitMergeError) return;
+
+        protos::GraphicsStatsHistogramBucketProto* bucket;
+        if (creatingHistogram) {
+            bucket = proto->add_gpu_histogram();
+            bucket->set_render_millis(entry.renderTimeMs);
+        } else {
+            bucket = proto->mutable_gpu_histogram(index);
+            if (bucket->render_millis() != static_cast<int32_t>(entry.renderTimeMs)) {
+                ALOGW("GPU frame time mistmatch %d vs. %u", bucket->render_millis(),
+                      entry.renderTimeMs);
+                hitMergeError = true;
+                return;
+            }
+        }
+        bucket->set_frame_count(bucket->frame_count() + entry.frameCount);
+        index++;
+    });
     return !hitMergeError;
 }
 
@@ -226,6 +258,22 @@
     return 0;
 }
 
+static int32_t findGPUPercentile(protos::GraphicsStatsProto* proto, int percentile) {
+    uint32_t totalGPUFrameCount = 0;  // this is usually  proto->summary().total_frames() - 3.
+    for (auto it = proto->gpu_histogram().rbegin(); it != proto->gpu_histogram().rend(); ++it) {
+        totalGPUFrameCount += it->frame_count();
+    }
+    int32_t pos = percentile * totalGPUFrameCount / 100;
+    int32_t remaining = totalGPUFrameCount - pos;
+    for (auto it = proto->gpu_histogram().rbegin(); it != proto->gpu_histogram().rend(); ++it) {
+        remaining -= it->frame_count();
+        if (remaining <= 0) {
+            return it->render_millis();
+        }
+    }
+    return 0;
+}
+
 void dumpAsTextToFd(protos::GraphicsStatsProto* proto, int fd) {
     // This isn't a full validation, just enough that we can deref at will
     if (proto->package_name().empty() || !proto->has_summary()) {
@@ -255,6 +303,14 @@
     for (const auto& it : proto->histogram()) {
         dprintf(fd, " %dms=%d", it.render_millis(), it.frame_count());
     }
+    dprintf(fd, "\n50th gpu percentile: %dms", findGPUPercentile(proto, 50));
+    dprintf(fd, "\n90th gpu percentile: %dms", findGPUPercentile(proto, 90));
+    dprintf(fd, "\n95th gpu percentile: %dms", findGPUPercentile(proto, 95));
+    dprintf(fd, "\n99th gpu percentile: %dms", findGPUPercentile(proto, 99));
+    dprintf(fd, "\nGPU HISTOGRAM:");
+    for (const auto& it : proto->gpu_histogram()) {
+        dprintf(fd, " %dms=%d", it.render_millis(), it.frame_count());
+    }
     dprintf(fd, "\n");
 }
 
diff --git a/media/OWNERS b/media/OWNERS
index a33a990..8bd037a 100644
--- a/media/OWNERS
+++ b/media/OWNERS
@@ -10,6 +10,7 @@
 jaewan@google.com
 jmtrivi@google.com
 jsharkey@android.com
+klhyun@google.com
 lajos@google.com
 marcone@google.com
 sungsoo@google.com
diff --git a/media/java/android/media/AudioPortConfig.java b/media/java/android/media/AudioPortConfig.java
index 45e49a7..ac19bb1 100644
--- a/media/java/android/media/AudioPortConfig.java
+++ b/media/java/android/media/AudioPortConfig.java
@@ -95,7 +95,6 @@
 
     /**
      * The gain configuration if this port supports gain control, null otherwise
-     * @see AudioGainConfig.
      */
     public AudioGainConfig gain() {
         return mGain;
diff --git a/media/java/android/media/session/MediaSessionManager.java b/media/java/android/media/session/MediaSessionManager.java
index 1f2283c..6fd3342 100644
--- a/media/java/android/media/session/MediaSessionManager.java
+++ b/media/java/android/media/session/MediaSessionManager.java
@@ -16,6 +16,7 @@
 
 package android.media.session;
 
+import android.annotation.CallbackExecutor;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
@@ -31,6 +32,7 @@
 import android.media.Session2Token;
 import android.os.Bundle;
 import android.os.Handler;
+import android.os.HandlerExecutor;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.ResultReceiver;
@@ -50,6 +52,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
+import java.util.concurrent.Executor;
 
 /**
  * Provides support for interacting with {@link MediaSession media sessions}
@@ -86,7 +89,7 @@
     @GuardedBy("mLock")
     private final CallbackStub mCbStub = new CallbackStub();
     @GuardedBy("mLock")
-    private final Map<Callback, Handler> mCallbacks = new HashMap<>();
+    private final Map<Callback, Executor> mCallbacks = new HashMap<>();
     @GuardedBy("mLock")
     private MediaSession.Token mCurMediaButtonSession;
     @GuardedBy("mLock")
@@ -765,13 +768,16 @@
      */
     // TODO: Remove this method once Bluetooth app stop calling it.
     public void setCallback(@Nullable Callback callback, @Nullable Handler handler) {
+        if (handler == null) {
+            handler = new Handler();
+        }
         synchronized (mLock) {
             if (mLegacyCallback != null) {
                 unregisterCallback(mLegacyCallback);
             }
             mLegacyCallback = callback;
             if (callback != null) {
-                registerCallback(callback, handler);
+                registerCallback(new HandlerExecutor(handler), callback);
             }
         }
     }
@@ -779,27 +785,29 @@
     /**
      * Register a {@link Callback}.
      *
+     * @param executor The executor on which the callback should be invoked
      * @param callback A {@link Callback}.
-     * @param handler The handler on which the callback should be invoked, or {@code null}
-     *            if the callback should be invoked on the calling thread's looper.
      * @hide
      */
     @SystemApi
     @RequiresPermission(value = android.Manifest.permission.MEDIA_CONTENT_CONTROL)
-    public void registerCallback(@NonNull Callback callback, @Nullable Handler handler) {
+    public void registerCallback(@NonNull @CallbackExecutor Executor executor,
+            @NonNull Callback callback) {
+        if (executor == null) {
+            throw new NullPointerException("executor shouldn't be null");
+        }
         if (callback == null) {
             throw new NullPointerException("callback shouldn't be null");
         }
         synchronized (mLock) {
             try {
-                if (handler == null) {
-                    handler = new Handler();
-                }
-                mCallbacks.put(callback, handler);
+                mCallbacks.put(callback, executor);
                 if (mCurMediaButtonSession != null) {
-                    handler.post(() -> callback.onAddressedPlayerChanged(mCurMediaButtonSession));
+                    executor.execute(
+                            () -> callback.onAddressedPlayerChanged(mCurMediaButtonSession));
                 } else if (mCurMediaButtonReceiver != null) {
-                    handler.post(() -> callback.onAddressedPlayerChanged(mCurMediaButtonReceiver));
+                    executor.execute(
+                            () -> callback.onAddressedPlayerChanged(mCurMediaButtonReceiver));
                 }
 
                 if (mCallbacks.size() == 1) {
@@ -1147,8 +1155,8 @@
         public void onMediaKeyEventDispatchedToMediaSession(KeyEvent event,
                 MediaSession.Token sessionToken) {
             synchronized (mLock) {
-                for (Map.Entry<Callback, Handler> e : mCallbacks.entrySet()) {
-                    e.getValue().post(
+                for (Map.Entry<Callback, Executor> e : mCallbacks.entrySet()) {
+                    e.getValue().execute(
                             () -> e.getKey().onMediaKeyEventDispatched(event, sessionToken));
                 }
             }
@@ -1158,8 +1166,8 @@
         public void onMediaKeyEventDispatchedToMediaButtonReceiver(KeyEvent event,
                 ComponentName mediaButtonReceiver) {
             synchronized (mLock) {
-                for (Map.Entry<Callback, Handler> e : mCallbacks.entrySet()) {
-                    e.getValue().post(
+                for (Map.Entry<Callback, Executor> e : mCallbacks.entrySet()) {
+                    e.getValue().execute(
                             () -> e.getKey().onMediaKeyEventDispatched(event, mediaButtonReceiver));
                 }
             }
@@ -1170,8 +1178,8 @@
             synchronized (mLock) {
                 mCurMediaButtonSession = sessionToken;
                 mCurMediaButtonReceiver = null;
-                for (Map.Entry<Callback, Handler> e : mCallbacks.entrySet()) {
-                    e.getValue().post(() -> e.getKey().onAddressedPlayerChanged(sessionToken));
+                for (Map.Entry<Callback, Executor> e : mCallbacks.entrySet()) {
+                    e.getValue().execute(() -> e.getKey().onAddressedPlayerChanged(sessionToken));
                 }
             }
         }
@@ -1182,8 +1190,8 @@
             synchronized (mLock) {
                 mCurMediaButtonSession = null;
                 mCurMediaButtonReceiver = mediaButtonReceiver;
-                for (Map.Entry<Callback, Handler> e : mCallbacks.entrySet()) {
-                    e.getValue().post(() -> e.getKey().onAddressedPlayerChanged(
+                for (Map.Entry<Callback, Executor> e : mCallbacks.entrySet()) {
+                    e.getValue().execute(() -> e.getKey().onAddressedPlayerChanged(
                             mediaButtonReceiver));
                 }
             }
diff --git a/media/jni/android_media_ImageWriter.cpp b/media/jni/android_media_ImageWriter.cpp
index 6d8b966..4a9da62 100644
--- a/media/jni/android_media_ImageWriter.cpp
+++ b/media/jni/android_media_ImageWriter.cpp
@@ -26,6 +26,7 @@
 
 #include <gui/IProducerListener.h>
 #include <gui/Surface.h>
+#include <ui/PublicFormat.h>
 #include <android_runtime/AndroidRuntime.h>
 #include <android_runtime/android_view_Surface.h>
 #include <android_runtime/android_hardware_HardwareBuffer.h>
@@ -126,7 +127,7 @@
             Condition mCondition;
             std::deque<wp<Surface>> mQueue;
 
-            static const nsecs_t kWaitDuration = 20000000; // 20 ms
+            static const nsecs_t kWaitDuration = 500000000; // 500 ms
         };
         sp<DetachThread> mThread;
 
@@ -401,8 +402,28 @@
             return 0;
         }
     } else {
+        // Set consumer buffer format to user specified format
+        PublicFormat publicFormat = static_cast<PublicFormat>(userFormat);
+        int nativeFormat = mapPublicFormatToHalFormat(publicFormat);
+        android_dataspace nativeDataspace = mapPublicFormatToHalDataspace(publicFormat);
+        res = native_window_set_buffers_format(anw.get(), nativeFormat);
+        if (res != OK) {
+            ALOGE("%s: Unable to configure consumer native buffer format to %#x",
+                    __FUNCTION__, nativeFormat);
+            jniThrowRuntimeException(env, "Failed to set Surface format");
+            return 0;
+        }
+
+        res = native_window_set_buffers_data_space(anw.get(), nativeDataspace);
+        if (res != OK) {
+            ALOGE("%s: Unable to configure consumer dataspace %#x",
+                    __FUNCTION__, nativeDataspace);
+            jniThrowRuntimeException(env, "Failed to set Surface dataspace");
+            return 0;
+        }
         surfaceFormat = userFormat;
     }
+
     ctx->setBufferFormat(surfaceFormat);
     env->SetIntField(thiz,
             gImageWriterClassInfo.mWriterFormat, reinterpret_cast<jint>(surfaceFormat));
diff --git a/media/native/midi/amidi.cpp b/media/native/midi/amidi.cpp
index 357bb5e5..46f2815 100644
--- a/media/native/midi/amidi.cpp
+++ b/media/native/midi/amidi.cpp
@@ -142,7 +142,7 @@
     return AMEDIA_OK;
 }
 
-media_status_t AMidiDevice_fromJava(JNIEnv *env, jobject j_midiDeviceObj,
+media_status_t AMIDI_API AMidiDevice_fromJava(JNIEnv *env, jobject j_midiDeviceObj,
         AMidiDevice** devicePtrPtr)
 {
     if (j_midiDeviceObj == nullptr) {
@@ -188,7 +188,7 @@
     return AMEDIA_OK;
 }
 
-media_status_t AMidiDevice_release(const AMidiDevice *device)
+media_status_t AMIDI_API AMidiDevice_release(const AMidiDevice *device)
 {
     if (device == nullptr || device->midiDeviceObj == nullptr) {
         return AMEDIA_ERROR_INVALID_PARAMETER;
@@ -217,21 +217,21 @@
     return AMEDIA_OK;
 }
 
-int32_t AMidiDevice_getType(const AMidiDevice *device) {
+int32_t AMIDI_API AMidiDevice_getType(const AMidiDevice *device) {
     if (device == nullptr) {
         return AMEDIA_ERROR_INVALID_PARAMETER;
     }
     return device->deviceInfo.type;
 }
 
-ssize_t AMidiDevice_getNumInputPorts(const AMidiDevice *device) {
+ssize_t AMIDI_API AMidiDevice_getNumInputPorts(const AMidiDevice *device) {
     if (device == nullptr) {
         return AMEDIA_ERROR_INVALID_PARAMETER;
     }
     return device->deviceInfo.inputPortCount;
 }
 
-ssize_t AMidiDevice_getNumOutputPorts(const AMidiDevice *device) {
+ssize_t AMIDI_API AMidiDevice_getNumOutputPorts(const AMidiDevice *device) {
     if (device == nullptr) {
         return AMEDIA_ERROR_INVALID_PARAMETER;
     }
@@ -291,7 +291,7 @@
 /*
  * Output (receiving) API
  */
-media_status_t AMidiOutputPort_open(const AMidiDevice *device, int32_t portNumber,
+media_status_t AMIDI_API AMidiOutputPort_open(const AMidiDevice *device, int32_t portNumber,
         AMidiOutputPort **outOutputPortPtr) {
     return AMIDI_openPort(device, portNumber, PORTTYPE_OUTPUT, (AMIDI_Port**)outOutputPortPtr);
 }
@@ -350,7 +350,7 @@
     AMIDI_Port *mPort;
 };
 
-ssize_t AMidiOutputPort_receive(const AMidiOutputPort *outputPort, int32_t *opcodePtr,
+ssize_t AMIDI_API AMidiOutputPort_receive(const AMidiOutputPort *outputPort, int32_t *opcodePtr,
          uint8_t *buffer, size_t maxBytes, size_t* numBytesReceivedPtr, int64_t *timestampPtr) {
 
     if (outputPort == nullptr || buffer == nullptr) {
@@ -361,19 +361,19 @@
            numBytesReceivedPtr, timestampPtr);
 }
 
-void AMidiOutputPort_close(const AMidiOutputPort *outputPort) {
+void AMIDI_API AMidiOutputPort_close(const AMidiOutputPort *outputPort) {
     AMIDI_closePort((AMIDI_Port*)outputPort);
 }
 
 /*
  * Input (sending) API
  */
-media_status_t AMidiInputPort_open(const AMidiDevice *device, int32_t portNumber,
+media_status_t AMIDI_API AMidiInputPort_open(const AMidiDevice *device, int32_t portNumber,
         AMidiInputPort **outInputPortPtr) {
     return AMIDI_openPort(device, portNumber, PORTTYPE_INPUT, (AMIDI_Port**)outInputPortPtr);
 }
 
-void AMidiInputPort_close(const AMidiInputPort *inputPort) {
+void AMIDI_API AMidiInputPort_close(const AMidiInputPort *inputPort) {
     AMIDI_closePort((AMIDI_Port*)inputPort);
 }
 
@@ -386,12 +386,12 @@
     return numBytes + AMIDI_PACKET_OVERHEAD;
 }
 
-ssize_t AMidiInputPort_send(const AMidiInputPort *inputPort, const uint8_t *buffer,
+ssize_t AMIDI_API AMidiInputPort_send(const AMidiInputPort *inputPort, const uint8_t *buffer,
                             size_t numBytes) {
     return AMidiInputPort_sendWithTimestamp(inputPort, buffer, numBytes, 0);
 }
 
-ssize_t AMidiInputPort_sendWithTimestamp(const AMidiInputPort *inputPort,
+ssize_t AMIDI_API AMidiInputPort_sendWithTimestamp(const AMidiInputPort *inputPort,
         const uint8_t *data, size_t numBytes, int64_t timestamp) {
     if (inputPort == nullptr || data == nullptr) {
         return AMEDIA_ERROR_INVALID_PARAMETER;
@@ -423,7 +423,7 @@
     return numSent;
 }
 
-media_status_t AMidiInputPort_sendFlush(const AMidiInputPort *inputPort) {
+media_status_t AMIDI_API AMidiInputPort_sendFlush(const AMidiInputPort *inputPort) {
     if (inputPort == nullptr) {
         return AMEDIA_ERROR_INVALID_PARAMETER;
     }
diff --git a/media/native/midi/include/amidi/AMidi.h b/media/native/midi/include/amidi/AMidi.h
index 76dec0f..0f930b5 100644
--- a/media/native/midi/include/amidi/AMidi.h
+++ b/media/native/midi/include/amidi/AMidi.h
@@ -37,6 +37,8 @@
 extern "C" {
 #endif
 
+#define AMIDI_API __attribute__((visibility("default")))
+
 typedef struct AMidiDevice AMidiDevice;
 typedef struct AMidiInputPort AMidiInputPort;
 typedef struct AMidiOutputPort AMidiOutputPort;
@@ -78,7 +80,7 @@
  *    is null or already connected to a native AMidiDevice
   *  @see AMEDIA_ERROR_UNKNOWN - an unknown error occurred.
  */
-media_status_t AMidiDevice_fromJava(
+media_status_t AMIDI_API AMidiDevice_fromJava(
         JNIEnv *env, jobject midiDeviceObj, AMidiDevice **outDevicePtrPtr) __INTRODUCED_IN(29);
 
 /**
@@ -93,7 +95,7 @@
  *  @see AMEDIA_ERROR_INVALID_OBJECT - the JNI interface initialization to the associated java MidiDevice failed.
  *  @see AMEDIA_ERROR_UNKNOWN - couldn't retrieve the device info.
  */
-media_status_t AMidiDevice_release(const AMidiDevice *midiDevice) __INTRODUCED_IN(29);
+media_status_t AMIDI_API AMidiDevice_release(const AMidiDevice *midiDevice) __INTRODUCED_IN(29);
 
 /**
  * Gets the MIDI device type.
@@ -108,7 +110,7 @@
  *  @see AMEDIA_ERROR_INVALID_PARAMETER - the device parameter is NULL.
  *  @see AMEDIA_ERROR_UNKNOWN - Unknown error.
  */
-int32_t AMidiDevice_getType(const AMidiDevice *device) __INTRODUCED_IN(29);
+int32_t AMIDI_API AMidiDevice_getType(const AMidiDevice *device) __INTRODUCED_IN(29);
 
 /**
  * Gets the number of input (sending) ports available on the specified MIDI device.
@@ -120,7 +122,7 @@
  *  @see AMEDIA_ERROR_INVALID_PARAMETER - the device parameter is NULL.
  *  @see AMEDIA_ERROR_UNKNOWN - couldn't retrieve the device info.
  */
-ssize_t AMidiDevice_getNumInputPorts(const AMidiDevice *device) __INTRODUCED_IN(29);
+ssize_t AMIDI_API AMidiDevice_getNumInputPorts(const AMidiDevice *device) __INTRODUCED_IN(29);
 
 /**
  * Gets the number of output (receiving) ports available on the specified MIDI device.
@@ -132,7 +134,7 @@
  *  @see AMEDIA_ERROR_INVALID_PARAMETER - the device parameter is NULL.
  *  @see AMEDIA_ERROR_UNKNOWN - couldn't retrieve the device info.
  */
-ssize_t AMidiDevice_getNumOutputPorts(const AMidiDevice *device) __INTRODUCED_IN(29);
+ssize_t AMIDI_API AMidiDevice_getNumOutputPorts(const AMidiDevice *device) __INTRODUCED_IN(29);
 
 /*
  * API for receiving data from the Output port of a device.
@@ -150,7 +152,7 @@
  * @return AMEDIA_OK, or a negative error code:
  *  @see AMEDIA_ERROR_UNKNOWN - Unknown Error.
  */
-media_status_t AMidiOutputPort_open(const AMidiDevice *device, int32_t portNumber,
+media_status_t AMIDI_API AMidiOutputPort_open(const AMidiDevice *device, int32_t portNumber,
                              AMidiOutputPort **outOutputPortPtr) __INTRODUCED_IN(29);
 
 /**
@@ -158,7 +160,7 @@
  *
  * @param outputPort    The native API port identifier of the port.
  */
-void AMidiOutputPort_close(const AMidiOutputPort *outputPort) __INTRODUCED_IN(29);
+void AMIDI_API AMidiOutputPort_close(const AMidiOutputPort *outputPort) __INTRODUCED_IN(29);
 
 /**
  * Receives the next pending MIDI message. To retrieve all pending messages, the client should
@@ -178,7 +180,7 @@
  * @return the number of messages received (either 0 or 1), or a negative error code:
  *  @see AMEDIA_ERROR_UNKNOWN - Unknown Error.
  */
-ssize_t AMidiOutputPort_receive(const AMidiOutputPort *outputPort, int32_t *opcodePtr,
+ssize_t AMIDI_API AMidiOutputPort_receive(const AMidiOutputPort *outputPort, int32_t *opcodePtr,
          uint8_t *buffer, size_t maxBytes, size_t* numBytesReceivedPtr, int64_t *outTimestampPtr) __INTRODUCED_IN(29);
 
 /*
@@ -197,7 +199,7 @@
  * @return AMEDIA_OK, or a negative error code:
  *  @see AMEDIA_ERROR_UNKNOWN - Unknown Error.
  */
-media_status_t AMidiInputPort_open(const AMidiDevice *device, int32_t portNumber,
+media_status_t AMIDI_API AMidiInputPort_open(const AMidiDevice *device, int32_t portNumber,
                             AMidiInputPort **outInputPortPtr) __INTRODUCED_IN(29);
 
 /**
@@ -210,7 +212,7 @@
  * @return The number of bytes sent, which could be less than specified or a negative error code:
  * @see AMEDIA_ERROR_INVALID_PARAMETER - The specified port was NULL, the specified buffer was NULL.
  */
-ssize_t AMidiInputPort_send(const AMidiInputPort *inputPort, const uint8_t *buffer,
+ssize_t AMIDI_API AMidiInputPort_send(const AMidiInputPort *inputPort, const uint8_t *buffer,
                    size_t numBytes) __INTRODUCED_IN(29);
 
 /**
@@ -224,7 +226,7 @@
  * @return The number of bytes sent, which could be less than specified or a negative error code:
  * @see AMEDIA_ERROR_INVALID_PARAMETER - The specified port was NULL, the specified buffer was NULL.
  */
-ssize_t AMidiInputPort_sendWithTimestamp(const AMidiInputPort *inputPort,
+ssize_t AMIDI_API AMidiInputPort_sendWithTimestamp(const AMidiInputPort *inputPort,
         const uint8_t *buffer, size_t numBytes, int64_t timestamp) __INTRODUCED_IN(29);
 
 /**
@@ -238,14 +240,14 @@
  * @see AMEDIA_ERROR_UNSUPPORTED - The FLUSH command couldn't
  * be sent.
  */
-media_status_t AMidiInputPort_sendFlush(const AMidiInputPort *inputPort) __INTRODUCED_IN(29);
+media_status_t AMIDI_API AMidiInputPort_sendFlush(const AMidiInputPort *inputPort) __INTRODUCED_IN(29);
 
 /**
  * Closes the input port.
  *
  * @param inputPort Identifies the input (sending) port to close.
  */
-void AMidiInputPort_close(const AMidiInputPort *inputPort) __INTRODUCED_IN(29);
+void AMIDI_API AMidiInputPort_close(const AMidiInputPort *inputPort) __INTRODUCED_IN(29);
 
 #endif /* __ANDROID_API__ >= 29 */
 
diff --git a/packages/CompanionDeviceManager/OWNERS b/packages/CompanionDeviceManager/OWNERS
new file mode 100644
index 0000000..da723b3
--- /dev/null
+++ b/packages/CompanionDeviceManager/OWNERS
@@ -0,0 +1 @@
+eugenesusla@google.com
\ No newline at end of file
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java
index d0ca04b..d11b5c5 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java
@@ -24,6 +24,7 @@
 import static com.android.internal.util.CollectionUtils.size;
 import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
 
+import android.annotation.MainThread;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.PendingIntent;
@@ -115,7 +116,8 @@
             }
             mFindCallback = findCallback;
             mServiceCallback = serviceCallback;
-            DeviceDiscoveryService.this.startDiscovery(request);
+            Handler.getMain().sendMessage(obtainMessage(
+                    DeviceDiscoveryService::startDiscovery, DeviceDiscoveryService.this, request));
         }
     };
 
@@ -145,6 +147,7 @@
         sInstance = this;
     }
 
+    @MainThread
     private void startDiscovery(AssociationRequest request) {
         if (!request.equals(mRequest)) {
             mRequest = request;
@@ -211,12 +214,13 @@
         return !isEmpty(mediumSpecificFilters) || isEmpty(mFilters);
     }
 
+    @MainThread
     private void reset() {
         if (DEBUG) Log.i(LOG_TAG, "reset()");
         stopScan();
         mDevicesFound.clear();
         mSelectedDevice = null;
-        notifyDataSetChanged();
+        mDevicesAdapter.notifyDataSetChanged();
     }
 
     @Override
@@ -260,16 +264,17 @@
 
         if (DEBUG) Log.i(LOG_TAG, "Found device " + device);
 
+        Handler.getMain().sendMessage(obtainMessage(
+                DeviceDiscoveryService::onDeviceFoundMainThread, this, device));
+    }
+
+    @MainThread
+    void onDeviceFoundMainThread(@NonNull DeviceFilterPair device) {
         if (mDevicesFound.isEmpty()) {
             onReadyToShowUI();
         }
         mDevicesFound.add(device);
-        notifyDataSetChanged();
-    }
-
-    private void notifyDataSetChanged() {
-        Handler.getMain().sendMessage(obtainMessage(
-                DevicesAdapter::notifyDataSetChanged, mDevicesAdapter));
+        mDevicesAdapter.notifyDataSetChanged();
     }
 
     //TODO also, on timeout -> call onFailure
@@ -286,9 +291,15 @@
     }
 
     private void onDeviceLost(@Nullable DeviceFilterPair device) {
-        mDevicesFound.remove(device);
-        notifyDataSetChanged();
         if (DEBUG) Log.i(LOG_TAG, "Lost device " + device.getDisplayName());
+        Handler.getMain().sendMessage(obtainMessage(
+                DeviceDiscoveryService::onDeviceLostMainThread, this, device));
+    }
+
+    @MainThread
+    void onDeviceLostMainThread(@Nullable DeviceFilterPair device) {
+        mDevicesFound.remove(device);
+        mDevicesAdapter.notifyDataSetChanged();
     }
 
     void onDeviceSelected(String callingPackage, String deviceAddress) {
diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
index e731b45..142078e 100644
--- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
+++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
@@ -291,7 +291,7 @@
         if (mInstallTask != null && mInstallTask.getResult() == RESULT_OK) {
             enabled = mInstallTask.commit();
         } else if (isDynamicSystemInstalled()) {
-            enabled = mDynSystem.setEnable(true);
+            enabled = mDynSystem.setEnable(true, true);
         } else {
             Log.e(TAG, "Trying to reboot to AOT while there is no complete installation");
             return;
diff --git a/packages/PrintSpooler/res/values-or/strings.xml b/packages/PrintSpooler/res/values-or/strings.xml
index 7eeac87..f385391 100644
--- a/packages/PrintSpooler/res/values-or/strings.xml
+++ b/packages/PrintSpooler/res/values-or/strings.xml
@@ -72,7 +72,7 @@
     <string name="select_to_add_printers" msgid="3800709038689830974">"ପ୍ରିଣ୍ଟର ଯୋଡ଼ିବାକୁ ଚୟନ କରନ୍ତୁ"</string>
     <string name="enable_print_service" msgid="3482815747043533842">"ସକ୍ଷମ କରିବା ପାଇଁ ଚୟନ କରନ୍ତୁ"</string>
     <string name="enabled_services_title" msgid="7036986099096582296">"ସକ୍ଷମ କରାଯାଇଥିବା ସର୍ଭିସ୍‌"</string>
-    <string name="recommended_services_title" msgid="3799434882937956924">"ସୁପାରିସ କରାଯାଇଥିବା ସର୍ଭିସ୍‌"</string>
+    <string name="recommended_services_title" msgid="3799434882937956924">"ସୁପାରିଶ କରାଯାଇଥିବା ସର୍ଭିସ୍‌"</string>
     <string name="disabled_services_title" msgid="7313253167968363211">"ଅକ୍ଷମ କରାଯାଇଥିବା ସର୍ଭିସ୍‌"</string>
     <string name="all_services_title" msgid="5578662754874906455">"ସମସ୍ତ ସର୍ଭିସ୍‌"</string>
     <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
diff --git a/packages/SettingsLib/Android.bp b/packages/SettingsLib/Android.bp
index b532621..7760e0e 100644
--- a/packages/SettingsLib/Android.bp
+++ b/packages/SettingsLib/Android.bp
@@ -23,6 +23,7 @@
         "SettingsLibBarChartPreference",
         "SettingsLibProgressBar",
         "SettingsLibAdaptiveIcon",
+        "SettingsLibRadioButtonPreference",
     ],
 
     // ANDROIDMK TRANSLATION ERROR: unsupported assignment to LOCAL_SHARED_JAVA_LIBRARIES
diff --git a/packages/SettingsLib/AppPreference/Android.bp b/packages/SettingsLib/AppPreference/Android.bp
index b56181d..b07176a 100644
--- a/packages/SettingsLib/AppPreference/Android.bp
+++ b/packages/SettingsLib/AppPreference/Android.bp
@@ -4,9 +4,10 @@
     srcs: ["src/**/*.java"],
     resource_dirs: ["res"],
 
-    libs: [
+    static_libs: [
         "androidx.annotation_annotation",
         "androidx.preference_preference",
+        "SettingsLibSettingsTheme",
     ],
     sdk_version: "system_current",
     min_sdk_version: "21",
diff --git a/packages/SettingsLib/EntityHeaderWidgets/Android.bp b/packages/SettingsLib/EntityHeaderWidgets/Android.bp
index 3ca4ecd..280848a 100644
--- a/packages/SettingsLib/EntityHeaderWidgets/Android.bp
+++ b/packages/SettingsLib/EntityHeaderWidgets/Android.bp
@@ -6,7 +6,7 @@
 
     static_libs: [
           "androidx.annotation_annotation",
-          "SettingsLibAppPreference"
+          "SettingsLibSettingsTheme"
     ],
 
     sdk_version: "system_current",
diff --git a/packages/SettingsLib/RadioButtonPreference/Android.bp b/packages/SettingsLib/RadioButtonPreference/Android.bp
new file mode 100644
index 0000000..136d6da
--- /dev/null
+++ b/packages/SettingsLib/RadioButtonPreference/Android.bp
@@ -0,0 +1,14 @@
+android_library {
+    name: "SettingsLibRadioButtonPreference",
+
+    srcs: ["src/**/*.java"],
+    resource_dirs: ["res"],
+
+    static_libs: [
+          "androidx.preference_preference",
+          "SettingsLibSettingsTheme",
+    ],
+
+    sdk_version: "system_current",
+    min_sdk_version: "21",
+}
diff --git a/packages/SettingsLib/AppPreference/res/values/dimens.xml b/packages/SettingsLib/RadioButtonPreference/AndroidManifest.xml
similarity index 70%
copy from packages/SettingsLib/AppPreference/res/values/dimens.xml
copy to packages/SettingsLib/RadioButtonPreference/AndroidManifest.xml
index e2a7a19..fda7fde 100644
--- a/packages/SettingsLib/AppPreference/res/values/dimens.xml
+++ b/packages/SettingsLib/RadioButtonPreference/AndroidManifest.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-  Copyright (C) 2018 The Android Open Source Project
+  Copyright (C) 2019 The Android Open Source Project
 
   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
@@ -13,8 +13,11 @@
   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.
-  -->
+-->
 
-<resources>
-    <dimen name="secondary_app_icon_size">32dp</dimen>
-</resources>
\ No newline at end of file
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="com.android.settingslib.widget">
+
+    <uses-sdk android:minSdkVersion="21" />
+
+</manifest>
diff --git a/packages/SettingsLib/RadioButtonPreference/res/layout/preference_radio.xml b/packages/SettingsLib/RadioButtonPreference/res/layout/preference_radio.xml
new file mode 100644
index 0000000..b4b4c63
--- /dev/null
+++ b/packages/SettingsLib/RadioButtonPreference/res/layout/preference_radio.xml
@@ -0,0 +1,107 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  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.
+  -->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:settings="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:background="?android:attr/selectableItemBackground"
+    android:gravity="center_vertical"
+    android:minHeight="?android:attr/listPreferredItemHeightSmall"
+    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
+
+    <LinearLayout
+        android:id="@android:id/widget_frame"
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent"
+        android:gravity="center"
+        android:minWidth="56dp"
+        android:layout_marginEnd="16dp"
+        android:orientation="vertical"/>
+
+    <LinearLayout
+        android:id="@+id/icon_frame"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:gravity="center_vertical"
+        android:minWidth="32dp"
+        android:orientation="horizontal"
+        android:layout_marginEnd="16dp"
+        android:paddingTop="4dp"
+        android:paddingBottom="4dp">
+        <androidx.preference.internal.PreferenceImageView
+            android:id="@android:id/icon"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            settings:maxWidth="@dimen/secondary_app_icon_size"
+            settings:maxHeight="@dimen/secondary_app_icon_size"/>
+    </LinearLayout>
+
+    <LinearLayout
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_weight="1"
+        android:orientation="vertical"
+        android:paddingTop="16dp"
+        android:paddingBottom="16dp">
+
+        <TextView
+            android:id="@android:id/title"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:singleLine="true"
+            android:textAppearance="?android:attr/textAppearanceListItem"
+            android:ellipsize="marquee"
+            android:fadingEdge="horizontal"/>
+
+        <LinearLayout
+            android:id="@+id/summary_container"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:visibility="gone">
+            <TextView
+                android:id="@android:id/summary"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_weight="1"
+                android:textAppearance="?android:attr/textAppearanceSmall"
+                android:textAlignment="viewStart"
+                android:textColor="?android:attr/textColorSecondary"/>
+
+            <TextView
+                android:id="@+id/appendix"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_weight="1"
+                android:textAppearance="?android:attr/textAppearanceSmall"
+                android:textAlignment="viewEnd"
+                android:textColor="?android:attr/textColorSecondary"
+                android:maxLines="1"
+                android:ellipsize="end"/>
+        </LinearLayout>
+        <ProgressBar
+            android:id="@android:id/progress"
+            style="?android:attr/progressBarStyleHorizontal"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="4dp"
+            android:max="100"
+            android:visibility="gone"/>
+    </LinearLayout>
+
+</LinearLayout>
diff --git a/packages/SettingsLib/AppPreference/res/values/dimens.xml b/packages/SettingsLib/RadioButtonPreference/res/layout/preference_widget_radiobutton.xml
similarity index 60%
copy from packages/SettingsLib/AppPreference/res/values/dimens.xml
copy to packages/SettingsLib/RadioButtonPreference/res/layout/preference_widget_radiobutton.xml
index e2a7a19..cb7b8eb 100644
--- a/packages/SettingsLib/AppPreference/res/values/dimens.xml
+++ b/packages/SettingsLib/RadioButtonPreference/res/layout/preference_widget_radiobutton.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-  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.
@@ -15,6 +15,11 @@
   limitations under the License.
   -->
 
-<resources>
-    <dimen name="secondary_app_icon_size">32dp</dimen>
-</resources>
\ No newline at end of file
+<RadioButton xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@android:id/checkbox"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:layout_gravity="center"
+    android:background="@null"
+    android:focusable="false"
+    android:clickable="false" />
diff --git a/packages/SettingsLib/RadioButtonPreference/src/com/android/settingslib/widget/RadioButtonPreference.java b/packages/SettingsLib/RadioButtonPreference/src/com/android/settingslib/widget/RadioButtonPreference.java
new file mode 100644
index 0000000..05e008c
--- /dev/null
+++ b/packages/SettingsLib/RadioButtonPreference/src/com/android/settingslib/widget/RadioButtonPreference.java
@@ -0,0 +1,163 @@
+/*
+ * 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.settingslib.widget;
+
+import android.content.Context;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.TextView;
+
+import androidx.preference.CheckBoxPreference;
+import androidx.preference.PreferenceViewHolder;
+
+/**
+ * Check box preference with check box replaced by radio button.
+ *
+ * Functionally speaking, it's actually a CheckBoxPreference. We only modified
+ * the widget to RadioButton to make it "look like" a RadioButtonPreference.
+ *
+ * In other words, there's no "RadioButtonPreferenceGroup" in this
+ * implementation. When you check one RadioButtonPreference, if you want to
+ * uncheck all the other preferences, you should do that by code yourself.
+ */
+public class RadioButtonPreference extends CheckBoxPreference {
+
+    /**
+     * Interface definition for a callback to be invoked when the preference is clicked.
+     */
+    public interface OnClickListener {
+        /**
+         * Called when a preference has been clicked.
+         *
+         * @param emiter The clicked preference
+         */
+        void onRadioButtonClicked(RadioButtonPreference emiter);
+    }
+
+    private OnClickListener mListener = null;
+    private View mAppendix;
+    private int mAppendixVisibility = -1;
+
+
+    /**
+     * Perform inflation from XML and apply a class-specific base style.
+     *
+     * @param context  The {@link Context} this is associated with, through which it can
+     *                 access the current theme, resources, {@link SharedPreferences}, etc.
+     * @param attrs    The attributes of the XML tag that is inflating the preference
+     * @param defStyle An attribute in the current theme that contains a reference to a style
+     *                 resource that supplies default values for the view. Can be 0 to not
+     *                 look for defaults.
+     */
+    public RadioButtonPreference(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+        init();
+    }
+
+
+    /**
+     * Perform inflation from XML and apply a class-specific base style.
+     *
+     * @param context The {@link Context} this is associated with, through which it can
+     *                access the current theme, resources, {@link SharedPreferences}, etc.
+     * @param attrs   The attributes of the XML tag that is inflating the preference
+     */
+    public RadioButtonPreference(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        init();
+    }
+
+    /**
+     * Constructor to create a preference.
+     *
+     * @param context The Context this is associated with.
+     */
+    public RadioButtonPreference(Context context) {
+        this(context, null);
+    }
+
+    /**
+     * Sets the callback to be invoked when this preference is clicked by the user.
+     *
+     * @param listener The callback to be invoked
+     */
+    public void setOnClickListener(OnClickListener listener) {
+        mListener = listener;
+    }
+
+    /**
+     * Processes a click on the preference.
+     */
+    @Override
+    public void onClick() {
+        if (mListener != null) {
+            mListener.onRadioButtonClicked(this);
+        }
+    }
+
+    /**
+     * Binds the created View to the data for this preference.
+     *
+     * <p>This is a good place to grab references to custom Views in the layout and set
+     * properties on them.
+     *
+     * <p>Make sure to call through to the superclass's implementation.
+     *
+     * @param holder The ViewHolder that provides references to the views to fill in. These views
+     *               will be recycled, so you should not hold a reference to them after this method
+     *               returns.
+     */
+    @Override
+    public void onBindViewHolder(PreferenceViewHolder holder) {
+        super.onBindViewHolder(holder);
+
+        View summaryContainer = holder.findViewById(R.id.summary_container);
+        if (summaryContainer != null) {
+            summaryContainer.setVisibility(
+                    TextUtils.isEmpty(getSummary()) ? View.GONE : View.VISIBLE);
+            mAppendix = holder.findViewById(R.id.appendix);
+            if (mAppendix != null && mAppendixVisibility != -1) {
+                mAppendix.setVisibility(mAppendixVisibility);
+            }
+        }
+
+        TextView title = (TextView) holder.findViewById(android.R.id.title);
+        if (title != null) {
+            title.setSingleLine(false);
+            title.setMaxLines(3);
+        }
+    }
+
+    /**
+     * Set the visibility state of appendix view.
+     *
+     * @param visibility One of {@link View#VISIBLE}, {@link View#INVISIBLE}, or {@link View#GONE}.
+     */
+    public void setAppendixVisibility(int visibility) {
+        if (mAppendix != null) {
+            mAppendix.setVisibility(visibility);
+        }
+        mAppendixVisibility = visibility;
+    }
+
+    private void init() {
+        setWidgetLayoutResource(R.layout.preference_widget_radiobutton);
+        setLayoutResource(R.layout.preference_radio);
+        setIconSpaceReserved(false);
+    }
+}
diff --git a/packages/SettingsLib/SettingsTheme/Android.bp b/packages/SettingsLib/SettingsTheme/Android.bp
new file mode 100644
index 0000000..6d505bf
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/Android.bp
@@ -0,0 +1,8 @@
+android_library {
+    name: "SettingsLibSettingsTheme",
+
+    resource_dirs: ["res"],
+
+    sdk_version: "system_current",
+    min_sdk_version: "21",
+}
diff --git a/packages/SettingsLib/AppPreference/res/values/dimens.xml b/packages/SettingsLib/SettingsTheme/AndroidManifest.xml
similarity index 70%
copy from packages/SettingsLib/AppPreference/res/values/dimens.xml
copy to packages/SettingsLib/SettingsTheme/AndroidManifest.xml
index e2a7a19..fda7fde 100644
--- a/packages/SettingsLib/AppPreference/res/values/dimens.xml
+++ b/packages/SettingsLib/SettingsTheme/AndroidManifest.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-  Copyright (C) 2018 The Android Open Source Project
+  Copyright (C) 2019 The Android Open Source Project
 
   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
@@ -13,8 +13,11 @@
   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.
-  -->
+-->
 
-<resources>
-    <dimen name="secondary_app_icon_size">32dp</dimen>
-</resources>
\ No newline at end of file
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="com.android.settingslib.widget">
+
+    <uses-sdk android:minSdkVersion="21" />
+
+</manifest>
diff --git a/packages/SettingsLib/AppPreference/res/values/dimens.xml b/packages/SettingsLib/SettingsTheme/res/values/dimens.xml
similarity index 92%
rename from packages/SettingsLib/AppPreference/res/values/dimens.xml
rename to packages/SettingsLib/SettingsTheme/res/values/dimens.xml
index e2a7a19..9485655 100644
--- a/packages/SettingsLib/AppPreference/res/values/dimens.xml
+++ b/packages/SettingsLib/SettingsTheme/res/values/dimens.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-  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.
@@ -17,4 +17,4 @@
 
 <resources>
     <dimen name="secondary_app_icon_size">32dp</dimen>
-</resources>
\ No newline at end of file
+</resources>
diff --git a/packages/SettingsLib/src/com/android/settingslib/widget/FooterPreference.java b/packages/SettingsLib/src/com/android/settingslib/widget/FooterPreference.java
index 7100acc..e48becf 100644
--- a/packages/SettingsLib/src/com/android/settingslib/widget/FooterPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/widget/FooterPreference.java
@@ -16,12 +16,14 @@
 
 package com.android.settingslib.widget;
 
+import android.annotation.StringRes;
 import android.content.Context;
 import android.text.TextUtils;
 import android.text.method.LinkMovementMethod;
 import android.util.AttributeSet;
 import android.widget.TextView;
 
+import androidx.annotation.NonNull;
 import androidx.core.content.res.TypedArrayUtils;
 import androidx.preference.Preference;
 import androidx.preference.PreferenceViewHolder;
@@ -72,10 +74,67 @@
     }
 
     private void init() {
-        setIcon(R.drawable.ic_info_outline_24);
+        if (getIcon() == null) {
+            setIcon(R.drawable.ic_info_outline_24);
+        }
         setOrder(ORDER_FOOTER);
         if (TextUtils.isEmpty(getKey())) {
             setKey(KEY_FOOTER);
         }
     }
+
+    /**
+     * The builder is convenient to creat a dynamic FooterPreference.
+     */
+    public static class Builder {
+        private Context mContext;
+        private String mKey;
+        private CharSequence mTitle;
+
+        public Builder(@NonNull Context context) {
+            mContext = context;
+        }
+
+        /**
+         * To set the key value of the {@link FooterPreference}.
+         * @param key The key value.
+         */
+        public Builder setKey(String key) {
+            mKey = key;
+            return this;
+        }
+
+        /**
+         * To set the title of the {@link FooterPreference}.
+         * @param title The title.
+         */
+        public Builder setTitle(CharSequence title) {
+            mTitle = title;
+            return this;
+        }
+
+        /**
+         * To set the title of the {@link FooterPreference}.
+         * @param titleResId The resource id of the title.
+         */
+        public Builder setTitle(@StringRes int titleResId) {
+            mTitle = mContext.getText(titleResId);
+            return this;
+        }
+
+        /**
+         * To generate the {@link FooterPreference}.
+         */
+        public FooterPreference build() {
+            final FooterPreference footerPreference = new FooterPreference(mContext);
+            footerPreference.setSelectable(false);
+            if (!TextUtils.isEmpty(mKey)) {
+                footerPreference.setKey(mKey);
+            }
+            if (!TextUtils.isEmpty(mTitle)) {
+                footerPreference.setTitle(mTitle);
+            }
+            return footerPreference;
+        }
+    }
 }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/RadioButtonPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/RadioButtonPreferenceTest.java
new file mode 100644
index 0000000..d58e68a
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/RadioButtonPreferenceTest.java
@@ -0,0 +1,103 @@
+/*
+ * 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.settingslib.widget;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.app.Application;
+import android.view.LayoutInflater;
+import android.view.View;
+
+import androidx.preference.PreferenceViewHolder;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(RobolectricTestRunner.class)
+public class RadioButtonPreferenceTest {
+
+    private Application mContext;
+    private RadioButtonPreference mPreference;
+
+    @Before
+    public void setUp() {
+        mContext = RuntimeEnvironment.application;
+        mPreference = new RadioButtonPreference(mContext);
+    }
+
+    @Test
+    public void shouldHaveRadioPreferenceLayout() {
+        assertThat(mPreference.getLayoutResource()).isEqualTo(R.layout.preference_radio);
+    }
+
+    @Test
+    public void iconSpaceReservedShouldBeFalse() {
+        assertThat(mPreference.isIconSpaceReserved()).isFalse();
+    }
+
+    @Test
+    public void summary_containerShouldBeVisible() {
+        mPreference.setSummary("some summary");
+        View summaryContainer = new View(mContext);
+        View view = mock(View.class);
+        when(view.findViewById(R.id.summary_container)).thenReturn(summaryContainer);
+        PreferenceViewHolder preferenceViewHolder =
+                PreferenceViewHolder.createInstanceForTests(view);
+        mPreference.onBindViewHolder(preferenceViewHolder);
+        assertEquals(View.VISIBLE, summaryContainer.getVisibility());
+    }
+
+    @Test
+    public void emptySummary_containerShouldBeGone() {
+        mPreference.setSummary("");
+        View summaryContainer = new View(mContext);
+        View view = mock(View.class);
+        when(view.findViewById(R.id.summary_container)).thenReturn(summaryContainer);
+        PreferenceViewHolder preferenceViewHolder =
+                PreferenceViewHolder.createInstanceForTests(view);
+        mPreference.onBindViewHolder(preferenceViewHolder);
+        assertEquals(View.GONE, summaryContainer.getVisibility());
+    }
+
+    @Test
+    public void nullSummary_containerShouldBeGone() {
+        mPreference.setSummary(null);
+        View summaryContainer = new View(mContext);
+        View view = mock(View.class);
+        when(view.findViewById(R.id.summary_container)).thenReturn(summaryContainer);
+        PreferenceViewHolder preferenceViewHolder =
+                PreferenceViewHolder.createInstanceForTests(view);
+        mPreference.onBindViewHolder(preferenceViewHolder);
+        assertEquals(View.GONE, summaryContainer.getVisibility());
+    }
+
+    @Test
+    public void hideAppendix_shouldBeGone() {
+        mPreference.setAppendixVisibility(View.GONE);
+        View view = LayoutInflater.from(mContext).inflate(R.layout.preference_radio, null);
+        PreferenceViewHolder holder = PreferenceViewHolder.createInstanceForTests(view);
+        mPreference.onBindViewHolder(holder);
+        assertThat(holder.findViewById(R.id.appendix).getVisibility()).isEqualTo(View.GONE);
+    }
+}
diff --git a/packages/SettingsProvider/AndroidManifest.xml b/packages/SettingsProvider/AndroidManifest.xml
index 9bc2d75..839899e 100644
--- a/packages/SettingsProvider/AndroidManifest.xml
+++ b/packages/SettingsProvider/AndroidManifest.xml
@@ -11,6 +11,7 @@
                  android:restoreAnyVersion="true"
                  android:icon="@mipmap/ic_launcher_settings"
                  android:defaultToDeviceProtectedStorage="true"
+                 android:forceQueryable="true"
                  android:directBootAware="true">
 
         <provider android:name="SettingsProvider"
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 8689eef..bb9a5e4 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -123,7 +123,6 @@
     <uses-permission android:name="android.permission.BIND_APPWIDGET" />
     <uses-permission android:name="android.permission.UPDATE_APP_OPS_STATS" />
     <uses-permission android:name="android.permission.MODIFY_APPWIDGET_BIND_PERMISSIONS"/>
-    <uses-permission android:name="android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS" />
     <uses-permission android:name="android.permission.CHANGE_APP_IDLE_STATE" />
     <uses-permission android:name="android.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST" />
     <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java
index 2727880..58e1d47 100644
--- a/packages/Shell/src/com/android/shell/BugreportProgressService.java
+++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java
@@ -199,9 +199,9 @@
     // Passed to Message.obtain() when msg.arg2 is not used.
     private static final int UNUSED_ARG2 = -2;
 
-    // Maximum progress displayed (like 99.00%).
-    private static final int CAPPED_PROGRESS = 9900;
-    private static final int CAPPED_MAX = 10000;
+    // Maximum progress displayed in %.
+    private static final int CAPPED_PROGRESS = 99;
+    private static final int CAPPED_MAX = 100;
 
     /** Show the progress log every this percent. */
     private static final int LOG_PROGRESS_STEP = 10;
@@ -582,9 +582,9 @@
         ParcelFileDescriptor screenshotFd = createReadWriteFile(BUGREPORT_DIR,
                 bugreportName + ".png");
         if (screenshotFd == null) {
-            Log.e(TAG, "Screenshot parcel file descriptor is null.");
-            // TODO(b/123617758): Delete bugreport file created above
+            Log.e(TAG, "Screenshot parcel file descriptor is null. Deleting bugreport file");
             FileUtils.closeQuietly(bugreportFd);
+            new File(BUGREPORT_DIR, String.format("%s.zip", bugreportName)).delete();
             return;
         }
         mBugreportManager = (BugreportManager) mContext.getSystemService(
@@ -972,18 +972,8 @@
     private void onBugreportFinished(int id) {
         BugreportInfo info = getInfo(id);
         final File bugreportFile = new File(BUGREPORT_DIR, info.name + ".zip");
-        if (bugreportFile == null) {
-            // Should never happen, an id always has a file linked to it.
-            Log.wtf(TAG, "Missing file " + bugreportFile.getPath() + " does not exist.");
-            return;
-        }
         final int max = -1; // this is to log metrics for dumpstate duration.
         File screenshotFile = new File(BUGREPORT_DIR, info.name + ".png");
-        if (screenshotFile == null) {
-            // Should never happen, an id always has a file linked to it.
-            Log.wtf(TAG, "Missing file " + screenshotFile.getPath() + " does not exist.");
-            return;
-        }
         // If the screenshot file did not get populated implies this type of bugreport does not
         // need the screenshot file; setting the file to null so that empty file doesnt get shared
         if (screenshotFile.length() == 0) {
@@ -2164,8 +2154,7 @@
 
         @Override
         public void onProgress(int progress) throws RemoteException {
-            updateProgressInfo(info, progress, 100 /* progress is already a percentage;
-                    so max = 100 */);
+            checkProgressUpdated(info, progress);
         }
 
         @Override
@@ -2178,26 +2167,6 @@
             // TODO(b/111441001): implement
         }
 
-        @Override
-        public void onProgressUpdated(int progress) throws RemoteException {
-            checkProgressUpdated(info, progress);
-        }
-
-        @Override
-        public void onMaxProgressUpdated(int maxProgress) throws RemoteException {
-            Log.d(TAG, "onMaxProgressUpdated: " + maxProgress);
-            info.realMax = maxProgress;
-        }
-
-        @Override
-        public void onSectionComplete(String title, int status, int size, int durationMs)
-                throws RemoteException {
-            if (DEBUG) {
-                Log.v(TAG, "Title: " + title + " Status: " + status + " Size: " + size
-                        + " Duration: " + durationMs + "ms");
-            }
-        }
-
         public void dump(String prefix, PrintWriter pw) {
             pw.print(prefix); pw.print("token: "); pw.println(token);
         }
@@ -2205,27 +2174,10 @@
     }
 
     private void checkProgressUpdated(BugreportInfo info, int progress) {
-        /*
-         * Checks whether the progress changed in a way that should be displayed to the user:
-         * - info.progress / info.max represents the displayed progress
-         * - info.realProgress / info.realMax represents the real progress
-         * - since the real progress can decrease, the displayed progress is only updated if it
-         *   increases
-         * - the displayed progress is capped at a maximum (like 99%)
-         */
-        info.realProgress = progress;
-        final int oldPercentage = (CAPPED_MAX * info.progress) / info.max;
-        int newPercentage = (CAPPED_MAX * info.realProgress) / info.realMax;
-        int max = info.realMax;
-
-        if (newPercentage > CAPPED_PROGRESS) {
-            progress = newPercentage = CAPPED_PROGRESS;
-            max = CAPPED_MAX;
+        if (progress > CAPPED_PROGRESS) {
+            progress = CAPPED_PROGRESS;
         }
-
-        if (progress == 0 || newPercentage > oldPercentage) {
-            updateProgressInfo(info, progress, max);
-        }
+        updateProgressInfo(info, progress, CAPPED_MAX);
     }
 
     private void updateProgressInfo(BugreportInfo info, int progress, int max) {
diff --git a/packages/SystemUI/res-keyguard/values-de/strings.xml b/packages/SystemUI/res-keyguard/values-de/strings.xml
index 7f39a19..d44bfbc 100644
--- a/packages/SystemUI/res-keyguard/values-de/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-de/strings.xml
@@ -152,6 +152,6 @@
       <item quantity="one">Die SIM-Karte ist jetzt deaktiviert. Gib den PUK-Code ein, um fortzufahren. Du hast noch <xliff:g id="_NUMBER_0">%d</xliff:g> Versuch, bevor die SIM-Karte endgültig gesperrt wird. Weitere Informationen erhältst du von deinem Mobilfunkanbieter.</item>
     </plurals>
     <string name="clock_title_default" msgid="6645600990069154049">"Standard"</string>
-    <string name="clock_title_bubble" msgid="1286365278681892114">"Blase"</string>
+    <string name="clock_title_bubble" msgid="1286365278681892114">"Bubble"</string>
     <string name="clock_title_analog" msgid="4047401488577315053">"Analog"</string>
 </resources>
diff --git a/packages/SystemUI/res/layout/keyguard_bottom_area.xml b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
index 21c2c6b..1bfc4c0 100644
--- a/packages/SystemUI/res/layout/keyguard_bottom_area.xml
+++ b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
@@ -24,48 +24,7 @@
     android:outlineProvider="none"
     android:elevation="5dp" > <!-- Put it above the status bar header -->
 
-    <LinearLayout
-        android:id="@+id/keyguard_indication_area"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_marginBottom="@dimen/keyguard_indication_margin_bottom"
-        android:layout_gravity="bottom|center_horizontal"
-        android:orientation="horizontal">
-
-        <include layout="@layout/left_docked_overlay" />
-
-        <LinearLayout
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_weight="1"
-            android:layout_gravity="center_vertical|center_horizontal"
-            android:orientation="vertical">
-
-            <com.android.systemui.statusbar.phone.KeyguardIndicationTextView
-                android:id="@+id/keyguard_indication_enterprise_disclosure"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:gravity="center"
-                android:paddingStart="@dimen/keyguard_indication_text_padding"
-                android:paddingEnd="@dimen/keyguard_indication_text_padding"
-                android:textAppearance="@style/TextAppearance.Keyguard.BottomArea"
-                android:visibility="gone" />
-
-            <com.android.systemui.statusbar.phone.KeyguardIndicationTextView
-                android:id="@+id/keyguard_indication_text"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:gravity="center"
-                android:paddingStart="@dimen/keyguard_indication_text_padding"
-                android:paddingEnd="@dimen/keyguard_indication_text_padding"
-                android:textAppearance="@style/TextAppearance.Keyguard.BottomArea"
-                android:accessibilityLiveRegion="polite" />
-
-        </LinearLayout>
-
-        <include layout="@layout/right_docked_overlay" />
-
-    </LinearLayout>
+    <include layout="@layout/keyguard_indication_area_overlay" />
 
     <FrameLayout
         android:id="@+id/preview_container"
diff --git a/packages/SystemUI/res/layout/keyguard_indication_area_overlay.xml b/packages/SystemUI/res/layout/keyguard_indication_area_overlay.xml
new file mode 100644
index 0000000..cc30a68
--- /dev/null
+++ b/packages/SystemUI/res/layout/keyguard_indication_area_overlay.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/keyguard_indication_area"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:layout_marginBottom="@dimen/keyguard_indication_margin_bottom"
+    android:layout_gravity="bottom|center_horizontal"
+    android:orientation="vertical">
+
+  <include layout="@layout/keyguard_indication_text_view" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/keyguard_indication_text_view.xml b/packages/SystemUI/res/layout/keyguard_indication_text_view.xml
new file mode 100644
index 0000000..2b2100c
--- /dev/null
+++ b/packages/SystemUI/res/layout/keyguard_indication_text_view.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <com.android.systemui.statusbar.phone.KeyguardIndicationTextView
+        android:id="@+id/keyguard_indication_enterprise_disclosure"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:gravity="center"
+        android:paddingStart="@dimen/keyguard_indication_text_padding"
+        android:paddingEnd="@dimen/keyguard_indication_text_padding"
+        android:textAppearance="@style/TextAppearance.Keyguard.BottomArea"
+        android:visibility="gone"/>
+
+    <com.android.systemui.statusbar.phone.KeyguardIndicationTextView
+        android:id="@+id/keyguard_indication_text"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:gravity="center"
+        android:paddingStart="@dimen/keyguard_indication_text_padding"
+        android:paddingEnd="@dimen/keyguard_indication_text_padding"
+        android:textAppearance="@style/TextAppearance.Keyguard.BottomArea"
+        android:accessibilityLiveRegion="polite"/>
+</merge>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/left_docked_overlay.xml b/packages/SystemUI/res/layout/left_docked_overlay.xml
deleted file mode 100644
index 430143c..0000000
--- a/packages/SystemUI/res/layout/left_docked_overlay.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ 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.
-  -->
-
-<!-- empty stub -->
-<merge />
diff --git a/packages/SystemUI/res/layout/right_docked_overlay.xml b/packages/SystemUI/res/layout/right_docked_overlay.xml
deleted file mode 100644
index 430143c..0000000
--- a/packages/SystemUI/res/layout/right_docked_overlay.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ 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.
-  -->
-
-<!-- empty stub -->
-<merge />
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 08fb0b3..90ead35 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -255,8 +255,8 @@
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Lommelygten er tændt."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Lommelygten er slukket."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Lommelygten er tændt."</string>
-    <string name="accessibility_quick_settings_color_inversion_changed_off" msgid="4406577213290173911">"Invertering af farver er slået fra."</string>
-    <string name="accessibility_quick_settings_color_inversion_changed_on" msgid="6897462320184911126">"Invertering af farver er slået til."</string>
+    <string name="accessibility_quick_settings_color_inversion_changed_off" msgid="4406577213290173911">"Ombytning af farver er slået fra."</string>
+    <string name="accessibility_quick_settings_color_inversion_changed_on" msgid="6897462320184911126">"Ombytning af farver er slået til."</string>
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="5004708003447561394">"Mobilhotspot er slået fra."</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Mobilhotspot er slået til."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Casting af din skærm er stoppet."</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 408254f..9b3974b 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -656,7 +656,7 @@
     <string name="notification_silence_title" msgid="5763240612242137433">"Lautlos"</string>
     <string name="notification_alert_title" msgid="8031196611815490340">"Benachrichtigen"</string>
     <string name="notification_channel_summary_low" msgid="3387466082089715555">"Benachrichtigungen werden ohne Ton oder Vibration angekündigt, um deine Konzentration nicht zu stören."</string>
-    <string name="notification_channel_summary_default" msgid="5994062840431965586">"Benachrichtigungen werden mit einem Ton oder einer Vibration angekündigt, um dich auf sie aufmerksam zu machen."</string>
+    <string name="notification_channel_summary_default" msgid="5994062840431965586">"Benachrichtigungen werden mit einem Ton oder einer Vibration angekündigt."</string>
     <string name="notification_unblockable_desc" msgid="4556908766584964102">"Diese Benachrichtigungen können nicht geändert werden."</string>
     <string name="notification_multichannel_desc" msgid="4695920306092240550">"Die Benachrichtigungsgruppe kann hier nicht konfiguriert werden"</string>
     <string name="notification_delegate_header" msgid="2857691673814814270">"Weitergeleitete Benachrichtigung"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 37aae55..d6c8d09 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -553,7 +553,7 @@
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Ocultar"</string>
     <string name="stream_voice_call" msgid="4410002696470423714">"Llamada"</string>
     <string name="stream_system" msgid="7493299064422163147">"Sistema"</string>
-    <string name="stream_ring" msgid="8213049469184048338">"Hacer sonar"</string>
+    <string name="stream_ring" msgid="8213049469184048338">"Timbre"</string>
     <string name="stream_music" msgid="9086982948697544342">"Multimedia"</string>
     <string name="stream_alarm" msgid="5209444229227197703">"Alarma"</string>
     <string name="stream_notification" msgid="2563720670905665031">"Notificación"</string>
@@ -561,7 +561,7 @@
     <string name="stream_dtmf" msgid="2447177903892477915">"Multifrecuencia de tono doble"</string>
     <string name="stream_accessibility" msgid="301136219144385106">"Accesibilidad"</string>
     <string name="ring_toggle_title" msgid="3281244519428819576">"Llamadas"</string>
-    <string name="volume_ringer_status_normal" msgid="4273142424125855384">"Hacer sonar"</string>
+    <string name="volume_ringer_status_normal" msgid="4273142424125855384">"Timbre"</string>
     <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"Vibrar"</string>
     <string name="volume_ringer_status_silent" msgid="6896394161022916369">"Silenciar"</string>
     <string name="qs_status_phone_vibrate" msgid="204362991135761679">"Teléfono en vibración"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index a3069a1..552d12e 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -886,7 +886,7 @@
     <string name="qs_dnd_prompt_app" msgid="7978037419334156034">"Le mode Ne pas déranger a été activé par une application (<xliff:g id="ID_1">%s</xliff:g>)."</string>
     <string name="qs_dnd_prompt_auto_rule_app" msgid="2599343675391111951">"Le mode Ne pas déranger a été activé par une règle automatique ou une application."</string>
     <string name="qs_dnd_until" msgid="3469471136280079874">"Jusqu\'à <xliff:g id="ID_1">%s</xliff:g>"</string>
-    <string name="qs_dnd_keep" msgid="1825009164681928736">"Garder"</string>
+    <string name="qs_dnd_keep" msgid="1825009164681928736">"Conserver"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"Remplacer"</string>
     <string name="running_foreground_services_title" msgid="381024150898615683">"Applications qui fonctionnent en arrière-plan"</string>
     <string name="running_foreground_services_msg" msgid="6326247670075574355">"Touchez pour afficher des détails sur l\'utilisation de la pile et des données"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 263fe8a..3fa2a48 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -46,8 +46,8 @@
     <string name="bluetooth_tethered" msgid="7094101612161133267">"ब्लूटूथ टीदर किया गया"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"इनपुट का तरीका सेट करें"</string>
     <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"सामान्य कीबोर्ड"</string>
-    <string name="usb_device_permission_prompt" msgid="1825685909587559679">"<xliff:g id="APPLICATION">%1$s</xliff:g> को <xliff:g id="USB_DEVICE">%2$s</xliff:g> के एक्सेस की अनुमति दें?"</string>
-    <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"<xliff:g id="APPLICATION">%1$s</xliff:g> को <xliff:g id="USB_ACCESSORY">%2$s</xliff:g> के एक्सेस की अनुमति दें?"</string>
+    <string name="usb_device_permission_prompt" msgid="1825685909587559679">"<xliff:g id="APPLICATION">%1$s</xliff:g> को <xliff:g id="USB_DEVICE">%2$s</xliff:g> के ऐक्सेस की अनुमति दें?"</string>
+    <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"<xliff:g id="APPLICATION">%1$s</xliff:g> को <xliff:g id="USB_ACCESSORY">%2$s</xliff:g> के ऐक्सेस की अनुमति दें?"</string>
     <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> के लिए <xliff:g id="APPLICATION">%1$s</xliff:g> खोलें?"</string>
     <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"<xliff:g id="USB_ACCESSORY">%2$s</xliff:g> के लिए <xliff:g id="APPLICATION">%1$s</xliff:g> खोलें?"</string>
     <string name="usb_accessory_uri_prompt" msgid="513450621413733343">"इस USB सहायक डिवाइस के साथ कोई भी इंस्टॉल ऐप्स  काम नहीं करता. इस सहायक डिवाइस के बारे में यहां ज़्यादा जानें: <xliff:g id="URL">%1$s</xliff:g>"</string>
@@ -205,7 +205,7 @@
     <string name="accessibility_overflow_action" msgid="5681882033274783311">"पूरी सूचनाएं देखें"</string>
     <string name="accessibility_remove_notification" msgid="3603099514902182350">"सूचना साफ़ करें"</string>
     <string name="accessibility_gps_enabled" msgid="3511469499240123019">"GPS सक्षम."</string>
-    <string name="accessibility_gps_acquiring" msgid="8959333351058967158">"GPS प्राप्त करना."</string>
+    <string name="accessibility_gps_acquiring" msgid="8959333351058967158">"GPS पाना."</string>
     <string name="accessibility_tty_enabled" msgid="4613200365379426561">"टेलीटाइपराइटर सक्षम."</string>
     <string name="accessibility_ringer_vibrate" msgid="666585363364155055">"रिंगर कंपन (वाइब्रेशन)."</string>
     <string name="accessibility_ringer_silent" msgid="9061243307939135383">"रिंगर मौन."</string>
@@ -452,8 +452,8 @@
     <string name="battery_saver_notification_title" msgid="8614079794522291840">"बैटरी सेवर चालू है"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"निष्‍पादन और पृष्ठभूमि डेटा को कम करता है"</string>
     <string name="battery_saver_notification_action_text" msgid="132118784269455533">"बैटरी सेवर बंद करें"</string>
-    <string name="media_projection_dialog_text" msgid="8585357687598538511">"रिकॉर्ड या कास्ट करते समय, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> आपकी स्क्रीन पर दिखाई जा रही या आपके डिवाइस पर चलाई जा रही संवेदनशील जानकारी एक्सेस कर सकता है. इस जानकारी में ऑडियो, पासवर्ड, भुगतान की जानकारी, फ़ोटो और मैसेज शामिल हैं."</string>
-    <string name="media_projection_dialog_service_text" msgid="3075544489835858258">"रिकॉर्ड या कास्ट करते समय, यह सेवा देने वाला ऐप्लिकेशन आपकी स्क्रीन पर दिखाई जा रही या आपके डिवाइस पर चलाई जा रही संवेदनशील जानकारी एक्सेस कर सकता है. इस जानकारी में ऑडियो, पासवर्ड, भुगतान की जानकारी, फ़ोटो और मैसेज शामिल हैं."</string>
+    <string name="media_projection_dialog_text" msgid="8585357687598538511">"रिकॉर्ड या कास्ट करते समय, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> आपकी स्क्रीन पर दिखाई जा रही या आपके डिवाइस पर चलाई जा रही संवेदनशील जानकारी ऐक्सेस कर सकता है. इस जानकारी में ऑडियो, पासवर्ड, भुगतान की जानकारी, फ़ोटो और मैसेज शामिल हैं."</string>
+    <string name="media_projection_dialog_service_text" msgid="3075544489835858258">"रिकॉर्ड या कास्ट करते समय, यह सेवा देने वाला ऐप्लिकेशन आपकी स्क्रीन पर दिखाई जा रही या आपके डिवाइस पर चलाई जा रही संवेदनशील जानकारी ऐक्सेस कर सकता है. इस जानकारी में ऑडियो, पासवर्ड, भुगतान की जानकारी, फ़ोटो और मैसेज शामिल हैं."</string>
     <string name="media_projection_dialog_title" msgid="8124184308671641248">"कास्ट करने/रिकॉर्ड करने के दौरान संवेदनशील जानकारी का सबके सामने आ जाना"</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"फिर से न दिखाएं"</string>
     <string name="clear_all_notifications_text" msgid="814192889771462828">"सभी को हटाएं"</string>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 20f638d..676208b 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -747,7 +747,7 @@
     <string name="data_saver" msgid="5037565123367048522">"डेटा सेव्हर"</string>
     <string name="accessibility_data_saver_on" msgid="8454111686783887148">"डेटा सेव्हर चालू आहे"</string>
     <string name="accessibility_data_saver_off" msgid="8841582529453005337">"डेटा सेव्हर बंद आहे"</string>
-    <string name="switch_bar_on" msgid="1142437840752794229">"चालू"</string>
+    <string name="switch_bar_on" msgid="1142437840752794229">"सुरू"</string>
     <string name="switch_bar_off" msgid="8803270596930432874">"बंद"</string>
     <string name="nav_bar" msgid="1993221402773877607">"नॅव्हिगेशन बार"</string>
     <string name="nav_bar_layout" msgid="3664072994198772020">"लेआउट"</string>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index 83a7aaa..1f75490 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -544,7 +544,7 @@
     <string name="screen_pinning_description_recents_invisible_accessible" msgid="6134833683151189507">"Kjo e ruan në pamje deri sa ta heqësh nga gozhdimi. Prek dhe mbaj të shtypur \"Kreu\" për ta hequr nga gozhdimi."</string>
     <string name="screen_pinning_toast" msgid="2266705122951934150">"Për të hequr gozhdimin e këtij ekrani, prek dhe mbaj butonat \"Prapa\" dhe \"Përmbledhja\"."</string>
     <string name="screen_pinning_toast_recents_invisible" msgid="8252402309499161281">"Për të hequr gozhdimin e këtij ekrani, prek dhe mbaj butonat \"Prapa\" dhe \"Kreu\"."</string>
-    <string name="screen_pinning_positive" msgid="3783985798366751226">"E kuptova!"</string>
+    <string name="screen_pinning_positive" msgid="3783985798366751226">"E kuptova"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Jo, faleminderit!"</string>
     <string name="screen_pinning_start" msgid="1022122128489278317">"Ekrani u gozhdua"</string>
     <string name="screen_pinning_exit" msgid="5187339744262325372">"Ekrani u hoq nga gozhdimi"</string>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 9f8f45e..6e8b097 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -761,7 +761,7 @@
     <item msgid="8175437057325747277">"ஏதுமில்லை"</item>
   </string-array>
   <string-array name="nav_bar_layouts">
-    <item msgid="8077901629964902399">"இயல்பானது"</item>
+    <item msgid="8077901629964902399">"சராசரி"</item>
     <item msgid="8256205964297588988">"சுருக்கமானது"</item>
     <item msgid="8719936228094005878">"இடப்புறம் சாய்ந்தது"</item>
     <item msgid="586019486955594690">"வலப்புறம் சாய்ந்தது"</item>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index affca3d..025efac 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -741,7 +741,7 @@
     <string name="battery" msgid="7498329822413202973">"Pin"</string>
     <string name="clock" msgid="7416090374234785905">"Đồng hồ"</string>
     <string name="headset" msgid="4534219457597457353">"Tai nghe"</string>
-    <string name="accessibility_long_click_tile" msgid="6687350750091842525">"Mở cài đặt"</string>
+    <string name="accessibility_long_click_tile" msgid="6687350750091842525">"Mở phần cài đặt"</string>
     <string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Đã kết nối tai nghe"</string>
     <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Đã kết nối tai nghe"</string>
     <string name="data_saver" msgid="5037565123367048522">"Trình tiết kiệm dữ liệu"</string>
@@ -817,7 +817,7 @@
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Ứng dụng không hỗ trợ chia đôi màn hình."</string>
     <string name="forced_resizable_secondary_display" msgid="4230857851756391925">"Ứng dụng có thể không hoạt động trên màn hình phụ."</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="7793821742158306742">"Ứng dụng không hỗ trợ khởi chạy trên màn hình phụ."</string>
-    <string name="accessibility_quick_settings_settings" msgid="6132460890024942157">"Mở cài đặt."</string>
+    <string name="accessibility_quick_settings_settings" msgid="6132460890024942157">"Mở phần cài đặt."</string>
     <string name="accessibility_quick_settings_expand" msgid="2375165227880477530">"Mở cài đặt nhanh."</string>
     <string name="accessibility_quick_settings_collapse" msgid="1792625797142648105">"Đóng cài đặt nhanh."</string>
     <string name="accessibility_quick_settings_alarm_set" msgid="1863000242431528676">"Đã đặt báo thức."</string>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 340cb3a..6e8e823 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -196,9 +196,6 @@
     <!-- Doze: duration to avoid false pickup gestures triggered by notification vibrations -->
     <integer name="doze_pickup_vibration_threshold">2000</integer>
 
-    <!-- Doze: can we assume the pickup sensor includes a proximity check? -->
-    <bool name="doze_pickup_performs_proximity_check">false</bool>
-
     <!-- Type of a sensor that provides a low-power estimate of the desired display
          brightness, suitable to listen to while the device is asleep (e.g. during
          always-on display) -->
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 7feacb4..fab7242 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -958,6 +958,9 @@
     <!-- Message shown when lock screen is tapped or face authentication fails. [CHAR LIMIT=60] -->
     <string name="keyguard_unlock">Swipe up to open</string>
 
+    <!-- Message shown when face authentication fails and the pin pad is visible. [CHAR LIMIT=60] -->
+    <string name="keyguard_retry">Swipe up to try again</string>
+
     <!-- Text on keyguard screen and in Quick Settings footer indicating that the device is enterprise-managed by a Device Owner [CHAR LIMIT=60] -->
     <string name="do_disclosure_generic">This device is managed by your organization</string>
 
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskKeyCache.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskKeyCache.java
index 342cb75..8a244bf 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskKeyCache.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskKeyCache.java
@@ -21,6 +21,9 @@
 
 import com.android.systemui.shared.recents.model.Task.TaskKey;
 
+import java.util.ArrayList;
+import java.util.Collection;
+
 /**
  * Base class for both strong and LRU task key cache.
  */
@@ -76,6 +79,15 @@
         mKeys.remove(key.id);
     }
 
+    /** @return {@link Collection} of {@link TaskKey} */
+    public Collection<TaskKey> getValues() {
+        Collection<TaskKey> result = new ArrayList<>(mKeys.size());
+        for (int i = 0; i < mKeys.size(); i++) {
+            result.add(mKeys.valueAt(i));
+        }
+        return result;
+    }
+
     /** Removes all the entries in the cache. */
     public final synchronized void evictAll() {
         evictAllCache();
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskKeyLruCache.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskKeyLruCache.java
index e106c65..bc57b08 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskKeyLruCache.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskKeyLruCache.java
@@ -49,7 +49,7 @@
 
             @Override
             protected void entryRemoved(boolean evicted, Integer taskId, V oldV, V newV) {
-                if (mEvictionCallback != null) {
+                if (mEvictionCallback != null && evicted) {
                     mEvictionCallback.onEntryEvicted(mKeys.get(taskId));
                 }
 
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/SystemGestureExclusionListenerCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/SystemGestureExclusionListenerCompat.java
index 9fdecfb..aeb0415 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/SystemGestureExclusionListenerCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/SystemGestureExclusionListenerCompat.java
@@ -34,9 +34,11 @@
             new ISystemGestureExclusionListener.Stub() {
                 @Override
                 public void onSystemGestureExclusionChanged(int displayId,
-                        Region systemGestureExclusion) {
+                        Region systemGestureExclusion, Region unrestrictedOrNull) {
                     if (displayId == mDisplayId) {
-                        onExclusionChanged(systemGestureExclusion);
+                        Region unrestricted = (unrestrictedOrNull == null)
+                                ? systemGestureExclusion : unrestrictedOrNull;
+                        onExclusionChanged(systemGestureExclusion, unrestricted);
                     }
                 }
             };
@@ -47,11 +49,29 @@
     }
 
     /**
-     * Called when the exclusion region has changed
+     * Called when the exclusion region has changed.
+     *
+     * TODO: remove, once all subclasses have migrated to
+     *       {@link #onExclusionChanged(Region, Region)}.
      */
     public abstract void onExclusionChanged(Region systemGestureExclusion);
 
     /**
+     * Called when the exclusion region has changed.
+     *
+     * @param systemGestureExclusion the system gesture exclusion to be applied
+     * @param systemGestureExclusionUnrestricted what would be the system gesture exclusion, if
+     *           there were no restrictions being applied. For logging purposes only.
+     *
+     */
+    public void onExclusionChanged(Region systemGestureExclusion,
+            Region systemGestureExclusionUnrestricted) {
+        // TODO: make abstract, once all subclasses have migrated away from
+        //       onExclusionChanged(Region)
+        onExclusionChanged(systemGestureExclusion);
+    }
+
+    /**
      * Registers the listener for getting exclusion rect changes.
      */
     public void register() {
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java
index c215d0f..7757161 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java
@@ -95,6 +95,11 @@
     public void onTaskDisplayChanged(int taskId, int newDisplayId) { }
 
     /**
+     * Called when any additions or deletions to the recent tasks list have been made.
+     */
+    public void onRecentTaskListUpdated() { }
+
+    /**
      * Checks that the current user matches the process. Since
      * {@link android.app.ITaskStackListener} is not multi-user aware, handlers of
      * {@link TaskStackChangeListener} should make this call to verify that we don't act on events
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java
index d570a58..a7f4396 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java
@@ -213,6 +213,11 @@
         mHandler.obtainMessage(H.ON_TASK_DISPLAY_CHANGED, taskId, newDisplayId).sendToTarget();
     }
 
+    @Override
+    public void onRecentTaskListUpdated() throws RemoteException {
+        mHandler.obtainMessage(H.ON_TASK_LIST_UPDATED).sendToTarget();
+    }
+
     private final class H extends Handler {
         private static final int ON_TASK_STACK_CHANGED = 1;
         private static final int ON_TASK_SNAPSHOT_CHANGED = 2;
@@ -234,6 +239,7 @@
         private static final int ON_BACK_PRESSED_ON_TASK_ROOT = 18;
         private static final int ON_SINGLE_TASK_DISPLAY_DRAWN = 19;
         private static final int ON_TASK_DISPLAY_CHANGED = 20;
+        private static final int ON_TASK_LIST_UPDATED = 21;
 
 
         public H(Looper looper) {
@@ -382,6 +388,12 @@
                         }
                         break;
                     }
+                    case ON_TASK_LIST_UPDATED: {
+                        for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+                            mTaskStackListeners.get(i).onRecentTaskListUpdated();
+                        }
+                        break;
+                    }
                 }
             }
         }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java
index a4b6958..517abac 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java
@@ -253,6 +253,7 @@
     protected void onUserInput() {
         if (mCallback != null) {
             mCallback.userActivity();
+            mCallback.onUserInput();
         }
         mSecurityMessageDisplay.setMessage("");
     }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java
index 55ddfc3..56b38f7 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java
@@ -274,6 +274,7 @@
         @Override
         public void onPatternCellAdded(List<LockPatternView.Cell> pattern) {
             mCallback.userActivity();
+            mCallback.onUserInput();
         }
 
         @Override
@@ -336,6 +337,7 @@
                     });
             if (pattern.size() > MIN_PATTERN_BEFORE_POKE_WAKELOCK) {
                 mCallback.userActivity();
+                mCallback.onUserInput();
             }
         }
 
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityCallback.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityCallback.java
index cbfbffb..49dcfff 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityCallback.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityCallback.java
@@ -55,4 +55,9 @@
     default void onCancelClicked() {
         // No-op
     }
+
+    /**
+     * Invoked whenever users are typing their password or drawing a pattern.
+     */
+    void onUserInput();
 }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index 8059dcf..169c97b 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -596,6 +596,11 @@
             }
         }
 
+        @Override
+        public void onUserInput() {
+            mUpdateMonitor.cancelFaceAuth();
+        }
+
         public void dismiss(boolean authenticated, int targetId) {
             mSecurityCallback.dismiss(authenticated, targetId);
         }
@@ -640,6 +645,8 @@
         @Override
         public void dismiss(boolean securityVerified, int targetUserId) { }
         @Override
+        public void onUserInput() { }
+        @Override
         public void reset() {}
     };
 
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 76bed23..1a5a60c 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -867,11 +867,6 @@
                     getCurrentUser());
         }
 
-        // The face timeout message is not very actionable, let's ask the user to
-        // manually retry.
-        if (msgId == FaceManager.FACE_ERROR_TIMEOUT) {
-            errString = mContext.getString(R.string.keyguard_unlock);
-        }
         for (int i = 0; i < mCallbacks.size(); i++) {
             KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
             if (cb != null) {
@@ -1669,6 +1664,13 @@
         updateFaceListeningState();
     }
 
+    /**
+     * In case face auth is running, cancel it.
+     */
+    public void cancelFaceAuth() {
+        stopListeningForFace();
+    }
+
     private void updateFaceListeningState() {
         // If this message exists, we should not authenticate again until this message is
         // consumed by the handler
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
index 4a4fead..cf9c470 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
@@ -339,7 +339,7 @@
         intent.setComponent(assistComponent);
         intent.putExtras(args);
 
-        if (structureEnabled) {
+        if (structureEnabled && AssistUtils.isDisclosureEnabled(mContext)) {
             showDisclosure();
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
index 923ca20..de08a8c 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
@@ -182,7 +182,7 @@
 
         mActivityView = new ActivityView(mContext, null /* attrs */, 0 /* defStyle */,
                 true /* singleTaskInstance */);
-
+        // Set ActivityView's alpha value as zero, since there is no view content to be shown.
         setContentVisibility(false);
         addView(mActivityView);
 
diff --git a/packages/SystemUI/src/com/android/systemui/colorextraction/SysuiColorExtractor.java b/packages/SystemUI/src/com/android/systemui/colorextraction/SysuiColorExtractor.java
index d3e8b3d..3ca1f59 100644
--- a/packages/SystemUI/src/com/android/systemui/colorextraction/SysuiColorExtractor.java
+++ b/packages/SystemUI/src/com/android/systemui/colorextraction/SysuiColorExtractor.java
@@ -68,9 +68,11 @@
         mBackdropColors.setMainColor(Color.BLACK);
 
         // Listen to all users instead of only the current one.
-        wallpaperManager.removeOnColorsChangedListener(this);
-        wallpaperManager.addOnColorsChangedListener(this, null /* handler */,
-                UserHandle.USER_ALL);
+        if (wallpaperManager.isWallpaperSupported()) {
+            wallpaperManager.removeOnColorsChangedListener(this);
+            wallpaperManager.addOnColorsChangedListener(this, null /* handler */,
+                    UserHandle.USER_ALL);
+        }
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
index f6a921d..f79bb3a 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
@@ -107,8 +107,7 @@
                         config.dozePickupSensorAvailable(),
                         DozeLog.REASON_SENSOR_PICKUP, false /* touchCoords */,
                         false /* touchscreen */,
-                        false /* ignoresSetting */,
-                        mDozeParameters.getPickupPerformsProxCheck()),
+                        false /* ignoresSetting */),
                 new TriggerSensor(
                         findSensorWithType(config.doubleTapSensorType()),
                         Settings.Secure.DOZE_DOUBLE_TAP_GESTURE,
@@ -205,11 +204,8 @@
     public void updateListening() {
         boolean anyListening = false;
         for (TriggerSensor s : mSensors) {
-            // We don't want to be listening while we're PAUSED (prox sensor is covered)
-            // except when the sensor is already gated by prox.
-            boolean listen = mListening && (!mPaused || s.performsProxCheck());
-            s.setListening(listen);
-            if (listen) {
+            s.setListening(mListening);
+            if (mListening) {
                 anyListening = true;
             }
         }
@@ -384,7 +380,6 @@
         private final boolean mReportsTouchCoordinates;
         private final boolean mSettingDefault;
         private final boolean mRequiresTouchscreen;
-        private final boolean mSensorPerformsProxCheck;
 
         protected boolean mRequested;
         protected boolean mRegistered;
@@ -401,14 +396,12 @@
                 boolean configured, int pulseReason, boolean reportsTouchCoordinates,
                 boolean requiresTouchscreen) {
             this(sensor, setting, settingDef, configured, pulseReason, reportsTouchCoordinates,
-                    requiresTouchscreen, false /* ignoresSetting */,
-                    false /* sensorPerformsProxCheck */);
+                    requiresTouchscreen, false /* ignoresSetting */);
         }
 
         private TriggerSensor(Sensor sensor, String setting, boolean settingDef,
                 boolean configured, int pulseReason, boolean reportsTouchCoordinates,
-                boolean requiresTouchscreen, boolean ignoresSetting,
-                boolean sensorPerformsProxCheck) {
+                boolean requiresTouchscreen, boolean ignoresSetting) {
             mSensor = sensor;
             mSetting = setting;
             mSettingDefault = settingDef;
@@ -417,7 +410,6 @@
             mReportsTouchCoordinates = reportsTouchCoordinates;
             mRequiresTouchscreen = requiresTouchscreen;
             mIgnoresSetting = ignoresSetting;
-            mSensorPerformsProxCheck = sensorPerformsProxCheck;
         }
 
         public void setListening(boolean listen) {
@@ -491,23 +483,13 @@
                     screenX = event.values[0];
                     screenY = event.values[1];
                 }
-                mCallback.onSensorPulse(mPulseReason, mSensorPerformsProxCheck, screenX, screenY,
-                        event.values);
+                mCallback.onSensorPulse(mPulseReason, screenX, screenY, event.values);
                 if (!mRegistered) {
                     updateListening();  // reregister, this sensor only fires once
                 }
             }));
         }
 
-        /**
-         * If the sensor itself performs proximity checks, to avoid pocket dialing.
-         * Gated sensors don't need to be stopped when the {@link DozeMachine} is
-         * {@link DozeMachine.State#DOZE_AOD_PAUSED}.
-         */
-        public boolean performsProxCheck() {
-            return mSensorPerformsProxCheck;
-        }
-
         public void registerSettingsObserver(ContentObserver settingsObserver) {
             if (mConfigured && !TextUtils.isEmpty(mSetting)) {
                 mResolver.registerContentObserver(
@@ -603,8 +585,7 @@
                     return;
                 }
                 if (DEBUG) Log.d(TAG, "onSensorEvent: " + triggerEventToString(event));
-                mCallback.onSensorPulse(mPulseReason, true /* sensorPerformsProxCheck */, -1, -1,
-                        event.getValues());
+                mCallback.onSensorPulse(mPulseReason, -1, -1, event.getValues());
             }));
         }
     }
@@ -614,13 +595,11 @@
         /**
          * Called when a sensor requests a pulse
          * @param pulseReason Requesting sensor, e.g. {@link DozeLog#REASON_SENSOR_PICKUP}
-         * @param sensorPerformedProxCheck true if the sensor already checked for FAR proximity.
          * @param screenX the location on the screen where the sensor fired or -1
- *                if the sensor doesn't support reporting screen locations.
+         *                if the sensor doesn't support reporting screen locations.
          * @param screenY the location on the screen where the sensor fired or -1
          * @param rawValues raw values array from the event.
          */
-        void onSensorPulse(int pulseReason, boolean sensorPerformedProxCheck,
-                float screenX, float screenY, float[] rawValues);
+        void onSensorPulse(int pulseReason, float screenX, float screenY, float[] rawValues);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
index 310f04a..00bfb3f 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
@@ -41,6 +41,7 @@
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.util.Preconditions;
 import com.android.systemui.Dependency;
+import com.android.systemui.R;
 import com.android.systemui.dock.DockManager;
 import com.android.systemui.statusbar.phone.DozeParameters;
 import com.android.systemui.util.Assert;
@@ -156,8 +157,7 @@
     }
 
     @VisibleForTesting
-    void onSensor(int pulseReason, boolean sensorPerformedProxCheck,
-            float screenX, float screenY, float[] rawValues) {
+    void onSensor(int pulseReason, float screenX, float screenY, float[] rawValues) {
         boolean isDoubleTap = pulseReason == DozeLog.REASON_SENSOR_DOUBLE_TAP;
         boolean isTap = pulseReason == DozeLog.REASON_SENSOR_TAP;
         boolean isPickup = pulseReason == DozeLog.REASON_SENSOR_PICKUP;
@@ -169,10 +169,11 @@
         if (isWakeDisplay) {
             onWakeScreen(wakeEvent, mMachine.isExecutingTransition() ? null : mMachine.getState());
         } else if (isLongPress) {
-            requestPulse(pulseReason, sensorPerformedProxCheck, null /* onPulseSupressedListener */);
+            requestPulse(pulseReason, true /* alreadyPerformedProxCheck */,
+                    null /* onPulseSupressedListener */);
         } else if (isWakeLockScreen) {
             if (wakeEvent) {
-                requestPulse(pulseReason, sensorPerformedProxCheck,
+                requestPulse(pulseReason, true /* alreadyPerformedProxCheck */,
                         null /* onPulseSupressedListener */);
             }
         } else {
@@ -191,8 +192,7 @@
                 } else {
                     mDozeHost.extendPulse(pulseReason);
                 }
-            }, sensorPerformedProxCheck
-                    || (mDockManager != null && mDockManager.isDocked()), pulseReason);
+            }, true /* alreadyPerformedProxCheck */, pulseReason);
         }
 
         if (isPickup) {
@@ -278,7 +278,7 @@
                             .setType(MetricsEvent.TYPE_OPEN)
                             .setSubtype(DozeLog.REASON_SENSOR_WAKE_UP));
                 }
-            }, false /* alreadyPerformedProxCheck */, DozeLog.REASON_SENSOR_WAKE_UP);
+            }, true /* alreadyPerformedProxCheck */, DozeLog.REASON_SENSOR_WAKE_UP);
         } else {
             boolean paused = (state == DozeMachine.State.DOZE_AOD_PAUSED);
             boolean pausing = (state == DozeMachine.State.DOZE_AOD_PAUSING);
@@ -433,7 +433,11 @@
 
         public void check() {
             Preconditions.checkState(!mFinished && !mRegistered);
-            final Sensor sensor = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
+            Sensor sensor = DozeSensors.findSensorWithType(mSensorManager,
+                    mContext.getString(R.string.doze_brightness_sensor_type));
+            if (sensor == null) {
+                sensor = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
+            }
             if (sensor == null) {
                 if (DozeMachine.DEBUG) Log.d(TAG, "ProxCheck: No sensor found");
                 finishWithResult(RESULT_UNKNOWN);
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
index fb8b6c7..75dc397 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
@@ -64,6 +64,8 @@
     private static final int CHARGE_CYCLE_PERCENT_RESET = 45;
     private static final long SIX_HOURS_MILLIS = Duration.ofHours(6).toMillis();
     public static final int NO_ESTIMATE_AVAILABLE = -1;
+    private static final String BOOT_COUNT_KEY = "boot_count";
+    private static final String PREFS = "powerui_prefs";
 
     private final Handler mHandler = new Handler();
     @VisibleForTesting
@@ -118,7 +120,7 @@
 
         // Check to see if we need to let the user know that the phone previously shut down due
         // to the temperature being too high.
-        showThermalShutdownDialog();
+        showWarnOnThermalShutdown();
 
         // Register an observer to configure mEnableSkinTemperatureWarning and perform the
         // registration of skin thermal event listener upon Settings change.
@@ -542,10 +544,23 @@
         }
     }
 
-    private void showThermalShutdownDialog() {
-        if (mPowerManager.getLastShutdownReason()
-                == PowerManager.SHUTDOWN_REASON_THERMAL_SHUTDOWN) {
-            mWarnings.showThermalShutdownWarning();
+    private void showWarnOnThermalShutdown() {
+        int bootCount = -1;
+        int lastReboot = mContext.getSharedPreferences(PREFS, 0).getInt(BOOT_COUNT_KEY, -1);
+        try {
+            bootCount = Settings.Global.getInt(mContext.getContentResolver(),
+                    Settings.Global.BOOT_COUNT);
+        } catch (Settings.SettingNotFoundException e) {
+            Slog.e(TAG, "Failed to read system boot count from Settings.Global.BOOT_COUNT");
+        }
+        // Only show the thermal shutdown warning when there is a thermal reboot.
+        if (bootCount > lastReboot) {
+            mContext.getSharedPreferences(PREFS, 0).edit().putInt(BOOT_COUNT_KEY,
+                    bootCount).apply();
+            if (mPowerManager.getLastShutdownReason()
+                    == PowerManager.SHUTDOWN_REASON_THERMAL_SHUTDOWN) {
+                mWarnings.showThermalShutdownWarning();
+            }
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
index f0413cd..be8a8fd 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
@@ -111,13 +111,25 @@
                 + mQSPanel.getMeasuredHeight() + getPaddingBottom();
         super.onMeasure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
                 MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
-
         // QSCustomizer will always be the height of the screen, but do this after
         // other measuring to avoid changing the height of the QS.
         mQSCustomizer.measure(widthMeasureSpec,
                 MeasureSpec.makeMeasureSpec(getDisplayHeight(), MeasureSpec.EXACTLY));
     }
 
+
+    @Override
+    protected void measureChildWithMargins(View child, int parentWidthMeasureSpec, int widthUsed,
+            int parentHeightMeasureSpec, int heightUsed) {
+        // Do not measure QSPanel again when doing super.onMeasure.
+        // This prevents the pages in PagedTileLayout to be remeasured with a different (incorrect)
+        // size to the one used for determining the number of rows and then the number of pages.
+        if (child != mQSPanel) {
+            super.measureChildWithMargins(child, parentWidthMeasureSpec, widthUsed,
+                    parentHeightMeasureSpec, heightUsed);
+        }
+    }
+
     @Override
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
         super.onLayout(changed, left, top, right, bottom);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 4be93df..bba64d9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -562,11 +562,11 @@
             return;
         }
 
-        String message = mContext.getString(R.string.keyguard_unlock);
         if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
+            String message = mContext.getString(R.string.keyguard_retry);
             mStatusBarKeyguardViewManager.showBouncerMessage(message, mInitialTextColorState);
         } else if (mKeyguardUpdateMonitor.isScreenOn()) {
-            showTransientIndication(message);
+            showTransientIndication(mContext.getString(R.string.keyguard_unlock));
             hideTransientIndicationDelayed(BaseKeyguardCallback.HIDE_DELAY_MS);
         }
     }
@@ -676,7 +676,11 @@
                 return;
             }
             animatePadlockError();
-            if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
+            if (msgId == FaceManager.FACE_ERROR_TIMEOUT) {
+                // The face timeout message is not very actionable, let's ask the user to
+                // manually retry.
+                showSwipeUpToUnlock();
+            } else if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
                 mStatusBarKeyguardViewManager.showBouncerMessage(errString, mInitialTextColorState);
             } else if (updateMonitor.isScreenOn()) {
                 showTransientIndication(errString);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java
index c67512c..f3201ec 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java
@@ -54,7 +54,6 @@
 import com.android.systemui.SysUiServiceProvider;
 import com.android.systemui.SystemUI;
 import com.android.systemui.UiOffloadThread;
-import com.android.systemui.shared.system.TaskStackChangeListener;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.policy.KeyguardMonitor;
 import com.android.systemui.util.NotificationChannels;
@@ -138,15 +137,6 @@
                 }
             };
 
-    private final TaskStackChangeListener mTaskListener =
-            new TaskStackChangeListener() {
-                @Override
-                public void onTaskStackChanged() {
-                    // Listen for changes to stacks and then check which instant apps are
-                    // foreground.
-                    updateForegroundInstantApps();
-                }
-            };
 
     private void updateForegroundInstantApps() {
         NotificationManager noMan = mContext.getSystemService(NotificationManager.class);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java
index 1ce4934..0009292 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java
@@ -420,7 +420,14 @@
             }
         }
 
-        Collections.sort(mSortedAndFiltered, mRankingComparator);
+        if (mSortedAndFiltered.size() == 1) {
+            // HACK: We need the comparator to run on all children in order to set the
+            // isHighPriority field. If there is only one child, then the comparison won't be run,
+            // so we have to trigger it manually. Get rid of this code as soon as possible.
+            mRankingComparator.compare(mSortedAndFiltered.get(0), mSortedAndFiltered.get(0));
+        } else {
+            Collections.sort(mSortedAndFiltered, mRankingComparator);
+        }
     }
 
     public void dump(PrintWriter pw, String indent) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index 6e84089..65e744b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -1208,12 +1208,12 @@
             mChildrenContainer.reInflateViews(mExpandClickListener, mEntry.notification);
         }
         if (mGuts != null) {
-            View oldGuts = mGuts;
+            NotificationGuts oldGuts = mGuts;
             int index = indexOfChild(oldGuts);
             removeView(oldGuts);
             mGuts = (NotificationGuts) LayoutInflater.from(mContext).inflate(
                     R.layout.notification_guts, this, false);
-            mGuts.setVisibility(oldGuts.getVisibility());
+            mGuts.setVisibility(oldGuts.isExposed() ? VISIBLE : GONE);
             addView(mGuts, index);
         }
         View oldMenu = mMenuRow == null ? null : mMenuRow.getMenuView();
@@ -1366,7 +1366,9 @@
         if (isChildInGroup()) {
             mTranslationWhenRemoved += getNotificationParent().getTranslationY();
         }
-        mPrivateLayout.setRemoved();
+        for (NotificationContentView l : mLayouts) {
+            l.setRemoved();
+        }
     }
 
     public boolean wasChildInGroupWhenRemoved() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
index 90f6324..0c5b27b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
@@ -1542,6 +1542,15 @@
         if (mHeadsUpRemoteInput != null) {
             mHeadsUpRemoteInput.setRemoved();
         }
+        if (mExpandedWrapper != null) {
+            mExpandedWrapper.setRemoved();
+        }
+        if (mContractedWrapper != null) {
+            mContractedWrapper.setRemoved();
+        }
+        if (mHeadsUpWrapper != null) {
+            mHeadsUpWrapper.setRemoved();
+        }
     }
 
     public void setContentHeightAnimating(boolean animating) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java
index 20e8b73..1116106 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java
@@ -39,6 +39,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.internal.widget.MediaNotificationView;
 import com.android.systemui.Dependency;
 import com.android.systemui.statusbar.NotificationMediaManager;
 import com.android.systemui.statusbar.TransformableView;
@@ -67,6 +68,7 @@
     private View mSeekBarView;
     private Context mContext;
     private MetricsLogger mMetricsLogger;
+    private boolean mIsViewVisible;
 
     @VisibleForTesting
     protected SeekBar.OnSeekBarChangeListener mSeekListener =
@@ -88,11 +90,46 @@
         }
     };
 
+    private MediaNotificationView.VisibilityChangeListener mVisibilityListener =
+            new MediaNotificationView.VisibilityChangeListener() {
+        @Override
+        public void onAggregatedVisibilityChanged(boolean isVisible) {
+            mIsViewVisible = isVisible;
+            if (isVisible && mMediaController != null) {
+                // Restart timer if we're currently playing and didn't already have one going
+                PlaybackState state = mMediaController.getPlaybackState();
+                if (state != null && state.getState() == PlaybackState.STATE_PLAYING
+                        && mSeekBarTimer == null && mSeekBarView != null
+                        && mSeekBarView.getVisibility() != View.GONE) {
+                    startTimer();
+                }
+            } else {
+                clearTimer();
+            }
+        }
+    };
+
+    private View.OnAttachStateChangeListener mAttachStateListener =
+            new View.OnAttachStateChangeListener() {
+        @Override
+        public void onViewAttachedToWindow(View v) {
+        }
+
+        @Override
+        public void onViewDetachedFromWindow(View v) {
+            mIsViewVisible = false;
+        }
+    };
+
     private MediaController.Callback mMediaCallback = new MediaController.Callback() {
         @Override
         public void onSessionDestroyed() {
             clearTimer();
             mMediaController.unregisterCallback(this);
+            if (mView instanceof MediaNotificationView) {
+                ((MediaNotificationView) mView).removeVisibilityListener(mVisibilityListener);
+                mView.removeOnAttachStateChangeListener(mAttachStateListener);
+            }
         }
 
         @Override
@@ -126,10 +163,17 @@
         mContext = ctx;
         mMediaManager = Dependency.get(NotificationMediaManager.class);
         mMetricsLogger = Dependency.get(MetricsLogger.class);
+
+        if (mView instanceof MediaNotificationView) {
+            MediaNotificationView mediaView = (MediaNotificationView) mView;
+            mediaView.addVisibilityListener(mVisibilityListener);
+            mView.addOnAttachStateChangeListener(mAttachStateListener);
+        }
     }
 
     private void resolveViews() {
         mActions = mView.findViewById(com.android.internal.R.id.media_actions);
+        mIsViewVisible = mView.isShown();
 
         final MediaSession.Token token = mRow.getEntry().notification.getNotification().extras
                 .getParcelable(Notification.EXTRA_MEDIA_SESSION);
@@ -208,24 +252,37 @@
 
     private void startTimer() {
         clearTimer();
-        mSeekBarTimer = new Timer(true /* isDaemon */);
-        mSeekBarTimer.schedule(new TimerTask() {
-            @Override
-            public void run() {
-                mHandler.post(mOnUpdateTimerTick);
-            }
-        }, 0, PROGRESS_UPDATE_INTERVAL);
+        if (mIsViewVisible) {
+            mSeekBarTimer = new Timer(true /* isDaemon */);
+            mSeekBarTimer.schedule(new TimerTask() {
+                @Override
+                public void run() {
+                    mHandler.post(mOnUpdateTimerTick);
+                }
+            }, 0, PROGRESS_UPDATE_INTERVAL);
+        }
     }
 
     private void clearTimer() {
         if (mSeekBarTimer != null) {
-            // TODO: also trigger this when the notification panel is collapsed
             mSeekBarTimer.cancel();
             mSeekBarTimer.purge();
             mSeekBarTimer = null;
         }
     }
 
+    @Override
+    public void setRemoved() {
+        clearTimer();
+        if (mMediaController != null) {
+            mMediaController.unregisterCallback(mMediaCallback);
+        }
+        if (mView instanceof MediaNotificationView) {
+            ((MediaNotificationView) mView).removeVisibilityListener(mVisibilityListener);
+            mView.removeOnAttachStateChangeListener(mAttachStateListener);
+        }
+    }
+
     private boolean canSeekMedia(@Nullable PlaybackState state) {
         if (state == null) {
             return false;
@@ -261,7 +318,6 @@
         public void run() {
             if (mMediaController != null && mSeekBar != null) {
                 PlaybackState playbackState = mMediaController.getPlaybackState();
-
                 if (playbackState != null) {
                     updatePlaybackUi(playbackState);
                 } else {
@@ -274,6 +330,10 @@
     };
 
     private void updatePlaybackUi(PlaybackState state) {
+        if (mSeekBar == null || mSeekBarElapsedTime == null) {
+            return;
+        }
+
         long position = state.getPosition();
         mSeekBar.setProgress((int) position);
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java
index 47906a7..3950003 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java
@@ -261,6 +261,12 @@
         mView.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
     }
 
+    /**
+     * Called to indicate this view is removed
+     */
+    public void setRemoved() {
+    }
+
     public int getCustomBackgroundColor() {
         // Parent notifications should always use the normal background color
         return mRow.isSummaryWithChildren() ? 0 : mBackgroundColor;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
index 10b48e7..bb6a38e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
@@ -207,10 +207,6 @@
         return SystemProperties.get(propName, mContext.getString(resId));
     }
 
-    public boolean getPickupPerformsProxCheck() {
-        return mContext.getResources().getBoolean(R.bool.doze_pickup_performs_proximity_check);
-    }
-
     public int getPulseVisibleDurationExtended() {
         return 2 * getPulseVisibleDuration();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java
index f9cdde8..6a74779 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java
@@ -31,6 +31,7 @@
 import android.os.Looper;
 import android.os.RemoteException;
 import android.os.SystemClock;
+import android.os.SystemProperties;
 import android.util.Log;
 import android.util.MathUtils;
 import android.view.Gravity;
@@ -66,7 +67,8 @@
 public class EdgeBackGestureHandler implements DisplayListener {
 
     private static final String TAG = "EdgeBackGestureHandler";
-    private static final int MAX_LONG_PRESS_TIMEOUT = 250;
+    private static final int MAX_LONG_PRESS_TIMEOUT = SystemProperties.getInt(
+            "gestures.back_timeout", 250);
 
     private final IPinnedStackListener.Stub mImeChangedListener = new IPinnedStackListener.Stub() {
         @Override
@@ -103,7 +105,7 @@
             new ISystemGestureExclusionListener.Stub() {
                 @Override
                 public void onSystemGestureExclusionChanged(int displayId,
-                        Region systemGestureExclusion) {
+                        Region systemGestureExclusion, Region unrestrictedOrNull) {
                     if (displayId == mDisplayId) {
                         mMainExecutor.execute(() -> mExcludeRegion.set(systemGestureExclusion));
                     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java
index d2023ec..dcb349b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java
@@ -79,10 +79,13 @@
 
         IWallpaperManager service = IWallpaperManager.Stub.asInterface(
                 ServiceManager.getService(Context.WALLPAPER_SERVICE));
-        try {
-            service.setLockWallpaperCallback(this);
-        } catch (RemoteException e) {
-            Log.e(TAG, "System dead?" + e);
+        if (service != null) {
+            // Service is disabled on some devices like Automotive
+            try {
+                service.setLockWallpaperCallback(this);
+            } catch (RemoteException e) {
+                Log.e(TAG, "System dead?" + e);
+            }
         }
     }
 
@@ -108,6 +111,11 @@
     public LoaderResult loadBitmap(int currentUserId, UserHandle selectedUser) {
         // May be called on any thread - only use thread safe operations.
 
+        if (!mWallpaperManager.isWallpaperSupported()) {
+            // When wallpaper is not supported, show the system wallpaper
+            return LoaderResult.success(null);
+        }
+
         // Prefer the selected user (when specified) over the current user for the FLAG_SET_LOCK
         // wallpaper.
         final int lockWallpaperUserId =
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 6bfa048..f689a3e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -619,6 +619,10 @@
         // Always disable recents when alternate car mode UI is active and for secondary displays.
         boolean disableRecent = isRecentsButtonDisabled();
 
+        // Disable the home handle if both hone and recents are disabled
+        boolean disableHomeHandle = disableRecent
+                && ((mDisabledFlags & View.STATUS_BAR_DISABLE_HOME) != 0);
+
         boolean disableBack = !useAltBack && (isGesturalMode(mNavBarMode)
                 || ((mDisabledFlags & View.STATUS_BAR_DISABLE_BACK) != 0));
 
@@ -649,6 +653,7 @@
         getBackButton().setVisibility(disableBack      ? View.INVISIBLE : View.VISIBLE);
         getHomeButton().setVisibility(disableHome      ? View.INVISIBLE : View.VISIBLE);
         getRecentsButton().setVisibility(disableRecent ? View.INVISIBLE : View.VISIBLE);
+        getHomeHandle().setVisibility(disableHomeHandle ? View.INVISIBLE : View.VISIBLE);
     }
 
     @VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 01dcbc7..c171730 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -1266,6 +1266,15 @@
             // earlier so the state is already up to date when dragging down.
             setListening(true);
         }
+        if (isQsSplitEnabled() && !mKeyguardShowing) {
+            if (mQsExpandImmediate) {
+                mNotificationStackScroller.setVisibility(View.GONE);
+                mQsFrame.setVisibility(View.VISIBLE);
+            } else {
+                mNotificationStackScroller.setVisibility(View.VISIBLE);
+                mQsFrame.setVisibility(View.GONE);
+            }
+        }
         return false;
     }
 
@@ -1539,6 +1548,10 @@
 
         mBarState = statusBarState;
         mKeyguardShowing = keyguardShowing;
+        if (mKeyguardShowing && isQsSplitEnabled()) {
+            mNotificationStackScroller.setVisibility(View.VISIBLE);
+            mQsFrame.setVisibility(View.VISIBLE);
+        }
 
         if (oldState == StatusBarState.KEYGUARD
                 && (goingToFullShade || statusBarState == StatusBarState.SHADE_LOCKED)) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
index c706062..b45914b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
@@ -133,6 +133,12 @@
             mBlankScreen = mDisplayRequiresBlanking;
             mAnimationDuration = mWakeLockScreenSensorActive
                     ? ScrimController.ANIMATION_DURATION_LONG : ScrimController.ANIMATION_DURATION;
+
+            // Wake sensor will show the wallpaper, let's fade from black. Otherwise it will
+            // feel like the screen is flashing if the wallpaper is light.
+            if (mWakeLockScreenSensorActive && previousState == AOD) {
+                updateScrimColor(mScrimBehind, 1f /* alpha */, Color.BLACK);
+            }
         }
 
         @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 4f9df43..90aba87 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -480,15 +480,17 @@
     private NotificationMediaManager mMediaManager;
     protected NotificationLockscreenUserManager mLockscreenUserManager;
     protected NotificationRemoteInputManager mRemoteInputManager;
+    private boolean mWallpaperSupported;
 
     private final BroadcastReceiver mWallpaperChangedReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
-            WallpaperManager wallpaperManager = context.getSystemService(WallpaperManager.class);
-            if (wallpaperManager == null) {
-                Log.w(TAG, "WallpaperManager not available");
+            if (!mWallpaperSupported) {
+                // Receiver should not have been registered at all...
+                Log.wtf(TAG, "WallpaperManager not supported");
                 return;
             }
+            WallpaperManager wallpaperManager = context.getSystemService(WallpaperManager.class);
             WallpaperInfo info = wallpaperManager.getWallpaperInfo(UserHandle.USER_CURRENT);
             final boolean deviceSupportsAodWallpaper = mContext.getResources().getBoolean(
                     com.android.internal.R.bool.config_dozeSupportsAodWallpaper);
@@ -715,11 +717,18 @@
 
         createAndAddWindows(result);
 
-        // Make sure we always have the most current wallpaper info.
-        IntentFilter wallpaperChangedFilter = new IntentFilter(Intent.ACTION_WALLPAPER_CHANGED);
-        mContext.registerReceiverAsUser(mWallpaperChangedReceiver, UserHandle.ALL,
-                wallpaperChangedFilter, null /* broadcastPermission */, null /* scheduler */);
-        mWallpaperChangedReceiver.onReceive(mContext, null);
+        mWallpaperSupported =
+                mContext.getSystemService(WallpaperManager.class).isWallpaperSupported();
+
+        if (mWallpaperSupported) {
+            // Make sure we always have the most current wallpaper info.
+            IntentFilter wallpaperChangedFilter = new IntentFilter(Intent.ACTION_WALLPAPER_CHANGED);
+            mContext.registerReceiverAsUser(mWallpaperChangedReceiver, UserHandle.ALL,
+                    wallpaperChangedFilter, null /* broadcastPermission */, null /* scheduler */);
+            mWallpaperChangedReceiver.onReceive(mContext, null);
+        } else if (DEBUG) {
+            Log.v(TAG, "start(): no wallpaper service ");
+        }
 
         // Set up the initial notification state. This needs to happen before CommandQueue.disable()
         setUpPresenter();
@@ -754,12 +763,14 @@
         mContext.registerReceiver(mBannerActionBroadcastReceiver, internalFilter, PERMISSION_SELF,
                 null);
 
-        IWallpaperManager wallpaperManager = IWallpaperManager.Stub.asInterface(
-                ServiceManager.getService(Context.WALLPAPER_SERVICE));
-        try {
-            wallpaperManager.setInAmbientMode(false /* ambientMode */, 0L /* duration */);
-        } catch (RemoteException e) {
-            // Just pass, nothing critical.
+        if (mWallpaperSupported) {
+            IWallpaperManager wallpaperManager = IWallpaperManager.Stub.asInterface(
+                    ServiceManager.getService(Context.WALLPAPER_SERVICE));
+            try {
+                wallpaperManager.setInAmbientMode(false /* ambientMode */, 0L /* duration */);
+            } catch (RemoteException e) {
+                // Just pass, nothing critical.
+            }
         }
 
         // end old BaseStatusBar.start().
@@ -2311,6 +2322,7 @@
         pw.println(Settings.Global.zenModeToString(Settings.Global.getInt(
                 mContext.getContentResolver(), Settings.Global.ZEN_MODE,
                 Settings.Global.ZEN_MODE_OFF)));
+        pw.print("  mWallpaperSupported= "); pw.println(mWallpaperSupported);
 
         if (mStatusBarView != null) {
             dumpBarTransitions(pw, "mStatusBarView", mStatusBarView.getBarTransitions());
@@ -2691,7 +2703,9 @@
     public void setLockscreenUser(int newUserId) {
         mLockscreenWallpaper.setCurrentUser(newUserId);
         mScrimController.setCurrentUser(newUserId);
-        mWallpaperChangedReceiver.onReceive(mContext, null);
+        if (mWallpaperSupported) {
+            mWallpaperChangedReceiver.onReceive(mContext, null);
+        }
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index 7b133f2..24d6c4c 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -1020,12 +1020,11 @@
         row.icon.setAlpha(iconEnabled ? 1 : 0.5f);
         final int iconRes =
                 isRingVibrate ? R.drawable.ic_volume_ringer_vibrate
-                : isRingSilent || zenMuted ? row.iconMuteRes
-                : ss.routedToBluetooth ?
-                        (ss.muted ? R.drawable.ic_volume_media_bt_mute
-                                : R.drawable.ic_volume_media_bt)
-                : mAutomute && ss.level == 0 ? row.iconMuteRes
-                : (ss.muted ? row.iconMuteRes : row.iconRes);
+                        : isRingSilent || zenMuted ? row.iconMuteRes
+                                : ss.routedToBluetooth
+                                        ? isStreamMuted(ss) ? R.drawable.ic_volume_media_bt_mute
+                                                : R.drawable.ic_volume_media_bt
+                                        : isStreamMuted(ss) ? row.iconMuteRes : row.iconRes;
         row.icon.setImageResource(iconRes);
         row.iconState =
                 iconRes == R.drawable.ic_volume_ringer_vibrate ? Events.ICON_STATE_VIBRATE
@@ -1087,6 +1086,10 @@
         updateVolumeRowSliderH(row, enableSlider, vlevel);
     }
 
+    private boolean isStreamMuted(final StreamState streamState) {
+        return (mAutomute && streamState.level == 0) || streamState.muted;
+    }
+
     private void updateVolumeRowTintH(VolumeRow row, boolean isActive) {
         if (isActive) {
             row.slider.requestFocus();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java
index 2ed0970..0c124ff 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java
@@ -37,7 +37,6 @@
         when(params.getPulseOnSigMotion()).thenReturn(false);
         when(params.getPickupVibrationThreshold()).thenReturn(0);
         when(params.getProxCheckBeforePulse()).thenReturn(true);
-        when(params.getPickupPerformsProxCheck()).thenReturn(true);
         when(params.getPolicy()).thenReturn(mock(AlwaysOnDisplayPolicy.class));
         when(params.doubleTapReportsTouchCoordinates()).thenReturn(false);
         when(params.getDisplayNeedsBlanking()).thenReturn(false);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java
index 7df45a3..cd6d1e0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java
@@ -19,7 +19,6 @@
 import static com.android.systemui.plugins.SensorManagerPlugin.Sensor.TYPE_WAKE_LOCK_SCREEN;
 
 import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyFloat;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
@@ -79,8 +78,6 @@
     private AlwaysOnDisplayPolicy mAlwaysOnDisplayPolicy;
     @Mock
     private TriggerSensor mTriggerSensor;
-    @Mock
-    private TriggerSensor mProxGatedTriggerSensor;
     private SensorManagerPlugin.SensorEventListener mWakeLockScreenListener;
     private TestableLooper mTestableLooper;
     private DozeSensors mDozeSensors;
@@ -88,7 +85,6 @@
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
-        when(mProxGatedTriggerSensor.performsProxCheck()).thenReturn(true);
         mTestableLooper = TestableLooper.get(this);
         when(mAmbientDisplayConfiguration.getWakeLockScreenDebounce()).thenReturn(5000L);
         when(mAmbientDisplayConfiguration.alwaysOnEnabled(anyInt())).thenReturn(true);
@@ -106,14 +102,14 @@
         mWakeLockScreenListener.onSensorChanged(mock(SensorManagerPlugin.SensorEvent.class));
         mTestableLooper.processAllMessages();
         verify(mCallback).onSensorPulse(eq(DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN),
-                anyBoolean(), anyFloat(), anyFloat(), eq(null));
+                anyFloat(), anyFloat(), eq(null));
 
         mDozeSensors.requestTemporaryDisable();
         reset(mCallback);
         mWakeLockScreenListener.onSensorChanged(mock(SensorManagerPlugin.SensorEvent.class));
         mTestableLooper.processAllMessages();
         verify(mCallback, never()).onSensorPulse(eq(DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN),
-                anyBoolean(), anyFloat(), anyFloat(), eq(null));
+                anyFloat(), anyFloat(), eq(null));
     }
 
     @Test
@@ -132,20 +128,17 @@
     }
 
     @Test
-    public void testSetPaused_onlyPausesNonGatedSensors() {
+    public void testSetPaused_doesntPause_sensors() {
         mDozeSensors.setListening(true);
         verify(mTriggerSensor).setListening(eq(true));
-        verify(mProxGatedTriggerSensor).setListening(eq(true));
 
-        clearInvocations(mTriggerSensor, mProxGatedTriggerSensor);
+        clearInvocations(mTriggerSensor);
         mDozeSensors.setPaused(true);
-        verify(mTriggerSensor).setListening(eq(false));
-        verify(mProxGatedTriggerSensor).setListening(eq(true));
-
-        clearInvocations(mTriggerSensor, mProxGatedTriggerSensor);
-        mDozeSensors.setPaused(false);
         verify(mTriggerSensor).setListening(eq(true));
-        verify(mProxGatedTriggerSensor).setListening(eq(true));
+
+        clearInvocations(mTriggerSensor);
+        mDozeSensors.setListening(false);
+        verify(mTriggerSensor).setListening(eq(false));
     }
 
     private class TestableDozeSensors extends DozeSensors {
@@ -161,7 +154,7 @@
                     mWakeLockScreenListener = (PluginSensor) sensor;
                 }
             }
-            mSensors = new TriggerSensor[] {mTriggerSensor, mProxGatedTriggerSensor};
+            mSensors = new TriggerSensor[] {mTriggerSensor};
         }
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
index d464223..e190f99 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
@@ -20,7 +20,6 @@
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.clearInvocations;
-import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
@@ -134,28 +133,4 @@
         mTriggers.transitionTo(DozeMachine.State.DOZE, DozeMachine.State.FINISH);
         verify(mDockManagerFake).removeListener(any());
     }
-
-    @Test
-    public void testOnSensor_whenUndockedWithNearAndDoubleTapScreen_shouldNotWakeUp() {
-        mSensors.getMockProximitySensor().sendProximityResult(false /* far */);
-
-        mTriggers.onSensor(DozeLog.REASON_SENSOR_DOUBLE_TAP,
-                false /* sensorPerformedProxCheck */, 50 /* screenX */, 50 /* screenY */,
-                null /* rawValues */);
-        verify(mMachine, never()).wakeUp();
-    }
-
-    @Test
-    public void testOnSensor_whenDockedWithNearAndDoubleTapScreen_shouldWakeUp() {
-        doReturn(true).when(mDockManagerFake).isDocked();
-        doReturn(true).when(mParameters).getDisplayNeedsBlanking();
-        mSensors.getMockProximitySensor().sendProximityResult(false /* far */);
-
-        mTriggers.onSensor(DozeLog.REASON_SENSOR_DOUBLE_TAP,
-                false /* sensorPerformedProxCheck */, 50 /* screenX */, 50 /* screenY */,
-                null /* rawValues */);
-
-        verify(mHost).setAodDimmingScrim(eq(1f));
-        verify(mMachine).wakeUp();
-    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/recents/model/TaskKeyLruCacheTest.java b/packages/SystemUI/tests/src/com/android/systemui/shared/recents/model/TaskKeyLruCacheTest.java
index eb71dd6..de6c87c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/recents/model/TaskKeyLruCacheTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/recents/model/TaskKeyLruCacheTest.java
@@ -20,6 +20,10 @@
 import static junit.framework.TestCase.assertEquals;
 import static junit.framework.TestCase.assertNull;
 
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
 import android.test.suitebuilder.annotation.SmallTest;
 
 import com.android.systemui.SysuiTestCase;
@@ -27,10 +31,10 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
+import org.mockito.junit.MockitoJUnitRunner;
 
 @SmallTest
-@RunWith(JUnit4.class)
+@RunWith(MockitoJUnitRunner.class)
 public class TaskKeyLruCacheTest extends SysuiTestCase {
     private static int sCacheSize = 3;
     private static int sIdTask1 = 1;
@@ -38,13 +42,18 @@
     private static int sIdTask3 = 3;
     private static int sIdUser1 = 1;
 
-    TaskKeyCache<Integer> mCache = new TaskKeyLruCache<>(sCacheSize, null);
-    Task.TaskKey mKey1;
-    Task.TaskKey mKey2;
-    Task.TaskKey mKey3;
+    TaskKeyLruCache.EvictionCallback mEvictionCallback;
+
+    TaskKeyLruCache<Integer> mCache;
+    private Task.TaskKey mKey1;
+    private Task.TaskKey mKey2;
+    private Task.TaskKey mKey3;
 
     @Before
     public void setup() {
+        mEvictionCallback = mock(TaskKeyLruCache.EvictionCallback.class);
+        mCache = new TaskKeyLruCache<>(sCacheSize, mEvictionCallback);
+
         mKey1 = new Task.TaskKey(sIdTask1, 0, null, null, sIdUser1, System.currentTimeMillis());
         mKey2 = new Task.TaskKey(sIdTask2, 0, null, null, sIdUser1, System.currentTimeMillis());
         mKey3 = new Task.TaskKey(sIdTask3, 0, null, null, sIdUser1, System.currentTimeMillis());
@@ -90,6 +99,7 @@
         assertNull(mCache.get(mKey1));
         assertEquals(3, mCache.mKeys.size());
         assertEquals(mKey2, mCache.mKeys.valueAt(0));
+        verify(mEvictionCallback, times(1)).onEntryEvicted(mKey1);
     }
 
     @Test
@@ -102,5 +112,29 @@
 
         assertNull(mCache.get(mKey2));
         assertEquals(2, mCache.mKeys.size());
+        verify(mEvictionCallback, times(0)).onEntryEvicted(mKey2);
+    }
+
+    @Test
+    public void put_evictionCallback_notCalled() {
+        mCache.put(mKey1, 1);
+        verify(mEvictionCallback, times(0)).onEntryEvicted(mKey1);
+    }
+
+    @Test
+    public void evictAll_evictionCallback_called() {
+        mCache.put(mKey1, 1);
+        mCache.evictAllCache();
+        verify(mEvictionCallback, times(1)).onEntryEvicted(mKey1);
+    }
+
+    @Test
+    public void trimAll_evictionCallback_called() {
+        mCache.put(mKey1, 1);
+        mCache.put(mKey2, 2);
+        mCache.trimToSize(-1);
+        verify(mEvictionCallback, times(1)).onEntryEvicted(mKey1);
+        verify(mEvictionCallback, times(1)).onEntryEvicted(mKey2);
+
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationDataTest.java
index 260555f..e2d8e56 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationDataTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationDataTest.java
@@ -23,6 +23,7 @@
 import static android.app.Notification.CATEGORY_EVENT;
 import static android.app.Notification.CATEGORY_MESSAGE;
 import static android.app.Notification.CATEGORY_REMINDER;
+import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
 import static android.app.NotificationManager.IMPORTANCE_LOW;
 import static android.app.NotificationManager.IMPORTANCE_MIN;
 
@@ -62,6 +63,8 @@
 import android.testing.TestableLooper.RunWithLooper;
 import android.util.ArraySet;
 
+import androidx.test.filters.SmallTest;
+
 import com.android.systemui.Dependency;
 import com.android.systemui.ForegroundServiceController;
 import com.android.systemui.InitController;
@@ -85,8 +88,6 @@
 import java.util.List;
 import java.util.Map;
 
-import androidx.test.filters.SmallTest;
-
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
 @RunWithLooper
@@ -114,6 +115,7 @@
         MockitoAnnotations.initMocks(this);
         when(mMockStatusBarNotification.getUid()).thenReturn(UID_NORMAL);
         when(mMockStatusBarNotification.cloneLight()).thenReturn(mMockStatusBarNotification);
+        when(mMockStatusBarNotification.getKey()).thenReturn("mock_key");
 
         when(mMockPackageManager.checkUidPermission(
                 eq(Manifest.permission.NOTIFICATION_DURING_SETUP),
@@ -232,6 +234,7 @@
         Notification n = mMockStatusBarNotification.getNotification();
         n.flags = Notification.FLAG_FOREGROUND_SERVICE;
         NotificationEntry entry = new NotificationEntry(mMockStatusBarNotification);
+        entry.setRow(mRow);
         mNotificationData.add(entry);
         Bundle override = new Bundle();
         override.putInt(OVERRIDE_VIS_EFFECTS, 255);
@@ -250,6 +253,7 @@
         n = nb.build();
         when(mMockStatusBarNotification.getNotification()).thenReturn(n);
         NotificationEntry entry = new NotificationEntry(mMockStatusBarNotification);
+        entry.setRow(mRow);
         mNotificationData.add(entry);
         Bundle override = new Bundle();
         override.putInt(OVERRIDE_VIS_EFFECTS, 255);
@@ -263,6 +267,7 @@
     public void testIsExemptFromDndVisualSuppression_system() {
         initStatusBarNotification(false);
         NotificationEntry entry = new NotificationEntry(mMockStatusBarNotification);
+        entry.setRow(mRow);
         entry.mIsSystemNotification = true;
         mNotificationData.add(entry);
         Bundle override = new Bundle();
@@ -277,6 +282,7 @@
     public void testIsNotExemptFromDndVisualSuppression_hiddenCategories() {
         initStatusBarNotification(false);
         NotificationEntry entry = new NotificationEntry(mMockStatusBarNotification);
+        entry.setRow(mRow);
         entry.mIsSystemNotification = true;
         Bundle override = new Bundle();
         override.putInt(OVERRIDE_VIS_EFFECTS, NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT);
@@ -529,6 +535,62 @@
         assertEquals(-1, mNotificationData.mRankingComparator.compare(a, b));
     }
 
+    @Test
+    public void testSort_properlySetsIsTopBucket() {
+
+        Notification notification = new Notification.Builder(mContext, "test")
+                .build();
+        StatusBarNotification sbn = new StatusBarNotification(
+                "pkg",
+                "pkg",
+                0,
+                "tag",
+                0,
+                0,
+                notification,
+                mContext.getUser(),
+                "",
+                0);
+
+        Bundle override = new Bundle();
+        override.putInt(OVERRIDE_IMPORTANCE, IMPORTANCE_DEFAULT);
+        mNotificationData.rankingOverrides.put(sbn.getKey(), override);
+
+        NotificationEntry entry = new NotificationEntry(sbn);
+        entry.setRow(mRow);
+        mNotificationData.add(entry);
+
+        assertTrue(entry.isTopBucket());
+    }
+
+    @Test
+    public void testSort_properlySetsIsNotTopBucket() {
+        Notification notification = new Notification.Builder(mContext, "test")
+                .build();
+        StatusBarNotification sbn = new StatusBarNotification(
+                "pkg",
+                "pkg",
+                0,
+                "tag",
+                0,
+                0,
+                notification,
+                mContext.getUser(),
+                "",
+                0);
+
+        Bundle override = new Bundle();
+        override.putInt(OVERRIDE_IMPORTANCE, IMPORTANCE_LOW);
+        mNotificationData.rankingOverrides.put(sbn.getKey(), override);
+
+        NotificationEntry entry = new NotificationEntry(sbn);
+        entry.setRow(mRow);
+
+        mNotificationData.add(entry);
+
+        assertFalse(entry.isTopBucket());
+    }
+
     private void initStatusBarNotification(boolean allowDuringSetup) {
         Bundle bundle = new Bundle();
         bundle.putBoolean(Notification.EXTRA_ALLOW_DURING_SETUP, allowDuringSetup);
diff --git a/services/art-profile-boot b/services/art-profile-boot
new file mode 100644
index 0000000..23d7090
--- /dev/null
+++ b/services/art-profile-boot
@@ -0,0 +1,326 @@
+Lcom/android/server/SystemServer;->run()V
+Lcom/android/server/SystemServer;->main([Ljava/lang/String;)V
+Lcom/android/server/SystemServer;->startBootstrapServices()V
+Lcom/android/server/pm/PackageManagerService;->main(Landroid/content/Context;Lcom/android/server/pm/Installer;ZZ)Lcom/android/server/pm/PackageManagerService;
+Lcom/android/server/pm/PackageManagerService;-><init>(Landroid/content/Context;Lcom/android/server/pm/Installer;ZZ)V
+Lcom/android/server/pm/Settings;->readLPw(Ljava/util/List;)Z
+Lcom/android/server/pm/Settings;->readPackageLPw(Lorg/xmlpull/v1/XmlPullParser;)V
+Lcom/android/server/pm/Settings;->readInstallPermissionsLPr(Lorg/xmlpull/v1/XmlPullParser;Lcom/android/server/pm/permission/PermissionsState;)V
+Lcom/android/server/pm/permission/PermissionsState;->grantPermission(Lcom/android/server/pm/permission/BasePermission;I)I
+Lcom/android/server/pm/permission/PermissionsState;->grantInstallPermission(Lcom/android/server/pm/permission/BasePermission;)I
+Lcom/android/server/-$$Lambda$YWiwiKm_Qgqb55C6tTuq_n2JzdY;->run()V
+Lcom/android/server/pm/PackageSignatures;->readXml(Lorg/xmlpull/v1/XmlPullParser;Ljava/util/ArrayList;)V
+Lcom/android/server/pm/permission/PermissionsState;->computeGids(I)[I
+Lcom/android/server/am/-$$Lambda$BatteryExternalStatsWorker$ddVY5lmqswnSjXppAxPTOHbuzzQ;->run()V
+Lcom/android/server/SystemServiceManager;->startService(Lcom/android/server/SystemService;)V
+Lcom/android/server/SystemServiceManager;->startService(Ljava/lang/Class;)Lcom/android/server/SystemService;
+Lcom/android/server/SystemServiceManager;->startService(Ljava/lang/String;)Lcom/android/server/SystemService;
+Lcom/android/server/pm/permission/PermissionsState;->hasPermission(Ljava/lang/String;I)Z
+Lcom/android/server/pm/permission/PermissionsState;->hasPermissionRequiringReview(I)Z
+Lcom/android/server/am/ActivityManagerService$Lifecycle;-><init>(Landroid/content/Context;)V
+Lcom/android/server/am/ActivityManagerService;-><init>(Landroid/content/Context;Lcom/android/server/wm/ActivityTaskManagerService;)V
+Lcom/android/server/pm/Settings;->readSharedUserLPw(Lorg/xmlpull/v1/XmlPullParser;)V
+Lcom/android/server/pm/permission/PermissionsState;->updatePermissionFlags(Lcom/android/server/pm/permission/BasePermission;III)Z
+Lcom/android/server/pm/permission/PermissionsState;->ensurePermissionData(Lcom/android/server/pm/permission/BasePermission;)Lcom/android/server/pm/permission/PermissionsState$PermissionData;
+Lcom/android/server/am/BatteryExternalStatsWorker$1;->run()V
+Lcom/android/server/am/BatteryExternalStatsWorker;->updateExternalStatsLocked(Ljava/lang/String;IZZZ)V
+Lcom/android/server/pm/permission/PermissionsState$PermissionData;->grant(I)Z
+Lcom/android/server/am/BatteryExternalStatsWorker$2;->run()V
+Lcom/android/server/pm/permission/PermissionSettings;->getPermission(Ljava/lang/String;)Lcom/android/server/pm/permission/BasePermission;
+Lcom/android/server/pm/permission/PermissionSettings;->getPermissionLocked(Ljava/lang/String;)Lcom/android/server/pm/permission/BasePermission;
+Lcom/android/server/pm/permission/PermissionSettings;->getPermissionTreeLocked(Ljava/lang/String;)Lcom/android/server/pm/permission/BasePermission;
+Lcom/android/server/pm/Settings;->readDisabledSysPackageLPw(Lorg/xmlpull/v1/XmlPullParser;)V
+Lcom/android/server/pm/permission/PermissionsState$PermissionData;->updateFlags(III)Z
+Lcom/android/server/pm/PackageSignatures;->readCertsListXml(Lorg/xmlpull/v1/XmlPullParser;Ljava/util/ArrayList;Ljava/util/ArrayList;IZLandroid/content/pm/PackageParser$SigningDetails$Builder;)I
+Lcom/android/server/pm/permission/PermissionsState$PermissionData;-><init>(Lcom/android/server/pm/permission/PermissionsState$PermissionData;)V
+Lcom/android/server/pm/permission/PermissionSettings;->readPermissions(Landroid/util/ArrayMap;Lorg/xmlpull/v1/XmlPullParser;)V
+Lcom/android/server/pm/permission/PermissionSettings;->readPermissions(Lorg/xmlpull/v1/XmlPullParser;)V
+Lcom/android/server/pm/Settings$RuntimePermissionPersistence;->readStateForUserSyncLPr(I)V
+Lcom/android/server/pm/Settings$RuntimePermissionPersistence;->parseRuntimePermissionsLPr(Lorg/xmlpull/v1/XmlPullParser;I)V
+Lcom/android/server/pm/Settings$RuntimePermissionPersistence;->parsePermissionsLPr(Lorg/xmlpull/v1/XmlPullParser;Lcom/android/server/pm/permission/PermissionsState;I)V
+Lcom/android/server/pm/permission/BasePermission;->readLPw(Ljava/util/Map;Lorg/xmlpull/v1/XmlPullParser;)Z
+Lcom/android/server/pm/Settings;->writeKernelMappingLPr()V
+Lcom/android/server/pm/Settings;->writeKernelMappingLPr(Lcom/android/server/pm/PackageSetting;)V
+Lcom/android/server/pm/Settings;->writeKernelMappingLPr(Ljava/lang/String;I[I)V
+Lcom/android/server/pm/Settings;->readPackageRestrictionsLPr(I)V
+Lcom/android/server/am/ActivityManagerService$Injector;->getAppOpsService(Ljava/io/File;Landroid/os/Handler;)Lcom/android/server/appop/AppOpsService;
+Lcom/android/server/appop/AppOpsService;-><init>(Ljava/io/File;Landroid/os/Handler;)V
+Lcom/android/server/appop/AppOpsService;->readState()V
+Lcom/android/server/am/ProcessStatsService;-><init>(Lcom/android/server/am/ActivityManagerService;Ljava/io/File;)V
+Lcom/android/server/pm/PackageManagerService;->scanDirTracedLI(Ljava/io/File;IIJ)V
+Lcom/android/server/pm/PackageManagerService;->scanDirLI(Ljava/io/File;IIJ)V
+Lcom/android/server/pm/PackageManagerService;->addForInitLI(Landroid/content/pm/PackageParser$Package;IIJLandroid/os/UserHandle;)Landroid/content/pm/PackageParser$Package;
+Lcom/android/server/pm/PackageManagerService;->scanPackageChildLI(Landroid/content/pm/PackageParser$Package;IIJLandroid/os/UserHandle;)Landroid/content/pm/PackageParser$Package;
+Lcom/android/server/pm/KeySetManagerService;->readKeySetsLPw(Lorg/xmlpull/v1/XmlPullParser;Landroid/util/ArrayMap;)V
+Lcom/android/server/pm/ParallelPackageParser;->lambda$submit$0$ParallelPackageParser(Ljava/io/File;I)V
+Lcom/android/server/pm/-$$Lambda$ParallelPackageParser$FTtinPrp068lVeI7K6bC1tNE3iM;->run()V
+Lcom/android/server/pm/ParallelPackageParser;->parsePackage(Landroid/content/pm/PackageParser;Ljava/io/File;I)Landroid/content/pm/PackageParser$Package;
+Lcom/android/server/appop/AppOpsService;->readPackage(Lorg/xmlpull/v1/XmlPullParser;)V
+Lcom/android/server/pm/Settings;->addPackageLPw(Ljava/lang/String;Ljava/lang/String;Ljava/io/File;Ljava/io/File;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;IJIILjava/lang/String;Ljava/util/List;[Ljava/lang/String;[J)Lcom/android/server/pm/PackageSetting;
+Lcom/android/server/appop/AppOpsService;->readUid(Lorg/xmlpull/v1/XmlPullParser;Ljava/lang/String;)V
+Lcom/android/server/appop/AppOpsService;->readUidOps(Lorg/xmlpull/v1/XmlPullParser;)V
+Lcom/android/server/pm/PackageSetting;-><init>(Lcom/android/server/pm/PackageSetting;)V
+Lcom/android/server/pm/PackageSetting;-><init>(Ljava/lang/String;Ljava/lang/String;Ljava/io/File;Ljava/io/File;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;JIILjava/lang/String;Ljava/util/List;I[Ljava/lang/String;[J)V
+Lcom/android/server/pm/SELinuxMMAC;->readInstallPolicy()Z
+Lcom/android/server/pm/KeySetManagerService;->readKeysLPw(Lorg/xmlpull/v1/XmlPullParser;)V
+Lcom/android/server/pm/Settings;->writeIntToFile(Ljava/io/File;I)V
+Lcom/android/server/pm/PackageSettingBase;-><init>(Ljava/lang/String;Ljava/lang/String;Ljava/io/File;Ljava/io/File;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;JIILjava/lang/String;Ljava/util/List;[Ljava/lang/String;[J)V
+Lcom/android/server/appop/AppOpsService;->readOp(Lorg/xmlpull/v1/XmlPullParser;Lcom/android/server/appop/AppOpsService$UidState;Ljava/lang/String;Z)V
+Lcom/android/server/pm/SELinuxMMAC;->readSignerOrThrow(Lorg/xmlpull/v1/XmlPullParser;)Lcom/android/server/pm/Policy;
+Lcom/android/server/pm/Settings;->readComponentsLPr(Lorg/xmlpull/v1/XmlPullParser;)Landroid/util/ArraySet;
+Lcom/android/server/pm/KeySetManagerService;->readPublicKeyLPw(Lorg/xmlpull/v1/XmlPullParser;)V
+Lcom/android/server/pm/PackageManagerService;->scanPackageNewLI(Landroid/content/pm/PackageParser$Package;IIJLandroid/os/UserHandle;)Lcom/android/server/pm/PackageManagerService$ScanResult;
+Lcom/android/server/pm/permission/PermissionsState;->grantRuntimePermission(Lcom/android/server/pm/permission/BasePermission;I)I
+Lcom/android/server/pm/Policy$PolicyBuilder;->addSignature(Ljava/lang/String;)Lcom/android/server/pm/Policy$PolicyBuilder;
+Lcom/android/server/display/DisplayManagerService;-><init>(Landroid/content/Context;)V
+Lcom/android/server/display/DisplayManagerService;-><init>(Landroid/content/Context;Lcom/android/server/display/DisplayManagerService$Injector;)V
+Lcom/android/server/am/ActivityManagerService;->start()V
+Lcom/android/server/am/ActivityManagerService;->startAssociationLocked(ILjava/lang/String;IIJLandroid/content/ComponentName;Ljava/lang/String;)Lcom/android/server/am/ActivityManagerService$Association;
+Lcom/android/server/am/ActivityManagerService;->startIsolatedProcess(Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ILjava/lang/Runnable;)Z
+Lcom/android/server/am/ActivityManagerService;->startObservingNativeCrashes()V
+Lcom/android/server/am/ActivityManagerService;->startPersistentApps(I)V
+Lcom/android/server/am/ActivityManagerService;->startProcessLocked(Ljava/lang/String;Landroid/content/pm/ApplicationInfo;ZILjava/lang/String;Landroid/content/ComponentName;ZZZ)Lcom/android/server/am/ProcessRecord;
+Lcom/android/server/am/ActivityManagerService;->startService(Landroid/app/IApplicationThread;Landroid/content/Intent;Ljava/lang/String;ZLjava/lang/String;I)Landroid/content/ComponentName;
+PLcom/android/server/am/ActivityManagerService;->startUserInBackgroundWithListener(ILandroid/os/IProgressListener;)Z
+Lcom/android/server/am/ActivityManagerService$Lifecycle;->onStart()V
+Lcom/android/server/pm/PackageManagerService;->scanPackageOnlyLI(Lcom/android/server/pm/PackageManagerService$ScanRequest;ZJ)Lcom/android/server/pm/PackageManagerService$ScanResult;
+Lcom/android/server/pm/PackageSettingBase;->modifyUserState(I)Landroid/content/pm/PackageUserState;
+Lcom/android/server/pm/PackageSettingBase;->modifyUserStateComponents(IZZ)Landroid/content/pm/PackageUserState;
+Lcom/android/server/pm/Settings;->readDomainVerificationLPw(Lorg/xmlpull/v1/XmlPullParser;Lcom/android/server/pm/PackageSettingBase;)V
+Lcom/android/server/pm/PackageSettingBase;->setEnabled(IILjava/lang/String;)V
+Lcom/android/server/am/BatteryStatsService;-><init>(Landroid/content/Context;Ljava/io/File;Landroid/os/Handler;)V
+Lcom/android/server/pm/PackageManagerService;->commitReconciledScanResultLocked(Lcom/android/server/pm/PackageManagerService$ReconciledPackage;)V
+Lcom/android/server/pm/KeySetManagerService;->readKeySetListLPw(Lorg/xmlpull/v1/XmlPullParser;)V
+Lcom/android/server/appop/AppOpsService$Op;->accessed(JILjava/lang/String;II)V
+Lcom/android/server/wm/ActivityTaskManagerService;->initialize(Lcom/android/server/firewall/IntentFirewall;Lcom/android/server/am/PendingIntentController;Landroid/os/Looper;)V
+Lcom/android/server/pm/SettingBase;-><init>(II)V
+Lcom/android/server/pm/PackageManagerService;->locationIsPrivileged(Ljava/lang/String;)Z
+Lcom/android/server/power/PowerManagerService;-><init>(Landroid/content/Context;)V
+Lcom/android/server/power/PowerManagerService;-><init>(Landroid/content/Context;Lcom/android/server/power/PowerManagerService$Injector;)V
+Lcom/android/server/pm/permission/PermissionsState;->enforceValidUserId(I)V
+Lcom/android/server/Watchdog;->getInstance()Lcom/android/server/Watchdog;
+Lcom/android/server/Watchdog;-><init>()V
+Lcom/android/server/pm/PackageManagerService;->commitPackageSettings(Landroid/content/pm/PackageParser$Package;Landroid/content/pm/PackageParser$Package;Lcom/android/server/pm/PackageSetting;IZLcom/android/server/pm/PackageManagerService$ReconciledPackage;)V
+Lcom/android/server/pm/PackageSetting;->getPermissionsState()Lcom/android/server/pm/permission/PermissionsState;
+Lcom/android/server/pm/Settings;->registerExistingAppIdLPw(ILcom/android/server/pm/SettingBase;Ljava/lang/Object;)Z
+Lcom/android/server/pm/permission/PermissionManagerService;->create(Landroid/content/Context;Lcom/android/server/pm/permission/DefaultPermissionGrantPolicy$DefaultPermissionGrantedCallback;Ljava/lang/Object;)Lcom/android/server/pm/permission/PermissionManagerServiceInternal;
+Lcom/android/server/pm/Settings;->addSharedUserLPw(Ljava/lang/String;III)Lcom/android/server/pm/SharedUserSetting;
+Lcom/android/server/pm/PackageSettingBase;->init(Ljava/io/File;Ljava/io/File;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;J)V
+Lcom/android/server/appop/AppOpsService$Op;->updateProxyState(JILjava/lang/String;)V
+Lcom/android/server/display/DisplayManagerService$DisplayAdapterListener;->onDisplayDeviceEvent(Lcom/android/server/display/DisplayDevice;I)V
+Lcom/android/server/wm/ActivityTaskManagerService;->onActivityManagerInternalAdded()V
+Lcom/android/server/SystemService;->publishBinderService(Ljava/lang/String;Landroid/os/IBinder;)V
+Lcom/android/server/am/ActivityManagerService;->initPowerManagement()V
+Lcom/android/server/wm/ActivityTaskManagerService$Lifecycle;-><init>(Landroid/content/Context;)V
+Lcom/android/server/display/DisplayManagerService;->onStart()V
+Lcom/android/server/pm/Settings;->readPreferredActivitiesLPw(Lorg/xmlpull/v1/XmlPullParser;I)V
+Lcom/android/server/pm/PackageKeySetData;-><init>()V
+Lcom/android/server/display/DisplayManagerService;->registerDefaultDisplayAdapters()V
+Lcom/android/server/display/LocalDisplayAdapter;->registerLocked()V
+Lcom/android/server/ServiceThread;->run()V
+Lcom/android/server/display/DisplayModeDirector;-><init>(Landroid/content/Context;Landroid/os/Handler;)V
+Lcom/android/server/pm/Settings;->addPackageSettingLPw(Lcom/android/server/pm/PackageSetting;Lcom/android/server/pm/SharedUserSetting;)V
+Lcom/android/server/pm/permission/PermissionManagerService;-><init>(Landroid/content/Context;Lcom/android/server/pm/permission/DefaultPermissionGrantPolicy$DefaultPermissionGrantedCallback;Ljava/lang/Object;)V
+Lcom/android/server/appop/AppOpsService;->getUidStateLocked(IZ)Lcom/android/server/appop/AppOpsService$UidState;
+Lcom/android/server/am/BatteryStatsService;->fillRailDataStats(Lcom/android/internal/os/RailStats;)V
+Lcom/android/server/pm/SELinuxMMAC;->getSeInfo(Landroid/content/pm/PackageParser$Package;ZII)Ljava/lang/String;
+Lcom/android/server/pm/PackageManagerService;->collectCertificatesLI(Lcom/android/server/pm/PackageSetting;Landroid/content/pm/PackageParser$Package;ZZ)V
+Lcom/android/server/pm/PackageManagerService;->reconcilePackagesLocked(Lcom/android/server/pm/PackageManagerService$ReconcileRequest;Lcom/android/server/pm/KeySetManagerService;)Ljava/util/Map;
+Lcom/android/server/pm/permission/BasePermission;->readInt(Lorg/xmlpull/v1/XmlPullParser;Ljava/lang/String;Ljava/lang/String;I)I
+Lcom/android/server/pm/UserManagerService;-><init>(Landroid/content/Context;Lcom/android/server/pm/PackageManagerService;Lcom/android/server/pm/UserDataPreparer;Ljava/lang/Object;)V
+Lcom/android/server/pm/UserManagerService;-><init>(Landroid/content/Context;Lcom/android/server/pm/PackageManagerService;Lcom/android/server/pm/UserDataPreparer;Ljava/lang/Object;Ljava/io/File;)V
+Lcom/android/server/display/LocalDisplayAdapter;->tryConnectDisplayLocked(J)V
+Lcom/android/server/pm/PreferredActivity;-><init>(Landroid/content/IntentFilter;I[Landroid/content/ComponentName;Landroid/content/ComponentName;Z)V
+Lcom/android/server/pm/PackageManagerService;->preparePackageParserCache()Ljava/io/File;
+Lcom/android/server/pm/Policy$PolicyBuilder;->build()Lcom/android/server/pm/Policy;
+Lcom/android/server/LockGuard;->installLock(Ljava/lang/Object;I)Ljava/lang/Object;
+Lcom/android/server/LockGuard;->installLock(Ljava/lang/Object;IZ)Ljava/lang/Object;
+Lcom/android/server/SystemServiceManager;->startBootPhase(I)V
+Lcom/android/server/display/PersistentDataStore;->load()V
+Lcom/android/server/display/PersistentDataStore;->loadDisplaysFromXml(Lorg/xmlpull/v1/XmlPullParser;)V
+Lcom/android/server/display/PersistentDataStore;->loadFromXml(Lorg/xmlpull/v1/XmlPullParser;)V
+Lcom/android/server/display/PersistentDataStore;->loadRememberedWifiDisplaysFromXml(Lorg/xmlpull/v1/XmlPullParser;)V
+Lcom/android/server/wm/AppWarnings;-><init>(Lcom/android/server/wm/ActivityTaskManagerService;Landroid/content/Context;Landroid/os/Handler;Landroid/os/Handler;Ljava/io/File;)V
+Lcom/android/server/pm/PreferredComponent;-><init>(Lcom/android/server/pm/PreferredComponent$Callbacks;I[Landroid/content/ComponentName;Landroid/content/ComponentName;Z)V
+Lcom/android/server/pm/PreferredComponent;-><init>(Lcom/android/server/pm/PreferredComponent$Callbacks;Lorg/xmlpull/v1/XmlPullParser;)V
+Lcom/android/server/display/DisplayManagerService;->handleDisplayDeviceAdded(Lcom/android/server/display/DisplayDevice;)V
+Lcom/android/server/display/DisplayManagerService;->handleDisplayDeviceAddedLocked(Lcom/android/server/display/DisplayDevice;)V
+Lcom/android/server/display/LocalDisplayAdapter$LocalDisplayDevice;->getDisplayDeviceInfoLocked()Lcom/android/server/display/DisplayDeviceInfo;
+Lcom/android/server/pm/PackageSettingBase;->setUserState(IJIZZZZIZLjava/lang/String;Landroid/content/pm/SuspendDialogInfo;Landroid/os/PersistableBundle;Landroid/os/PersistableBundle;ZZLjava/lang/String;Landroid/util/ArraySet;Landroid/util/ArraySet;IIILjava/lang/String;)V
+Lcom/android/server/pm/Installer;->onStart()V
+Lcom/android/server/pm/Installer;->connect()V
+Lcom/android/server/lights/LightsService$LightImpl;-><init>(Lcom/android/server/lights/LightsService;Landroid/content/Context;I)V
+Lcom/android/server/pm/PackageManagerService;->addBuiltInSharedLibraryLocked(Ljava/lang/String;Ljava/lang/String;)Z
+Lcom/android/server/LockGuard;->findOrCreateLockInfo(Ljava/lang/Object;)Lcom/android/server/LockGuard$LockInfo;
+Lcom/android/server/lights/LightsService;-><init>(Landroid/content/Context;)V
+Lcom/android/server/pm/Policy;->getMatchedSeInfo(Landroid/content/pm/PackageParser$Package;)Ljava/lang/String;
+Lcom/android/server/ServiceThread;-><init>(Ljava/lang/String;IZ)V
+Lcom/android/server/wm/ActivityTaskManagerService;->createStackSupervisor()Lcom/android/server/wm/ActivityStackSupervisor;
+Lcom/android/server/Watchdog;->addMonitor(Lcom/android/server/Watchdog$Monitor;)V
+Lcom/android/server/wm/ActivityStackSupervisor;->initPowerManagement()V
+Lcom/android/server/wm/ActivityTaskManagerService;->onInitPowerManagement()V
+Lcom/android/server/pm/KeySetManagerService;->addScannedPackageLPw(Landroid/content/pm/PackageParser$Package;)V
+Lcom/android/server/am/BatteryStatsService;->initPowerManagement()V
+Lcom/android/server/wm/ActivityTaskManagerService;-><init>(Landroid/content/Context;)V
+Lcom/android/server/am/ProcessList;-><init>()V
+Lcom/android/server/pm/PackageManagerService;->commitSharedLibraryInfoLocked(Landroid/content/pm/SharedLibraryInfo;)V
+Lcom/android/server/pm/PackageManagerServiceUtils;->getLastModifiedTime(Landroid/content/pm/PackageParser$Package;)J
+Lcom/android/server/am/ProcessStatsService;->updateFile()V
+Lcom/android/server/pm/Policy$PolicyBuilder;->setGlobalSeinfoOrThrow(Ljava/lang/String;)Lcom/android/server/pm/Policy$PolicyBuilder;
+Lcom/android/server/wm/AppWarnings;->readConfigFromFileAmsThread()V
+Lcom/android/server/am/BatteryStatsService;->fillLowPowerStats(Lcom/android/internal/os/RpmStats;)V
+Lcom/android/server/display/DisplayManagerService;->handleDisplayDeviceChanged(Lcom/android/server/display/DisplayDevice;)V
+Lcom/android/server/firewall/IntentFirewall;-><init>(Lcom/android/server/firewall/IntentFirewall$AMSInterface;Landroid/os/Handler;)V
+Lcom/android/server/pm/PackageSettingBase;->getNotInstalledUserIds()[I
+Lcom/android/server/appop/AppOpsService$UidState;->evalForegroundOps(Landroid/util/SparseArray;)V
+Lcom/android/server/SystemServerInitThreadPool;->submit(Ljava/lang/Runnable;Ljava/lang/String;)Ljava/util/concurrent/Future;
+Lcom/android/server/pm/KeySetManagerService;->addSigningKeySetToPackageLPw(Lcom/android/server/pm/PackageSetting;Landroid/util/ArraySet;)V
+Lcom/android/server/pm/ComponentResolver;->addAllComponents(Landroid/content/pm/PackageParser$Package;Z)V
+Lcom/android/server/appop/AppOpsService;->publish(Landroid/content/Context;)V
+Lcom/android/server/power/PowerManagerService;->onStart()V
+Lcom/android/server/os/DeviceIdentifiersPolicyService;->onStart()V
+Lcom/android/server/uri/UriGrantsManagerService$Lifecycle;-><init>(Landroid/content/Context;)V
+Lcom/android/server/pm/PackageManagerService;->applyPolicy(Landroid/content/pm/PackageParser$Package;IILandroid/content/pm/PackageParser$Package;)V
+Lcom/android/server/pm/KeySetManagerService;->addRefCountsFromSavedPackagesLPw(Landroid/util/ArrayMap;)V
+Lcom/android/server/am/OomAdjuster;-><init>(Lcom/android/server/am/ActivityManagerService;Lcom/android/server/am/ProcessList;Lcom/android/server/am/ActiveUids;)V
+Lcom/android/server/am/ProcessList;->init(Lcom/android/server/am/ActivityManagerService;Lcom/android/server/am/ActiveUids;)V
+Lcom/android/server/pm/PackageManagerService$ScanRequest;-><init>(Landroid/content/pm/PackageParser$Package;Lcom/android/server/pm/SharedUserSetting;Landroid/content/pm/PackageParser$Package;Lcom/android/server/pm/PackageSetting;Lcom/android/server/pm/PackageSetting;Lcom/android/server/pm/PackageSetting;Ljava/lang/String;IIZLandroid/os/UserHandle;)V
+Lcom/android/server/pm/Settings;->writeUserRestrictionsLPw(Lcom/android/server/pm/PackageSetting;Lcom/android/server/pm/PackageSetting;)V
+PLcom/android/server/pm/permission/PermissionsState;-><init>(Lcom/android/server/pm/permission/PermissionsState;)V
+Lcom/android/server/pm/UserManagerService;->readUserListLP()V
+Lcom/android/server/RescueParty;->isUsbActive()Z
+Lcom/android/server/RescueParty;->isDisabled()Z
+Lcom/android/server/pm/SharedUserSetting;->addPackage(Lcom/android/server/pm/PackageSetting;)V
+Lcom/android/server/display/LocalDisplayAdapter$LocalDisplayDevice;-><init>(Lcom/android/server/display/LocalDisplayAdapter;Landroid/os/IBinder;J[Landroid/view/SurfaceControl$PhysicalDisplayInfo;I[I[IIZ)V
+Lcom/android/server/am/BatteryStatsService$WakeupReasonThread;->run()V
+Lcom/android/server/pm/PackageSettingBase;->doCopy(Lcom/android/server/pm/PackageSettingBase;)V
+Lcom/android/server/SystemServerInitThreadPool;->get()Lcom/android/server/SystemServerInitThreadPool;
+Lcom/android/server/pm/PreferredActivity;->onReadTag(Ljava/lang/String;Lorg/xmlpull/v1/XmlPullParser;)Z
+Lcom/android/server/FgThread;->getHandler()Landroid/os/Handler;
+Lcom/android/server/FgThread;->ensureThreadLocked()V
+Lcom/android/server/IntentResolver;->addFilter(Landroid/content/IntentFilter;)V
+Lcom/android/server/IntentResolver;->addFilter(Landroid/util/ArrayMap;Ljava/lang/String;Landroid/content/IntentFilter;)V
+Lcom/android/server/pm/PackageManagerService;->assertPackageIsValid(Landroid/content/pm/PackageParser$Package;II)V
+Lcom/android/server/pm/PackageManagerService;->getSettingsVersionForPackage(Landroid/content/pm/PackageParser$Package;)Lcom/android/server/pm/Settings$VersionInfo;
+Lcom/android/server/pm/KeySetManagerService;->getPublicKeysFromKeySetLPr(J)Landroid/util/ArraySet;
+Lcom/android/server/pm/ComponentResolver;->addActivitiesLocked(Landroid/content/pm/PackageParser$Package;Ljava/util/List;Z)V
+Lcom/android/server/pm/PackageManagerServiceCompilerMapping;->checkProperties()V
+Lcom/android/server/pm/Settings;->getSettingLPr(I)Lcom/android/server/pm/SettingBase;
+Lcom/android/server/uri/UriGrantsManagerService;-><init>(Landroid/content/Context;)V
+Lcom/android/server/pm/Settings;-><init>(Ljava/io/File;Lcom/android/server/pm/permission/PermissionSettings;Ljava/lang/Object;)V
+Lcom/android/server/uri/UriGrantsManagerService$Lifecycle;->onStart()V
+Lcom/android/server/wm/ActivityTaskManagerService$Lifecycle;->onStart()V
+Lcom/android/server/pm/PackageSetting;->updateFrom(Lcom/android/server/pm/PackageSetting;)V
+Lcom/android/server/display/DisplayModeDirector$SettingsObserver;-><init>(Lcom/android/server/display/DisplayModeDirector;Landroid/content/Context;Landroid/os/Handler;)V
+Lcom/android/server/power/batterysaver/BatterySaverController;-><init>(Ljava/lang/Object;Landroid/content/Context;Landroid/os/Looper;Lcom/android/server/power/batterysaver/BatterySaverPolicy;Lcom/android/server/power/batterysaver/BatterySavingStats;)V
+Lcom/android/server/wm/ActivityStackSupervisor;-><init>(Lcom/android/server/wm/ActivityTaskManagerService;Landroid/os/Looper;)V
+Lcom/android/server/PackageWatchdog;-><init>(Landroid/content/Context;)V
+Lcom/android/server/PackageWatchdog;->getInstance(Landroid/content/Context;)Lcom/android/server/PackageWatchdog;
+Lcom/android/server/pm/Settings;->getAllUsers(Lcom/android/server/pm/UserManagerService;)Ljava/util/List;
+Lcom/android/server/Watchdog;->addThread(Landroid/os/Handler;)V
+Lcom/android/server/Watchdog;->addThread(Landroid/os/Handler;J)V
+Lcom/android/server/wm/RecentTasks;-><init>(Lcom/android/server/wm/ActivityTaskManagerService;Lcom/android/server/wm/ActivityStackSupervisor;)V
+Lcom/android/server/pm/PackageSettingBase;->updateFrom(Lcom/android/server/pm/PackageSettingBase;)Lcom/android/server/pm/PackageSettingBase;
+Lcom/android/server/pm/UserManagerService;->getUsers(Z)Ljava/util/List;
+Lcom/android/server/firewall/IntentFirewall;->readRulesDir(Ljava/io/File;)V
+Lcom/android/server/wm/TaskChangeNotificationController;-><init>(Ljava/lang/Object;Lcom/android/server/wm/ActivityStackSupervisor;Landroid/os/Handler;)V
+Lcom/android/server/am/BatteryExternalStatsWorker;->awaitControllerInfo(Landroid/os/SynchronousResultReceiver;)Landroid/os/Parcelable;
+Lcom/android/server/display/DisplayManagerService;->addLogicalDisplayLocked(Lcom/android/server/display/DisplayDevice;)Lcom/android/server/display/LogicalDisplay;
+Lcom/android/server/display/DisplayManagerService;->updateLogicalDisplaysLocked()Z
+Lcom/android/server/display/LocalDisplayAdapter$LocalDisplayDevice;->updatePhysicalDisplayInfoLocked([Landroid/view/SurfaceControl$PhysicalDisplayInfo;I[I[II)Z
+Lcom/android/server/display/DisplayDeviceInfo;->toString()Ljava/lang/String;
+Lcom/android/server/UiThread;->run()V
+Lcom/android/server/pm/PackageKeySetData;->setProperSigningKeySet(J)V
+Lcom/android/server/UiThread;->ensureThreadLocked()V
+Lcom/android/server/UiThread;->getHandler()Landroid/os/Handler;
+Lcom/android/server/pm/Settings;->getPackageLPr(Ljava/lang/String;)Lcom/android/server/pm/PackageSetting;
+Lcom/android/server/IoThread;->ensureThreadLocked()V
+Lcom/android/server/IoThread;->getHandler()Landroid/os/Handler;
+Lcom/android/server/pm/Settings;->getInternalVersion()Lcom/android/server/pm/Settings$VersionInfo;
+Lcom/android/server/appop/AppOpsService$Op;->running(JJII)V
+Lcom/android/server/appop/AppOpsService$Op;->updateAccessTimeAndDuration(JJII)V
+Lcom/android/server/appop/AppOpsService$Op;->rejected(JILjava/lang/String;II)V
+Lcom/android/server/DisplayThread;->ensureThreadLocked()V
+Lcom/android/server/DisplayThread;->getHandler()Landroid/os/Handler;
+Lcom/android/server/am/UserController;-><init>(Lcom/android/server/am/UserController$Injector;)V
+Lcom/android/server/AnimationThread;->ensureThreadLocked()V
+Lcom/android/server/AnimationThread;->getHandler()Landroid/os/Handler;
+Lcom/android/server/wm/SurfaceAnimationThread;->ensureThreadLocked()V
+Lcom/android/server/wm/SurfaceAnimationThread;->getHandler()Landroid/os/Handler;
+Lcom/android/server/wm/ActivityStackSupervisor;->initialize()V
+Lcom/android/server/pm/PackageSettingBase;->readUserState(I)Landroid/content/pm/PackageUserState;
+Lcom/android/server/pm/PackageManagerServiceUtils;->getCompressedFiles(Ljava/lang/String;)[Ljava/io/File;
+Lcom/android/server/pm/Settings;->insertPackageSettingLPw(Lcom/android/server/pm/PackageSetting;Landroid/content/pm/PackageParser$Package;)V
+Lcom/android/server/pm/ComponentResolver$ActivityIntentResolver;->addActivity(Landroid/content/pm/PackageParser$Activity;Ljava/lang/String;Ljava/util/List;)V
+Lcom/android/server/pm/Installer;->invalidateMounts()V
+Lcom/android/server/power/PowerManagerService$NativeWrapper;->nativeInit(Lcom/android/server/power/PowerManagerService;)V
+Lcom/android/server/power/ThermalManagerService;->onStart()V
+Lcom/android/server/am/OomAdjProfiler;-><init>()V
+Lcom/android/server/pm/PackageManagerService;->maybeClearProfilesForUpgradesLI(Lcom/android/server/pm/PackageSetting;Landroid/content/pm/PackageParser$Package;)V
+Lcom/android/server/am/ActivityManagerConstants;-><init>(Lcom/android/server/am/ActivityManagerService;Landroid/os/Handler;)V
+Lcom/android/server/IntentResolver;-><init>()V
+Lcom/android/server/pm/Settings;->updatePackageSetting(Lcom/android/server/pm/PackageSetting;Lcom/android/server/pm/PackageSetting;Lcom/android/server/pm/SharedUserSetting;Ljava/io/File;Ljava/io/File;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;IILjava/util/List;Lcom/android/server/pm/UserManagerService;[Ljava/lang/String;[J)V
+Lcom/android/server/PackageWatchdog;->loadFromFile()V
+Lcom/android/server/power/batterysaver/BatterySaverPolicy;-><init>(Ljava/lang/Object;Landroid/content/Context;Lcom/android/server/power/batterysaver/BatterySavingStats;)V
+Lcom/android/server/power/AttentionDetector;-><init>(Ljava/lang/Runnable;Ljava/lang/Object;)V
+Lcom/android/server/pm/dex/DexManager;-><init>(Landroid/content/Context;Landroid/content/pm/IPackageManager;Lcom/android/server/pm/PackageDexOptimizer;Lcom/android/server/pm/Installer;Ljava/lang/Object;)V
+Lcom/android/server/appop/AppOpsService$Op;-><init>(Lcom/android/server/appop/AppOpsService$UidState;Ljava/lang/String;I)V
+Lcom/android/server/pm/UserManagerService;->readUserLP(I)Lcom/android/server/pm/UserManagerService$UserData;
+Lcom/android/server/pm/UserManagerService;->readUserLP(ILjava/io/InputStream;)Lcom/android/server/pm/UserManagerService$UserData;
+Lcom/android/server/pm/UserRestrictionsUtils;->readRestrictions(Lorg/xmlpull/v1/XmlPullParser;)Landroid/os/Bundle;
+Lcom/android/server/pm/UserRestrictionsUtils;->readRestrictions(Lorg/xmlpull/v1/XmlPullParser;Landroid/os/Bundle;)V
+Lcom/android/server/pm/PackageManagerService;->adjustScanFlags(ILcom/android/server/pm/PackageSetting;Lcom/android/server/pm/PackageSetting;Landroid/os/UserHandle;Landroid/content/pm/PackageParser$Package;)I
+Lcom/android/server/pm/SettingBase;->setFlags(I)V
+Lcom/android/server/display/LogicalDisplay;->updateLocked(Ljava/util/List;)V
+Lcom/android/server/Watchdog$HandlerChecker;->run()V
+Lcom/android/server/Watchdog;->run()V
+Lcom/android/server/display/DisplayAdapter$1;->run()V
+Lcom/android/server/display/DisplayManagerService$DisplayManagerHandler;->handleMessage(Landroid/os/Message;)V
+Lcom/android/server/pm/PackageManagerServiceCompilerMapping;->getAndCheckValidity(I)Ljava/lang/String;
+Lcom/android/server/pm/ParallelPackageParser;->take()Lcom/android/server/pm/ParallelPackageParser$ParseResult;
+Lcom/android/server/pm/KeySetManagerService;->assertScannedPackageValid(Landroid/content/pm/PackageParser$Package;)V
+Lcom/android/server/display/LocalDisplayAdapter$LocalDisplayDevice$1;->run()V
+Lcom/android/server/pm/PackageManagerServiceUtils;->verifySignatures(Lcom/android/server/pm/PackageSetting;Lcom/android/server/pm/PackageSetting;Landroid/content/pm/PackageParser$SigningDetails;ZZ)Z
+Lcom/android/server/pm/PackageManagerService;->getSharedLibLatestVersionSetting(Lcom/android/server/pm/PackageManagerService$ScanResult;)Lcom/android/server/pm/PackageSetting;
+Lcom/android/server/display/LocalDisplayAdapter$LocalDisplayDevice$1;->setDisplayBrightness(I)V
+Lcom/android/server/pm/PackageManagerService;->getLatestSharedLibraVersionLPr(Landroid/content/pm/PackageParser$Package;)Landroid/content/pm/SharedLibraryInfo;
+Lcom/android/server/pm/PackageManagerServiceCompilerMapping;->getSystemPropertyName(I)Ljava/lang/String;
+Lcom/android/server/lights/LightsService$LightImpl;->setLightLocked(IIIII)V
+Lcom/android/server/lights/LightsService$LightImpl;->setBrightness(I)V
+Lcom/android/server/lights/LightsService$LightImpl;->setBrightness(II)V
+Lcom/android/server/Watchdog$HandlerChecker;->scheduleCheckLocked()V
+Lcom/android/server/pm/permission/PermissionsState;->copyFrom(Lcom/android/server/pm/permission/PermissionsState;)V
+Lcom/android/server/pm/permission/PermissionManagerService$PermissionManagerServiceInternalImpl;->addAllPermissionGroups(Landroid/content/pm/PackageParser$Package;Z)V
+Lcom/android/server/RecoverySystemService;->onStart()V
+Lcom/android/server/display/DisplayManagerService;->onBootPhase(I)V
+Lcom/android/server/am/ProcessList;->updateOomLevels(IIZ)V
+Lcom/android/server/am/OomAdjProfiler;->batteryPowerChanged(Z)V
+Lcom/android/server/pm/UserManagerService;->hasManageUsersOrPermission(Ljava/lang/String;)Z
+Lcom/android/server/am/OomAdjProfiler;->scheduleSystemServerCpuTimeUpdate()V
+Lcom/android/server/pm/PackageManagerService$ReconcileRequest;-><init>(Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;Lcom/android/server/pm/PackageManagerService$1;)V
+Lcom/android/server/pm/PackageManagerService$ReconcileRequest;-><init>(Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;)V
+Lcom/android/server/wm/ConfigurationContainer;->onConfigurationChanged(Landroid/content/res/Configuration;)V
+Lcom/android/server/wm/RootActivityContainer;-><init>(Lcom/android/server/wm/ActivityTaskManagerService;)V
+Lcom/android/server/wm/ActivityTaskManagerService;->createRecentTasks()Lcom/android/server/wm/RecentTasks;
+Lcom/android/server/am/OomAdjuster;->updateOomAdjLocked()V
+Lcom/android/server/am/OomAdjuster;->updateOomAdjLocked(Lcom/android/server/am/ProcessRecord;Z)Z
+Lcom/android/server/am/ActivityManagerService;->updateOomAdjLocked()V
+Lcom/android/server/am/ActivityManagerService;->updateOomAdjLocked(Lcom/android/server/am/ProcessRecord;Z)Z
+Lcom/android/server/pm/Settings;->getRenamedPackageLPr(Ljava/lang/String;)Ljava/lang/String;
+Lcom/android/server/am/OomAdjProfiler;->updateSystemServerCpuTime(ZZ)V
+Lcom/android/server/pm/UserManagerService;->getInstance()Lcom/android/server/pm/UserManagerService;
+Lcom/android/server/pm/permission/PermissionManagerService$PermissionManagerServiceInternalImpl;->addAllPermissions(Landroid/content/pm/PackageParser$Package;Z)V
+Lcom/android/server/power/PowerManagerService$Injector;->createBatterySaverPolicy(Ljava/lang/Object;Landroid/content/Context;Lcom/android/server/power/batterysaver/BatterySavingStats;)Lcom/android/server/power/batterysaver/BatterySaverPolicy;
+Lcom/android/server/power/ThermalManagerService;-><init>(Landroid/content/Context;)V
+Lcom/android/server/power/ThermalManagerService;-><init>(Landroid/content/Context;Lcom/android/server/power/ThermalManagerService$ThermalHalWrapper;)V
+Lcom/android/server/display/PersistentDataStore$Injector;->openRead()Ljava/io/InputStream;
+Lcom/android/server/pm/PackageManagerService$ReconciledPackage;-><init>(Lcom/android/server/pm/PackageManagerService$InstallArgs;Lcom/android/server/pm/PackageSetting;Lcom/android/server/pm/PackageManagerService$PackageInstalledInfo;Lcom/android/server/pm/PackageManagerService$PrepareResult;Lcom/android/server/pm/PackageManagerService$ScanResult;Lcom/android/server/pm/PackageManagerService$DeletePackageAction;Ljava/util/List;Landroid/content/pm/PackageParser$SigningDetails;ZZLcom/android/server/pm/PackageManagerService$1;)V
+Lcom/android/server/pm/ComponentResolver;-><init>(Lcom/android/server/pm/UserManagerService;Landroid/content/pm/PackageManagerInternal;Ljava/lang/Object;)V
+Lcom/android/server/wm/LaunchParamsController;->registerDefaultModifiers(Lcom/android/server/wm/ActivityStackSupervisor;)V
+Lcom/android/server/Watchdog$OpenFdMonitor;->create()Lcom/android/server/Watchdog$OpenFdMonitor;
+Lcom/android/server/SystemServiceManager;->warnIfTooLong(JLcom/android/server/SystemService;Ljava/lang/String;)V
+Lcom/android/server/am/UserController$Injector;->getLockPatternUtils()Lcom/android/internal/widget/LockPatternUtils;
+Lcom/android/server/am/PendingIntentController;-><init>(Landroid/os/Looper;Lcom/android/server/am/UserController;)V
+Lcom/android/server/am/BroadcastQueue;-><init>(Lcom/android/server/am/ActivityManagerService;Landroid/os/Handler;Ljava/lang/String;Lcom/android/server/am/BroadcastConstants;Z)V
+Lcom/android/server/display/LocalDisplayAdapter$LocalDisplayDevice$1;->setDisplayState(I)V
+Lcom/android/server/am/BatteryStatsService$WakeupReasonThread;->waitWakeup()Ljava/lang/String;
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 46c2a85..b4ee0b1 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -2402,7 +2402,9 @@
 
                 // Update the view states first...
                 mCurrentViewId = viewState.id;
-                viewState.setCurrentValue(value);
+                if (value != null) {
+                    viewState.setCurrentValue(value);
+                }
 
                 if (mCompatMode && (viewState.getState() & ViewState.STATE_URL_BAR) != 0) {
                     if (sDebug) Slog.d(TAG, "Ignoring VIEW_ENTERED on URL BAR (id=" + id + ")");
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index d5a7c81..dc0bdb3 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -31,14 +31,11 @@
 import android.app.job.JobParameters;
 import android.app.job.JobScheduler;
 import android.app.job.JobService;
-import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
-import android.content.IntentFilter;
 import android.content.pm.PackageManager;
 import android.os.Binder;
-import android.os.FileUtils;
 import android.os.IBinder;
 import android.os.ParcelFileDescriptor;
 import android.os.Trace;
@@ -49,13 +46,10 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.DumpUtils;
-import com.android.server.SystemConfig;
 import com.android.server.SystemService;
 
-import java.io.File;
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
-import java.util.Collections;
 import java.util.Set;
 
 /**
@@ -74,64 +68,16 @@
     @VisibleForTesting
     static final String DUMP_RUNNING_USERS_MESSAGE = "Backup Manager is running for users:";
 
-    // The published binder is a singleton Trampoline object that calls through to the proper code.
-    // This indirection lets us turn down the heavy implementation object on the fly without
-    // disturbing binders that have been cached elsewhere in the system.
-    private static Trampoline sInstance;
-
-    static Trampoline getInstance() {
-        // Always constructed during system bring up, so no need to lazy-init.
-        return sInstance;
-    }
-
     private final Context mContext;
     private final Trampoline mTrampoline;
 
     // Keeps track of all unlocked users registered with this service. Indexed by user id.
     private final SparseArray<UserBackupManagerService> mServiceUsers = new SparseArray<>();
 
-    private Set<ComponentName> mTransportWhitelist;
-
-    private final BroadcastReceiver mUserRemovedReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            if (Intent.ACTION_USER_REMOVED.equals(intent.getAction())) {
-                int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
-                if (userId > 0) { // for only non system users
-                    onRemovedNonSystemUser(userId);
-                }
-            }
-        }
-    };
-
     /** Instantiate a new instance of {@link BackupManagerService}. */
     public BackupManagerService(Context context, Trampoline trampoline) {
         mContext = checkNotNull(context);
         mTrampoline = checkNotNull(trampoline);
-
-        // Set up our transport options.
-        SystemConfig systemConfig = SystemConfig.getInstance();
-        mTransportWhitelist = systemConfig.getBackupTransportWhitelist();
-        if (mTransportWhitelist == null) {
-            mTransportWhitelist = Collections.emptySet();
-        }
-
-        mContext.registerReceiver(mUserRemovedReceiver,
-                new IntentFilter(Intent.ACTION_USER_REMOVED));
-    }
-
-    /**
-     * Remove backup state for non system {@code userId} when the user is removed from the device.
-     * For non system users, backup state is stored in both the user's own dir and the system dir.
-     * When the user is removed, the user's own dir gets removed by the OS. This method ensures that
-     * the part of the user backup state which is in the system dir also gets removed.
-     */
-    private void onRemovedNonSystemUser(int userId) {
-        Slog.i(TAG, "Removing state for non system user " + userId);
-        File dir = UserBackupManagerFiles.getStateDirInSystemDir(userId);
-        if (!FileUtils.deleteContentsAndDir(dir)) {
-            Slog.w(TAG, "Failed to delete state dir for removed user: " + userId);
-        }
     }
 
     /**
@@ -157,7 +103,7 @@
      * UserBackupManagerService} and registering it with this service.
      */
     @VisibleForTesting
-    protected void startServiceForUser(int userId) {
+    protected void startServiceForUser(int userId, Set<ComponentName> transportWhitelist) {
         if (mServiceUsers.get(userId) != null) {
             Slog.i(TAG, "userId " + userId + " already started, so not starting again");
             return;
@@ -165,7 +111,7 @@
 
         UserBackupManagerService userBackupManagerService =
                 UserBackupManagerService.createAndInitializeService(
-                        userId, mContext, mTrampoline, mTransportWhitelist);
+                        userId, mContext, mTrampoline, transportWhitelist);
         startServiceForUser(userId, userBackupManagerService);
     }
 
@@ -195,16 +141,20 @@
     }
 
     boolean isAbleToServeUser(int userId) {
-        return getServiceUsers().get(UserHandle.USER_SYSTEM) != null
-                && getServiceUsers().get(userId) != null;
+        return getUserServices().get(UserHandle.USER_SYSTEM) != null
+                && getUserServices().get(userId) != null;
     }
 
     /**
-     *  Returns a lst of users currently unlocked that have a
-     *  {@link UserBackupManagerService} registered.
+     *  Returns a list of users currently unlocked that have a {@link UserBackupManagerService}
+     *  registered.
+     *
+     *  Warning: Do NOT modify returned object as it's used inside.
+     *
+     *  TODO: Return a copy or only expose read-only information through other means.
      */
     @VisibleForTesting
-    public SparseArray<UserBackupManagerService> getServiceUsers() {
+    public SparseArray<UserBackupManagerService> getUserServices() {
         return mServiceUsers;
     }
 
@@ -370,19 +320,6 @@
                 : userBackupManagerService.listAllTransportComponents();
     }
 
-    /** Report all system whitelisted transports. */
-    @Nullable
-    public String[] getTransportWhitelist() {
-        // No permission check, intentionally.
-        String[] whitelistedTransports = new String[mTransportWhitelist.size()];
-        int i = 0;
-        for (ComponentName component : mTransportWhitelist) {
-            whitelistedTransports[i] = component.flattenToShortString();
-            i++;
-        }
-        return whitelistedTransports;
-    }
-
     /**
      * Update the attributes of the transport identified by {@code transportComponent}. If the
      * specified transport has not been bound at least once (for registration), this call will be
@@ -495,7 +432,8 @@
 
     /**
      * Returns a {@link UserHandle} for the user that has {@code ancestralSerialNumber} as the
-     * serial number of the its ancestral work profile.
+     * serial number of the its ancestral work profile or null if there is no {@link
+     * UserBackupManagerService} associated with that user.
      *
      * <p> The ancestral work profile is set by {@link #setAncestralSerialNumber(long)}
      * and it corresponds to the profile that was used to restore to the callers profile.
@@ -504,16 +442,18 @@
     public UserHandle getUserForAncestralSerialNumber(long ancestralSerialNumber) {
         int callingUserId = Binder.getCallingUserHandle().getIdentifier();
         long oldId = Binder.clearCallingIdentity();
-        int[] userIds;
+        final int[] userIds;
         try {
-            userIds = mContext.getSystemService(UserManager.class).getProfileIds(callingUserId,
-                    false);
+            userIds =
+                    mContext
+                            .getSystemService(UserManager.class)
+                            .getProfileIds(callingUserId, false);
         } finally {
             Binder.restoreCallingIdentity(oldId);
         }
 
         for (int userId : userIds) {
-            UserBackupManagerService userBackupManagerService = getServiceUsers().get(userId);
+            UserBackupManagerService userBackupManagerService = getUserServices().get(userId);
             if (userBackupManagerService != null) {
                 if (userBackupManagerService.getAncestralSerialNumber() == ancestralSerialNumber) {
                     return UserHandle.of(userId);
@@ -880,28 +820,35 @@
     }
 
     /** Implementation to receive lifecycle event callbacks for system services. */
-    public static final class Lifecycle extends SystemService {
+    public static class Lifecycle extends SystemService {
         public Lifecycle(Context context) {
+            this(context, new Trampoline(context));
+        }
+
+        @VisibleForTesting
+        Lifecycle(Context context, Trampoline trampoline) {
             super(context);
-            sInstance = new Trampoline(context);
+            Trampoline.sInstance = trampoline;
         }
 
         @Override
         public void onStart() {
-            publishBinderService(Context.BACKUP_SERVICE, sInstance);
+            publishService(Context.BACKUP_SERVICE, Trampoline.sInstance);
         }
 
         @Override
         public void onUnlockUser(int userId) {
-            if (userId == UserHandle.USER_SYSTEM) {
-                sInstance.initializeService();
-            }
-            sInstance.unlockUser(userId);
+            Trampoline.sInstance.onUnlockUser(userId);
         }
 
         @Override
         public void onStopUser(int userId) {
-            sInstance.stopUser(userId);
+            Trampoline.sInstance.onStopUser(userId);
+        }
+
+        @VisibleForTesting
+        void publishService(String name, IBinder service) {
+            publishBinderService(name, service);
         }
     }
 }
diff --git a/services/backup/java/com/android/server/backup/FullBackupJob.java b/services/backup/java/com/android/server/backup/FullBackupJob.java
index 088e1f9..19a8543 100644
--- a/services/backup/java/com/android/server/backup/FullBackupJob.java
+++ b/services/backup/java/com/android/server/backup/FullBackupJob.java
@@ -91,7 +91,7 @@
             mParamsForUser.put(userId, params);
         }
 
-        Trampoline service = BackupManagerService.getInstance();
+        Trampoline service = Trampoline.getInstance();
         return service.beginFullBackup(userId, this);
     }
 
@@ -105,7 +105,7 @@
             }
         }
 
-        Trampoline service = BackupManagerService.getInstance();
+        Trampoline service = Trampoline.getInstance();
         service.endFullBackup(userId);
 
         return false;
diff --git a/services/backup/java/com/android/server/backup/KeyValueBackupJob.java b/services/backup/java/com/android/server/backup/KeyValueBackupJob.java
index ac43fc3..7b5dbd7 100644
--- a/services/backup/java/com/android/server/backup/KeyValueBackupJob.java
+++ b/services/backup/java/com/android/server/backup/KeyValueBackupJob.java
@@ -144,7 +144,7 @@
         }
 
         // Time to run a key/value backup!
-        Trampoline service = BackupManagerService.getInstance();
+        Trampoline service = Trampoline.getInstance();
         try {
             service.backupNowForUser(userId);
         } catch (RemoteException e) {}
diff --git a/services/backup/java/com/android/server/backup/Trampoline.java b/services/backup/java/com/android/server/backup/Trampoline.java
index f4b6645..59d9c0e 100644
--- a/services/backup/java/com/android/server/backup/Trampoline.java
+++ b/services/backup/java/com/android/server/backup/Trampoline.java
@@ -16,8 +16,11 @@
 
 package com.android.server.backup;
 
+import static com.android.internal.util.Preconditions.checkNotNull;
 import static com.android.server.backup.BackupManagerService.TAG;
 
+import static java.util.Collections.emptySet;
+
 import android.Manifest;
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
@@ -29,10 +32,13 @@
 import android.app.backup.IFullBackupRestoreObserver;
 import android.app.backup.IRestoreSession;
 import android.app.backup.ISelectBackupTransportCallback;
+import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.IntentFilter;
 import android.os.Binder;
+import android.os.FileUtils;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.IBinder;
@@ -40,19 +46,21 @@
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.SystemProperties;
-import android.os.Trace;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.util.Slog;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.DumpUtils;
+import com.android.server.SystemConfig;
 import com.android.server.backup.utils.RandomAccessFileUtils;
 
 import java.io.File;
 import java.io.FileDescriptor;
 import java.io.IOException;
 import java.io.PrintWriter;
+import java.util.Set;
 
 /**
  * A proxy to the {@link BackupManagerService} implementation.
@@ -73,9 +81,6 @@
  * Temporary disabling is controlled by {@link #setBackupServiceActive(int, boolean)} through
  * privileged callers (currently {@link DevicePolicyManager}). This is called on {@link
  * UserHandle#USER_SYSTEM} and disables backup for all users.
- *
- * <p>Creation of the backup service is done when {@link UserHandle#USER_SYSTEM} is unlocked. The
- * system user is unlocked before any other users.
  */
 public class Trampoline extends IBackupManager.Stub {
     /**
@@ -101,6 +106,12 @@
 
     private static final String BACKUP_THREAD = "backup";
 
+    static Trampoline sInstance;
+
+    static Trampoline getInstance() {
+        return checkNotNull(sInstance);
+    }
+
     private final Context mContext;
     private final UserManager mUserManager;
 
@@ -109,8 +120,24 @@
     // TODD(b/121198006): remove this object and synchronized all methods on "this".
     private final Object mStateLock = new Object();
 
-    private volatile BackupManagerService mService;
+    // TODO: This is not marked as final because of test code. Since we'll merge BMS and Trampoline,
+    // it doesn't make sense to refactor for final. It's never null.
+    @VisibleForTesting
+    protected volatile BackupManagerService mService;
     private final Handler mHandler;
+    private final Set<ComponentName> mTransportWhitelist;
+
+    private final BroadcastReceiver mUserRemovedReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (Intent.ACTION_USER_REMOVED.equals(intent.getAction())) {
+                int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
+                if (userId > 0) { // for only non system users
+                    mHandler.post(() -> onRemovedNonSystemUser(userId));
+                }
+            }
+        }
+    };
 
     public Trampoline(Context context) {
         mContext = context;
@@ -120,6 +147,18 @@
         handlerThread.start();
         mHandler = new Handler(handlerThread.getLooper());
         mUserManager = UserManager.get(context);
+        mService = new BackupManagerService(mContext, this);
+        Set<ComponentName> transportWhitelist =
+                SystemConfig.getInstance().getBackupTransportWhitelist();
+        mTransportWhitelist = (transportWhitelist == null) ? emptySet() : transportWhitelist;
+        mContext.registerReceiver(
+                mUserRemovedReceiver, new IntentFilter(Intent.ACTION_USER_REMOVED));
+    }
+
+    // TODO: Remove this when we implement DI by injecting in the construtor.
+    @VisibleForTesting
+    Handler getBackupHandler() {
+        return mHandler;
     }
 
     protected boolean isBackupDisabled() {
@@ -150,6 +189,20 @@
         return UserBackupManagerFiles.getStateFileInSystemDir(BACKUP_ACTIVATED_FILENAME, userId);
     }
 
+    /**
+     * Remove backup state for non system {@code userId} when the user is removed from the device.
+     * For non system users, backup state is stored in both the user's own dir and the system dir.
+     * When the user is removed, the user's own dir gets removed by the OS. This method ensures that
+     * the part of the user backup state which is in the system dir also gets removed.
+     */
+    private void onRemovedNonSystemUser(int userId) {
+        Slog.i(TAG, "Removing state for non system user " + userId);
+        File dir = UserBackupManagerFiles.getStateDirInSystemDir(userId);
+        if (!FileUtils.deleteContentsAndDir(dir)) {
+            Slog.w(TAG, "Failed to delete state dir for removed user: " + userId);
+        }
+    }
+
     // TODO (b/124359804) move to util method in FileUtils
     private void createFile(File file) throws IOException {
         if (file.exists()) {
@@ -205,7 +258,7 @@
     // This method should not perform any I/O (e.g. do not call isBackupActivatedForUser),
     // it's used in multiple places where I/O waits would cause system lock-ups.
     private boolean isUserReadyForBackup(int userId) {
-        return mService != null && mService.isAbleToServeUser(userId);
+        return mService.isAbleToServeUser(userId);
     }
 
     /**
@@ -230,68 +283,55 @@
         return mUserManager;
     }
 
-    protected BackupManagerService createBackupManagerService() {
-        return new BackupManagerService(mContext, this);
-    }
-
     protected void postToHandler(Runnable runnable) {
         mHandler.post(runnable);
     }
 
     /**
-     * Called from {@link BackupManagerService.Lifecycle} when the system user is unlocked. Attempts
-     * to initialize {@link BackupManagerService}. Offloads work onto the handler thread {@link
-     * #mHandlerThread} to keep unlock time low.
-     */
-    void initializeService() {
-        postToHandler(
-                () -> {
-                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "backup init");
-                    if (mGlobalDisable) {
-                        Slog.i(TAG, "Backup service not supported");
-                        return;
-                    }
-                    synchronized (mStateLock) {
-                        if (mService == null) {
-                            mService = createBackupManagerService();
-                        }
-                    }
-                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
-                });
-    }
-
-    /**
      * Called from {@link BackupManagerService.Lifecycle} when a user {@code userId} is unlocked.
      * Starts the backup service for this user if backup is active for this user. Offloads work onto
-     * the handler thread {@link #mHandlerThread} to keep unlock time low.
+     * the handler thread {@link #mHandlerThread} to keep unlock time low since backup is not
+     * essential for device functioning.
      */
-    void unlockUser(int userId) {
+    void onUnlockUser(int userId) {
         postToHandler(() -> startServiceForUser(userId));
     }
 
     private void startServiceForUser(int userId) {
         // We know that the user is unlocked here because it is called from setBackupServiceActive
         // and unlockUser which have these guarantees. So we can check if the file exists.
-        if (mService != null && isBackupActivatedForUser(userId)) {
-            Slog.i(TAG, "Starting service for user: " + userId);
-            mService.startServiceForUser(userId);
+        if (mGlobalDisable) {
+            Slog.i(TAG, "Backup service not supported");
+            return;
         }
+        if (!isBackupActivatedForUser(userId)) {
+            Slog.i(TAG, "Backup not activated for user " + userId);
+            return;
+        }
+        Slog.i(TAG, "Starting service for user: " + userId);
+        mService.startServiceForUser(userId, mTransportWhitelist);
     }
 
     /**
      * Called from {@link BackupManagerService.Lifecycle} when a user {@code userId} is stopped.
      * Offloads work onto the handler thread {@link #mHandlerThread} to keep stopping time low.
      */
-    void stopUser(int userId) {
+    void onStopUser(int userId) {
         postToHandler(
                 () -> {
-                    if (mService != null) {
+                    if (!mGlobalDisable) {
                         Slog.i(TAG, "Stopping service for user: " + userId);
                         mService.stopServiceForUser(userId);
                     }
                 });
     }
 
+    /** Returns {@link UserBackupManagerService} for user {@code userId}. */
+    @Nullable
+    public UserBackupManagerService getUserService(int userId) {
+        return mService.getUserServices().get(userId);
+    }
+
     /**
      * The system user and managed profiles can only be acted on by callers in the system or root
      * processes. Other users can be acted on by callers who have both android.permission.BACKUP and
@@ -350,9 +390,6 @@
         synchronized (mStateLock) {
             Slog.i(TAG, "Making backup " + (makeActive ? "" : "in") + "active");
             if (makeActive) {
-                if (mService == null) {
-                    mService = createBackupManagerService();
-                }
                 try {
                     activateBackupForUserLocked(userId);
                 } catch (IOException e) {
@@ -380,7 +417,7 @@
                 }
                 //TODO(b/121198006): loop through active users that have work profile and
                 // stop them as well.
-                stopUser(userId);
+                onStopUser(userId);
             }
         }
     }
@@ -388,8 +425,7 @@
     // IBackupManager binder API
 
     /**
-     * Querying activity state of backup service. Calling this method before initialize yields
-     * undefined result.
+     * Querying activity state of backup service.
      *
      * @param userId The user in which the activity state of backup service is queried.
      * @return true if the service is active.
@@ -397,7 +433,7 @@
     @Override
     public boolean isBackupServiceActive(int userId) {
         synchronized (mStateLock) {
-            return mService != null && isBackupActivatedForUser(userId);
+            return !mGlobalDisable && isBackupActivatedForUser(userId);
         }
     }
 
@@ -598,8 +634,8 @@
     @Override
     @Nullable
     public ComponentName getCurrentTransportComponentForUser(int userId) {
-        return (isUserReadyForBackup(userId)) ? mService.getCurrentTransportComponent(userId)
-                : null;
+        return (isUserReadyForBackup(userId))
+                ? mService.getCurrentTransportComponent(userId) : null;
     }
 
     @Override
@@ -614,14 +650,24 @@
 
     @Override
     public ComponentName[] listAllTransportComponentsForUser(int userId) throws RemoteException {
-        return (isUserReadyForBackup(userId)) ? mService.listAllTransportComponents(userId)
-                : null;
+        return (isUserReadyForBackup(userId))
+                ? mService.listAllTransportComponents(userId) : null;
     }
 
     @Override
     public String[] getTransportWhitelist() {
         int userId = binderGetCallingUserId();
-        return (isUserReadyForBackup(userId)) ? mService.getTransportWhitelist() : null;
+        if (!isUserReadyForBackup(userId)) {
+            return null;
+        }
+        // No permission check, intentionally.
+        String[] whitelistedTransports = new String[mTransportWhitelist.size()];
+        int i = 0;
+        for (ComponentName component : mTransportWhitelist) {
+            whitelistedTransports[i] = component.flattenToShortString();
+            i++;
+        }
+        return whitelistedTransports;
     }
 
     @Override
@@ -648,8 +694,8 @@
     @Override
     public String selectBackupTransportForUser(int userId, String transport)
             throws RemoteException {
-        return (isUserReadyForBackup(userId)) ? mService.selectBackupTransport(userId, transport)
-                : null;
+        return (isUserReadyForBackup(userId))
+                ? mService.selectBackupTransport(userId, transport) : null;
     }
 
     @Override
@@ -700,8 +746,8 @@
     @Override
     public Intent getDataManagementIntentForUser(int userId, String transport)
             throws RemoteException {
-        return isUserReadyForBackup(userId) ? mService.getDataManagementIntent(userId, transport)
-                : null;
+        return isUserReadyForBackup(userId)
+                ? mService.getDataManagementIntent(userId, transport) : null;
     }
 
     @Override
@@ -784,15 +830,15 @@
 
     @Override
     @Nullable public UserHandle getUserForAncestralSerialNumber(long ancestralSerialNumber) {
-        if (mService != null) {
-            return mService.getUserForAncestralSerialNumber(ancestralSerialNumber);
+        if (mGlobalDisable) {
+            return null;
         }
-        return null;
+        return mService.getUserForAncestralSerialNumber(ancestralSerialNumber);
     }
 
     @Override
     public void setAncestralSerialNumber(long ancestralSerialNumber) {
-        if (mService != null) {
+        if (!mGlobalDisable) {
             mService.setAncestralSerialNumber(ancestralSerialNumber);
         }
     }
diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerService.java b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
index ed4e596..d599aab 100644
--- a/services/backup/java/com/android/server/backup/UserBackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
@@ -166,6 +166,53 @@
 
 /** System service that performs backup/restore operations. */
 public class UserBackupManagerService {
+    /**
+     * Wrapper over {@link PowerManager.WakeLock} to prevent double-free exceptions on release()
+     * after quit().
+     */
+    public static class BackupWakeLock {
+        private final PowerManager.WakeLock mPowerManagerWakeLock;
+        private boolean mHasQuit = false;
+
+        public BackupWakeLock(PowerManager.WakeLock powerManagerWakeLock) {
+            mPowerManagerWakeLock = powerManagerWakeLock;
+        }
+
+        /** Acquires the {@link PowerManager.WakeLock} if hasn't been quit. */
+        public synchronized void acquire() {
+            if (mHasQuit) {
+                Slog.v(TAG, "Ignore wakelock acquire after quit: " + mPowerManagerWakeLock.getTag());
+                return;
+            }
+            mPowerManagerWakeLock.acquire();
+        }
+
+        /** Releases the {@link PowerManager.WakeLock} if hasn't been quit. */
+        public synchronized void release() {
+            if (mHasQuit) {
+                Slog.v(TAG, "Ignore wakelock release after quit: " + mPowerManagerWakeLock.getTag());
+                return;
+            }
+            mPowerManagerWakeLock.release();
+        }
+
+        /**
+         * Returns true if the {@link PowerManager.WakeLock} has been acquired but not yet released.
+         */
+        public synchronized boolean isHeld() {
+            return mPowerManagerWakeLock.isHeld();
+        }
+
+        /** Release the {@link PowerManager.WakeLock} till it isn't held. */
+        public synchronized void quit() {
+            while (mPowerManagerWakeLock.isHeld()) {
+                Slog.v(TAG, "Releasing wakelock: " + mPowerManagerWakeLock.getTag());
+                mPowerManagerWakeLock.release();
+            }
+            mHasQuit = true;
+        }
+    }
+
     // Persistently track the need to do a full init.
     private static final String INIT_SENTINEL_FILE_NAME = "_need_init_";
 
@@ -252,7 +299,6 @@
     private final @UserIdInt int mUserId;
     private final BackupAgentTimeoutParameters mAgentTimeoutParameters;
     private final TransportManager mTransportManager;
-    private final HandlerThread mUserBackupThread;
 
     private final Context mContext;
     private final PackageManager mPackageManager;
@@ -263,7 +309,7 @@
     private final AlarmManager mAlarmManager;
     private final IStorageManager mStorageManager;
     private final BackupManagerConstants mConstants;
-    private final PowerManager.WakeLock mWakelock;
+    private final BackupWakeLock mWakelock;
     private final BackupHandler mBackupHandler;
 
     private final IBackupManager mBackupManagerBinder;
@@ -487,8 +533,7 @@
         mAgentTimeoutParameters.start();
 
         checkNotNull(userBackupThread, "userBackupThread cannot be null");
-        mUserBackupThread = userBackupThread;
-        mBackupHandler = new BackupHandler(this, userBackupThread.getLooper());
+        mBackupHandler = new BackupHandler(this, userBackupThread);
 
         // Set up our bookkeeping
         final ContentResolver resolver = context.getContentResolver();
@@ -588,7 +633,10 @@
         mBackupHandler.postDelayed(this::parseLeftoverJournals, INITIALIZATION_DELAY_MILLIS);
 
         // Power management
-        mWakelock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*backup*-" + userId);
+        mWakelock = new BackupWakeLock(
+                mPowerManager.newWakeLock(
+                        PowerManager.PARTIAL_WAKE_LOCK,
+                        "*backup*-" + userId + "-" + userBackupThread.getThreadId()));
 
         // Set up the various sorts of package tracking we do
         mFullBackupScheduleFile = new File(mBaseStateDir, "fb-schedule");
@@ -608,7 +656,7 @@
         mContext.unregisterReceiver(mRunBackupReceiver);
         mContext.unregisterReceiver(mRunInitReceiver);
         mContext.unregisterReceiver(mPackageTrackingReceiver);
-        mUserBackupThread.quit();
+        mBackupHandler.stop();
     }
 
     public @UserIdInt int getUserId() {
@@ -668,7 +716,7 @@
         mSetupComplete = setupComplete;
     }
 
-    public PowerManager.WakeLock getWakelock() {
+    public BackupWakeLock getWakelock() {
         return mWakelock;
     }
 
@@ -679,7 +727,7 @@
     @VisibleForTesting
     public void setWorkSource(@Nullable WorkSource workSource) {
         // TODO: This is for testing, unfortunately WakeLock is final and WorkSource is not exposed
-        mWakelock.setWorkSource(workSource);
+        mWakelock.mPowerManagerWakeLock.setWorkSource(workSource);
     }
 
     public Handler getBackupHandler() {
diff --git a/services/backup/java/com/android/server/backup/internal/BackupHandler.java b/services/backup/java/com/android/server/backup/internal/BackupHandler.java
index ba153bf..059b1b9 100644
--- a/services/backup/java/com/android/server/backup/internal/BackupHandler.java
+++ b/services/backup/java/com/android/server/backup/internal/BackupHandler.java
@@ -23,7 +23,7 @@
 import android.app.backup.RestoreSet;
 import android.content.Intent;
 import android.os.Handler;
-import android.os.Looper;
+import android.os.HandlerThread;
 import android.os.Message;
 import android.os.RemoteException;
 import android.os.UserHandle;
@@ -83,19 +83,47 @@
     // backup task state machine tick
     public static final int MSG_BACKUP_RESTORE_STEP = 20;
     public static final int MSG_OP_COMPLETE = 21;
+    // Release the wakelock. This is used to ensure we don't hold it after
+    // a user is removed. This will also terminate the looper thread.
+    public static final int MSG_STOP = 22;
 
     private final UserBackupManagerService backupManagerService;
     private final BackupAgentTimeoutParameters mAgentTimeoutParameters;
 
-    public BackupHandler(UserBackupManagerService backupManagerService, Looper looper) {
-        super(looper);
+    private final HandlerThread mBackupThread;
+    private volatile boolean mIsStopping = false;
+
+    public BackupHandler(
+            UserBackupManagerService backupManagerService, HandlerThread backupThread) {
+        super(backupThread.getLooper());
+        mBackupThread = backupThread;
         this.backupManagerService = backupManagerService;
         mAgentTimeoutParameters = Preconditions.checkNotNull(
                 backupManagerService.getAgentTimeoutParameters(),
                 "Timeout parameters cannot be null");
     }
 
+    /**
+     * Put the BackupHandler into a stopping state where the remaining messages on the queue will be
+     * silently dropped and the {@link WakeLock} held by the {@link UserBackupManagerService} will
+     * then be released.
+     */
+    public void stop() {
+        mIsStopping = true;
+        sendMessage(obtainMessage(BackupHandler.MSG_STOP));
+    }
+
     public void handleMessage(Message msg) {
+        if (msg.what == MSG_STOP) {
+            Slog.v(TAG, "Stopping backup handler");
+            backupManagerService.getWakelock().quit();
+            mBackupThread.quitSafely();
+        }
+
+        if (mIsStopping) {
+            // If we're finishing all other types of messages should be ignored
+            return;
+        }
 
         TransportManager transportManager = backupManagerService.getTransportManager();
         switch (msg.what) {
diff --git a/services/backup/java/com/android/server/backup/internal/RunInitializeReceiver.java b/services/backup/java/com/android/server/backup/internal/RunInitializeReceiver.java
index 97711e3..96d61e5 100644
--- a/services/backup/java/com/android/server/backup/internal/RunInitializeReceiver.java
+++ b/services/backup/java/com/android/server/backup/internal/RunInitializeReceiver.java
@@ -23,7 +23,6 @@
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
-import android.os.PowerManager;
 import android.util.Slog;
 
 import com.android.server.backup.UserBackupManagerService;
@@ -57,7 +56,8 @@
 
                 mUserBackupManagerService.clearPendingInits();
 
-                PowerManager.WakeLock wakelock = mUserBackupManagerService.getWakelock();
+                UserBackupManagerService.BackupWakeLock wakelock =
+                        mUserBackupManagerService.getWakelock();
                 wakelock.acquire();
                 OnTaskFinishedListener listener = caller -> wakelock.release();
 
diff --git a/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java b/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java
index 10304c3..5a57cdc 100644
--- a/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java
+++ b/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java
@@ -34,7 +34,6 @@
 import android.os.Binder;
 import android.os.Handler;
 import android.os.Message;
-import android.os.PowerManager;
 import android.util.Slog;
 
 import com.android.server.backup.TransportManager;
@@ -110,7 +109,7 @@
             // comes in.
             mBackupManagerService.getBackupHandler().removeMessages(MSG_RESTORE_SESSION_TIMEOUT);
 
-            PowerManager.WakeLock wakelock = mBackupManagerService.getWakelock();
+            UserBackupManagerService.BackupWakeLock wakelock = mBackupManagerService.getWakelock();
             wakelock.acquire();
 
             // Prevent lambda from leaking 'this'
@@ -392,7 +391,7 @@
         Handler backupHandler = mBackupManagerService.getBackupHandler();
         backupHandler.removeMessages(MSG_RESTORE_SESSION_TIMEOUT);
 
-        PowerManager.WakeLock wakelock = mBackupManagerService.getWakelock();
+        UserBackupManagerService.BackupWakeLock wakelock = mBackupManagerService.getWakelock();
         wakelock.acquire();
         if (MORE_DEBUG) {
             Slog.d(TAG, callerLogString);
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index d162441..fede487 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -2604,8 +2604,7 @@
             mConstants.dumpProto(proto, AlarmManagerServiceDumpProto.SETTINGS);
 
             if (mAppStateTracker != null) {
-                mAppStateTracker.dumpProto(proto,
-                        AlarmManagerServiceDumpProto.FORCE_APP_STANDBY_TRACKER);
+                mAppStateTracker.dumpProto(proto, AlarmManagerServiceDumpProto.APP_STATE_TRACKER);
             }
 
             proto.write(AlarmManagerServiceDumpProto.IS_INTERACTIVE, mInteractive);
diff --git a/services/core/java/com/android/server/AppStateTracker.java b/services/core/java/com/android/server/AppStateTracker.java
index 3a7b5d6..2c67c50 100644
--- a/services/core/java/com/android/server/AppStateTracker.java
+++ b/services/core/java/com/android/server/AppStateTracker.java
@@ -56,8 +56,8 @@
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.Preconditions;
 import com.android.internal.util.StatLogger;
-import com.android.server.ForceAppStandbyTrackerProto.ExemptedPackage;
-import com.android.server.ForceAppStandbyTrackerProto.RunAnyInBackgroundRestrictedPackages;
+import com.android.server.AppStateTrackerProto.ExemptedPackage;
+import com.android.server.AppStateTrackerProto.RunAnyInBackgroundRestrictedPackages;
 
 import java.io.PrintWriter;
 import java.util.Arrays;
@@ -1308,43 +1308,42 @@
         synchronized (mLock) {
             final long token = proto.start(fieldId);
 
-            proto.write(ForceAppStandbyTrackerProto.FORCE_ALL_APPS_STANDBY, mForceAllAppsStandby);
-            proto.write(ForceAppStandbyTrackerProto.IS_SMALL_BATTERY_DEVICE,
-                    isSmallBatteryDevice());
-            proto.write(ForceAppStandbyTrackerProto.FORCE_ALL_APPS_STANDBY_FOR_SMALL_BATTERY,
+            proto.write(AppStateTrackerProto.FORCED_APP_STANDBY_FEATURE_ENABLED,
+                    mForcedAppStandbyEnabled);
+            proto.write(AppStateTrackerProto.FORCE_ALL_APPS_STANDBY,
+                    isForceAllAppsStandbyEnabled());
+            proto.write(AppStateTrackerProto.IS_SMALL_BATTERY_DEVICE, isSmallBatteryDevice());
+            proto.write(AppStateTrackerProto.FORCE_ALL_APPS_STANDBY_FOR_SMALL_BATTERY,
                     mForceAllAppStandbyForSmallBattery);
-            proto.write(ForceAppStandbyTrackerProto.IS_PLUGGED_IN, mIsPluggedIn);
+            proto.write(AppStateTrackerProto.IS_PLUGGED_IN, mIsPluggedIn);
 
             for (int i = 0; i < mActiveUids.size(); i++) {
                 if (mActiveUids.valueAt(i)) {
-                    proto.write(ForceAppStandbyTrackerProto.ACTIVE_UIDS,
-                            mActiveUids.keyAt(i));
+                    proto.write(AppStateTrackerProto.ACTIVE_UIDS, mActiveUids.keyAt(i));
                 }
             }
 
             for (int i = 0; i < mForegroundUids.size(); i++) {
                 if (mForegroundUids.valueAt(i)) {
-                    proto.write(ForceAppStandbyTrackerProto.FOREGROUND_UIDS,
-                            mForegroundUids.keyAt(i));
+                    proto.write(AppStateTrackerProto.FOREGROUND_UIDS, mForegroundUids.keyAt(i));
                 }
             }
 
             for (int appId : mPowerWhitelistedAllAppIds) {
-                proto.write(ForceAppStandbyTrackerProto.POWER_SAVE_WHITELIST_APP_IDS, appId);
+                proto.write(AppStateTrackerProto.POWER_SAVE_WHITELIST_APP_IDS, appId);
             }
 
             for (int appId : mPowerWhitelistedUserAppIds) {
-                proto.write(ForceAppStandbyTrackerProto.POWER_SAVE_USER_WHITELIST_APP_IDS, appId);
+                proto.write(AppStateTrackerProto.POWER_SAVE_USER_WHITELIST_APP_IDS, appId);
             }
 
             for (int appId : mTempWhitelistedAppIds) {
-                proto.write(ForceAppStandbyTrackerProto.TEMP_POWER_SAVE_WHITELIST_APP_IDS, appId);
+                proto.write(AppStateTrackerProto.TEMP_POWER_SAVE_WHITELIST_APP_IDS, appId);
             }
 
             for (int i = 0; i < mExemptedPackages.size(); i++) {
                 for (int j = 0; j < mExemptedPackages.sizeAt(i); j++) {
-                    final long token2 = proto.start(
-                            ForceAppStandbyTrackerProto.EXEMPTED_PACKAGES);
+                    final long token2 = proto.start(AppStateTrackerProto.EXEMPTED_PACKAGES);
 
                     proto.write(ExemptedPackage.USER_ID, mExemptedPackages.keyAt(i));
                     proto.write(ExemptedPackage.PACKAGE_NAME, mExemptedPackages.valueAt(i, j));
@@ -1355,14 +1354,14 @@
 
             for (Pair<Integer, String> uidAndPackage : mRunAnyRestrictedPackages) {
                 final long token2 = proto.start(
-                        ForceAppStandbyTrackerProto.RUN_ANY_IN_BACKGROUND_RESTRICTED_PACKAGES);
+                        AppStateTrackerProto.RUN_ANY_IN_BACKGROUND_RESTRICTED_PACKAGES);
                 proto.write(RunAnyInBackgroundRestrictedPackages.UID, uidAndPackage.first);
                 proto.write(RunAnyInBackgroundRestrictedPackages.PACKAGE_NAME,
                         uidAndPackage.second);
                 proto.end(token2);
             }
 
-            mStatLogger.dumpProto(proto, ForceAppStandbyTrackerProto.STATS);
+            mStatLogger.dumpProto(proto, AppStateTrackerProto.STATS);
 
             proto.end(token);
         }
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 293ab02..e67ccc4 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -150,7 +150,6 @@
 import android.util.Pair;
 import android.util.Slog;
 import android.util.SparseArray;
-import android.util.SparseBooleanArray;
 import android.util.SparseIntArray;
 import android.util.Xml;
 
@@ -168,7 +167,6 @@
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.MessageUtils;
-import com.android.internal.util.WakeupMessage;
 import com.android.internal.util.XmlUtils;
 import com.android.server.am.BatteryStatsService;
 import com.android.server.connectivity.AutodestructReference;
@@ -305,7 +303,8 @@
     /** Flag indicating if background data is restricted. */
     private boolean mRestrictBackground;
 
-    final private Context mContext;
+    private final Context mContext;
+    private final Dependencies mDeps;
     // 0 is full bad, 100 is full good
     private int mDefaultInetConditionPublished = 0;
 
@@ -586,11 +585,6 @@
     private NetworkNotificationManager mNotifier;
     private LingerMonitor mLingerMonitor;
 
-    // sequence number for Networks; keep in sync with system/netd/NetworkController.cpp
-    private static final int MIN_NET_ID = 100; // some reserved marks
-    private static final int MAX_NET_ID = 65535 - 0x0400; // Top 1024 bits reserved by IpSecService
-    private int mNextNetId = MIN_NET_ID;
-
     // sequence number of NetworkRequests
     private int mNextNetworkRequestId = 1;
 
@@ -834,19 +828,113 @@
         }
     };
 
+    /**
+     * Dependencies of ConnectivityService, for injection in tests.
+     */
+    @VisibleForTesting
+    public static class Dependencies {
+        /**
+         * Get system properties to use in ConnectivityService.
+         */
+        public MockableSystemProperties getSystemProperties() {
+            return new MockableSystemProperties();
+        }
+
+        /**
+         * Create a HandlerThread to use in ConnectivityService.
+         */
+        public HandlerThread makeHandlerThread() {
+            return new HandlerThread("ConnectivityServiceThread");
+        }
+
+        /**
+         * Get a reference to the NetworkStackClient.
+         */
+        public NetworkStackClient getNetworkStack() {
+            return NetworkStackClient.getInstance();
+        }
+
+        /**
+         * @see Tethering
+         */
+        public Tethering makeTethering(@NonNull Context context,
+                @NonNull INetworkManagementService nms,
+                @NonNull INetworkStatsService statsService,
+                @NonNull INetworkPolicyManager policyManager,
+                @NonNull TetheringDependencies tetheringDeps) {
+            return new Tethering(context, nms, statsService, policyManager,
+                    IoThread.get().getLooper(), getSystemProperties(), tetheringDeps);
+        }
+
+        /**
+         * @see ProxyTracker
+         */
+        public ProxyTracker makeProxyTracker(@NonNull Context context,
+                @NonNull Handler connServiceHandler) {
+            return new ProxyTracker(context, connServiceHandler, EVENT_PROXY_HAS_CHANGED);
+        }
+
+        /**
+         * @see NetIdManager
+         */
+        public NetIdManager makeNetIdManager() {
+            return new NetIdManager();
+        }
+
+        /**
+         * @see NetworkUtils#queryUserAccess(int, int)
+         */
+        public boolean queryUserAccess(int uid, int netId) {
+            return NetworkUtils.queryUserAccess(uid, netId);
+        }
+
+        /**
+         * @see MultinetworkPolicyTracker
+         */
+        public MultinetworkPolicyTracker makeMultinetworkPolicyTracker(
+                @NonNull Context c, @NonNull Handler h, @NonNull Runnable r) {
+            return new MultinetworkPolicyTracker(c, h, r);
+        }
+
+        /**
+         * @see ServiceManager#checkService(String)
+         */
+        public boolean hasService(@NonNull String name) {
+            return ServiceManager.checkService(name) != null;
+        }
+
+        /**
+         * @see IpConnectivityMetrics.Logger
+         */
+        public IpConnectivityMetrics.Logger getMetricsLogger() {
+            return checkNotNull(LocalServices.getService(IpConnectivityMetrics.Logger.class),
+                    "no IpConnectivityMetrics service");
+        }
+
+        /**
+         * @see IpConnectivityMetrics
+         */
+        public IIpConnectivityMetrics getIpConnectivityMetrics() {
+            return IIpConnectivityMetrics.Stub.asInterface(
+                    ServiceManager.getService(IpConnectivityLog.SERVICE_NAME));
+        }
+    }
+
     public ConnectivityService(Context context, INetworkManagementService netManager,
             INetworkStatsService statsService, INetworkPolicyManager policyManager) {
-        this(context, netManager, statsService, policyManager,
-            getDnsResolver(), new IpConnectivityLog(), NetdService.getInstance());
+        this(context, netManager, statsService, policyManager, getDnsResolver(),
+                new IpConnectivityLog(), NetdService.getInstance(), new Dependencies());
     }
 
     @VisibleForTesting
     protected ConnectivityService(Context context, INetworkManagementService netManager,
             INetworkStatsService statsService, INetworkPolicyManager policyManager,
-            IDnsResolver dnsresolver, IpConnectivityLog logger, INetd netd) {
+            IDnsResolver dnsresolver, IpConnectivityLog logger, INetd netd, Dependencies deps) {
         if (DBG) log("ConnectivityService starting up");
 
-        mSystemProperties = getSystemProperties();
+        mDeps = checkNotNull(deps, "missing Dependencies");
+        mSystemProperties = mDeps.getSystemProperties();
+        mNetIdManager = mDeps.makeNetIdManager();
 
         mMetricsLog = logger;
         mDefaultRequest = createDefaultInternetRequestForTransport(-1, NetworkRequest.Type.REQUEST);
@@ -863,7 +951,7 @@
         mDefaultWifiRequest = createDefaultInternetRequestForTransport(
                 NetworkCapabilities.TRANSPORT_WIFI, NetworkRequest.Type.BACKGROUND_REQUEST);
 
-        mHandlerThread = new HandlerThread("ConnectivityServiceThread");
+        mHandlerThread = mDeps.makeHandlerThread();
         mHandlerThread.start();
         mHandler = new InternalHandler(mHandlerThread.getLooper());
         mTrackerHandler = new NetworkStateTrackerHandler(mHandlerThread.getLooper());
@@ -881,7 +969,7 @@
                 LocalServices.getService(NetworkPolicyManagerInternal.class),
                 "missing NetworkPolicyManagerInternal");
         mDnsResolver = checkNotNull(dnsresolver, "missing IDnsResolver");
-        mProxyTracker = makeProxyTracker();
+        mProxyTracker = mDeps.makeProxyTracker(mContext, mHandler);
 
         mNetd = netd;
         mKeyStore = KeyStore.getInstance();
@@ -949,7 +1037,7 @@
 
         // Do the same for Ethernet, since it's often not specified in the configs, although many
         // devices can use it via USB host adapters.
-        if (mNetConfigs[TYPE_ETHERNET] == null && hasService(Context.ETHERNET_SERVICE)) {
+        if (mNetConfigs[TYPE_ETHERNET] == null && mDeps.hasService(Context.ETHERNET_SERVICE)) {
             mLegacyTypeTracker.addSupportedType(TYPE_ETHERNET);
             mNetworksDefined++;
         }
@@ -969,7 +1057,8 @@
 
         mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
 
-        mTethering = makeTethering();
+        mTethering = deps.makeTethering(mContext, mNMS, mStatsService, mPolicyManager,
+                makeTetheringDependencies());
 
         mPermissionMonitor = new PermissionMonitor(mContext, mNetd);
 
@@ -1028,7 +1117,7 @@
                 LingerMonitor.DEFAULT_NOTIFICATION_RATE_LIMIT_MILLIS);
         mLingerMonitor = new LingerMonitor(mContext, mNotifier, dailyLimit, rateLimit);
 
-        mMultinetworkPolicyTracker = createMultinetworkPolicyTracker(
+        mMultinetworkPolicyTracker = mDeps.makeMultinetworkPolicyTracker(
                 mContext, mHandler, () -> rematchForAvoidBadWifiUpdate());
         mMultinetworkPolicyTracker.start();
 
@@ -1038,10 +1127,8 @@
         registerPrivateDnsSettingsCallbacks();
     }
 
-    @VisibleForTesting
-    protected Tethering makeTethering() {
-        // TODO: Move other elements into @Overridden getters.
-        final TetheringDependencies deps = new TetheringDependencies() {
+    private TetheringDependencies makeTetheringDependencies() {
+        return new TetheringDependencies() {
             @Override
             public boolean isTetheringSupported() {
                 return ConnectivityService.this.isTetheringSupported();
@@ -1051,14 +1138,6 @@
                 return mDefaultRequest;
             }
         };
-        return new Tethering(mContext, mNMS, mStatsService, mPolicyManager,
-                IoThread.get().getLooper(), new MockableSystemProperties(),
-                deps);
-    }
-
-    @VisibleForTesting
-    protected ProxyTracker makeProxyTracker() {
-        return new ProxyTracker(mContext, mHandler, EVENT_PROXY_HAS_CHANGED);
     }
 
     private static NetworkCapabilities createDefaultNetworkCapabilitiesForUid(int uid) {
@@ -1150,22 +1229,6 @@
         return mNextNetworkRequestId++;
     }
 
-    @VisibleForTesting
-    protected int reserveNetId() {
-        synchronized (mNetworkForNetId) {
-            for (int i = MIN_NET_ID; i <= MAX_NET_ID; i++) {
-                int netId = mNextNetId;
-                if (++mNextNetId > MAX_NET_ID) mNextNetId = MIN_NET_ID;
-                // Make sure NetID unused.  http://b/16815182
-                if (!mNetIdInUse.get(netId)) {
-                    mNetIdInUse.put(netId, true);
-                    return netId;
-                }
-            }
-        }
-        throw new IllegalStateException("No free netIds");
-    }
-
     private NetworkState getFilteredNetworkState(int networkType, int uid) {
         if (mLegacyTypeTracker.isTypeSupported(networkType)) {
             final NetworkAgentInfo nai = mLegacyTypeTracker.getNetworkForType(networkType);
@@ -1797,11 +1860,8 @@
         }
     };
 
-    @VisibleForTesting
-    protected void registerNetdEventCallback() {
-        final IIpConnectivityMetrics ipConnectivityMetrics =
-                IIpConnectivityMetrics.Stub.asInterface(
-                        ServiceManager.getService(IpConnectivityLog.SERVICE_NAME));
+    private void registerNetdEventCallback() {
+        final IIpConnectivityMetrics ipConnectivityMetrics = mDeps.getIpConnectivityMetrics();
         if (ipConnectivityMetrics == null) {
             Slog.wtf(TAG, "Missing IIpConnectivityMetrics");
             return;
@@ -2237,12 +2297,6 @@
     protected static final String DEFAULT_TCP_BUFFER_SIZES = "4096,87380,110208,4096,16384,110208";
     private static final String DEFAULT_TCP_RWND_KEY = "net.tcp.default_init_rwnd";
 
-    // Overridden for testing purposes to avoid writing to SystemProperties.
-    @VisibleForTesting
-    protected MockableSystemProperties getSystemProperties() {
-        return new MockableSystemProperties();
-    }
-
     private void updateTcpBufferSizes(String tcpBufferSizes) {
         String[] values = null;
         if (tcpBufferSizes != null) {
@@ -2632,8 +2686,9 @@
                     }
                     if (valid != nai.lastValidated) {
                         if (wasDefault) {
-                            metricsLogger().defaultNetworkMetrics().logDefaultNetworkValidity(
-                                    SystemClock.elapsedRealtime(), valid);
+                            mDeps.getMetricsLogger()
+                                    .defaultNetworkMetrics().logDefaultNetworkValidity(
+                                            SystemClock.elapsedRealtime(), valid);
                         }
                         final int oldScore = nai.getCurrentScore();
                         nai.lastValidated = valid;
@@ -2968,8 +3023,8 @@
                     final boolean wasDefault = isDefaultNetwork(nai);
                     synchronized (mNetworkForNetId) {
                         mNetworkForNetId.remove(nai.network.netId);
-                        mNetIdInUse.delete(nai.network.netId);
                     }
+                    mNetIdManager.releaseNetId(nai.network.netId);
                     // Just in case.
                     mLegacyTypeTracker.remove(nai, wasDefault);
                 }
@@ -3016,7 +3071,7 @@
             // if there is a fallback. Taken together, the two form a X -> 0, 0 -> Y sequence
             // whose timestamps tell how long it takes to recover a default network.
             long now = SystemClock.elapsedRealtime();
-            metricsLogger().defaultNetworkMetrics().logDefaultNetworkEvent(now, null, nai);
+            mDeps.getMetricsLogger().defaultNetworkMetrics().logDefaultNetworkEvent(now, null, nai);
         }
         notifyIfacesChangedForNetworkStats();
         // TODO - we shouldn't send CALLBACK_LOST to requests that can be satisfied
@@ -3070,9 +3125,7 @@
             destroyNativeNetwork(nai);
             mDnsManager.removeNetwork(nai.network);
         }
-        synchronized (mNetworkForNetId) {
-            mNetIdInUse.delete(nai.network.netId);
-        }
+        mNetIdManager.releaseNetId(nai.network.netId);
     }
 
     private boolean createNativeNetwork(@NonNull NetworkAgentInfo networkAgent) {
@@ -4156,7 +4209,7 @@
                 return null;
             }
             return getLinkPropertiesProxyInfo(activeNetwork);
-        } else if (queryUserAccess(Binder.getCallingUid(), network.netId)) {
+        } else if (mDeps.queryUserAccess(Binder.getCallingUid(), network.netId)) {
             // Don't call getLinkProperties() as it requires ACCESS_NETWORK_STATE permission, which
             // caller may not have.
             return getLinkPropertiesProxyInfo(network);
@@ -4165,10 +4218,6 @@
         return null;
     }
 
-    @VisibleForTesting
-    protected boolean queryUserAccess(int uid, int netId) {
-        return NetworkUtils.queryUserAccess(uid, netId);
-    }
 
     private ProxyInfo getLinkPropertiesProxyInfo(Network network) {
         final NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network);
@@ -4761,7 +4810,7 @@
         final long ident = Binder.clearCallingIdentity();
         try {
             // Concatenate the range of types onto the range of NetIDs.
-            int id = MAX_NET_ID + 1 + (networkType - ConnectivityManager.TYPE_NONE);
+            int id = NetIdManager.MAX_NET_ID + 1 + (networkType - ConnectivityManager.TYPE_NONE);
             mNotifier.setProvNotificationVisible(visible, id, action);
         } finally {
             Binder.restoreCallingIdentity(ident);
@@ -5372,10 +5421,9 @@
     @GuardedBy("mNetworkForNetId")
     private final SparseArray<NetworkAgentInfo> mNetworkForNetId = new SparseArray<>();
     // NOTE: Accessed on multiple threads, synchronized with mNetworkForNetId.
-    // An entry is first added to mNetIdInUse, prior to mNetworkForNetId, so
+    // An entry is first reserved with NetIdManager, prior to being added to mNetworkForNetId, so
     // there may not be a strict 1:1 correlation between the two.
-    @GuardedBy("mNetworkForNetId")
-    private final SparseBooleanArray mNetIdInUse = new SparseBooleanArray();
+    private final NetIdManager mNetIdManager;
 
     // NetworkAgentInfo keyed off its connecting messenger
     // TODO - eval if we can reduce the number of lists/hashmaps/sparsearrays
@@ -5477,9 +5525,9 @@
         // satisfies mDefaultRequest.
         final NetworkCapabilities nc = new NetworkCapabilities(networkCapabilities);
         final NetworkAgentInfo nai = new NetworkAgentInfo(messenger, new AsyncChannel(),
-                new Network(reserveNetId()), new NetworkInfo(networkInfo), lp, nc, currentScore,
-                mContext, mTrackerHandler, new NetworkMisc(networkMisc), this, mNetd, mDnsResolver,
-                mNMS, factorySerialNumber);
+                new Network(mNetIdManager.reserveNetId()), new NetworkInfo(networkInfo), lp, nc,
+                currentScore, mContext, mTrackerHandler, new NetworkMisc(networkMisc), this, mNetd,
+                mDnsResolver, mNMS, factorySerialNumber);
         // Make sure the network capabilities reflect what the agent info says.
         nai.setNetworkCapabilities(mixInCapabilities(nai, nc));
         final String extraInfo = networkInfo.getExtraInfo();
@@ -5488,7 +5536,7 @@
         if (DBG) log("registerNetworkAgent " + nai);
         final long token = Binder.clearCallingIdentity();
         try {
-            getNetworkStack().makeNetworkMonitor(
+            mDeps.getNetworkStack().makeNetworkMonitor(
                     nai.network, name, new NetworkMonitorCallbacks(nai));
         } finally {
             Binder.restoreCallingIdentity(token);
@@ -5500,11 +5548,6 @@
         return nai.network.netId;
     }
 
-    @VisibleForTesting
-    protected NetworkStackClient getNetworkStack() {
-        return NetworkStackClient.getInstance();
-    }
-
     private void handleRegisterNetworkAgent(NetworkAgentInfo nai, INetworkMonitor networkMonitor) {
         nai.onNetworkMonitorCreated(networkMonitor);
         if (VDBG) log("Got NetworkAgent Messenger");
@@ -6313,7 +6356,7 @@
             // Notify system services that this network is up.
             makeDefault(newNetwork);
             // Log 0 -> X and Y -> X default network transitions, where X is the new default.
-            metricsLogger().defaultNetworkMetrics().logDefaultNetworkEvent(
+            mDeps.getMetricsLogger().defaultNetworkMetrics().logDefaultNetworkEvent(
                     now, newNetwork, oldDefaultNetwork);
             // Have a new default network, release the transition wakelock in
             scheduleReleaseNetworkTransitionWakelock();
@@ -6990,27 +7033,6 @@
         return nwm.getWatchlistConfigHash();
     }
 
-    @VisibleForTesting
-    MultinetworkPolicyTracker createMultinetworkPolicyTracker(Context c, Handler h, Runnable r) {
-        return new MultinetworkPolicyTracker(c, h, r);
-    }
-
-    @VisibleForTesting
-    public WakeupMessage makeWakeupMessage(Context c, Handler h, String s, int cmd, Object obj) {
-        return new WakeupMessage(c, h, s, cmd, 0, 0, obj);
-    }
-
-    @VisibleForTesting
-    public boolean hasService(String name) {
-        return ServiceManager.checkService(name) != null;
-    }
-
-    @VisibleForTesting
-    protected IpConnectivityMetrics.Logger metricsLogger() {
-        return checkNotNull(LocalServices.getService(IpConnectivityMetrics.Logger.class),
-                "no IpConnectivityMetrics service");
-    }
-
     private void logNetworkEvent(NetworkAgentInfo nai, int evtype) {
         int[] transports = nai.networkCapabilities.getTransportTypes();
         mMetricsLog.log(nai.network.netId, transports, new NetworkEvent(evtype));
diff --git a/services/core/java/com/android/server/DynamicSystemService.java b/services/core/java/com/android/server/DynamicSystemService.java
index 173d5b0..e531412 100644
--- a/services/core/java/com/android/server/DynamicSystemService.java
+++ b/services/core/java/com/android/server/DynamicSystemService.java
@@ -181,18 +181,16 @@
 
     @Override
     public boolean remove() throws RemoteException {
-        return getGsiService().removeGsiInstall();
+        return getGsiService().removeGsi();
     }
 
     @Override
-    public boolean setEnable(boolean enable) throws RemoteException {
+    public boolean setEnable(boolean enable, boolean oneShot) throws RemoteException {
         IGsiService gsiService = getGsiService();
         if (enable) {
-            final int status = gsiService.getGsiBootStatus();
-            final boolean singleBoot = (status == IGsiService.BOOT_STATUS_SINGLE_BOOT);
-            return gsiService.setGsiBootable(singleBoot) == 0;
+            return gsiService.enableGsi(oneShot) == 0;
         } else {
-            return gsiService.disableGsiInstall();
+            return gsiService.disableGsi();
         }
     }
 
@@ -200,9 +198,4 @@
     public boolean write(byte[] buf) throws RemoteException {
         return getGsiService().commitGsiChunkFromMemory(buf);
     }
-
-    @Override
-    public boolean commit() throws RemoteException {
-        return getGsiService().setGsiBootable(true) == 0;
-    }
 }
diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java
index fe22dcd..a629b3f 100644
--- a/services/core/java/com/android/server/IpSecService.java
+++ b/services/core/java/com/android/server/IpSecService.java
@@ -750,10 +750,10 @@
         }
     }
 
-    // These values have been reserved in ConnectivityService
+    // These values have been reserved in NetIdManager
     @VisibleForTesting static final int TUN_INTF_NETID_START = 0xFC00;
 
-    @VisibleForTesting static final int TUN_INTF_NETID_RANGE = 0x0400;
+    public static final int TUN_INTF_NETID_RANGE = 0x0400;
 
     private final SparseBooleanArray mTunnelNetIds = new SparseBooleanArray();
     private int mNextTunnelNetIdIndex = 0;
diff --git a/services/core/java/com/android/server/NetIdManager.java b/services/core/java/com/android/server/NetIdManager.java
new file mode 100644
index 0000000..11533be
--- /dev/null
+++ b/services/core/java/com/android/server/NetIdManager.java
@@ -0,0 +1,76 @@
+/*
+ * 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;
+
+import android.annotation.NonNull;
+import android.util.SparseBooleanArray;
+
+import com.android.internal.annotations.GuardedBy;
+
+/**
+ * Class used to reserve and release net IDs.
+ *
+ * <p>Instances of this class are thread-safe.
+ */
+public class NetIdManager {
+    // Sequence number for Networks; keep in sync with system/netd/NetworkController.cpp
+    public static final int MIN_NET_ID = 100; // some reserved marks
+    // Top IDs reserved by IpSecService
+    public static final int MAX_NET_ID = 65535 - IpSecService.TUN_INTF_NETID_RANGE;
+
+    @GuardedBy("mNetIdInUse")
+    private final SparseBooleanArray mNetIdInUse = new SparseBooleanArray();
+
+    @GuardedBy("mNetIdInUse")
+    private int mLastNetId = MIN_NET_ID - 1;
+
+    /**
+     * Get the first netId that follows the provided lastId and is available.
+     */
+    private static int getNextAvailableNetIdLocked(
+            int lastId, @NonNull SparseBooleanArray netIdInUse) {
+        int netId = lastId;
+        for (int i = MIN_NET_ID; i <= MAX_NET_ID; i++) {
+            netId = netId < MAX_NET_ID ? netId + 1 : MIN_NET_ID;
+            if (!netIdInUse.get(netId)) {
+                return netId;
+            }
+        }
+        throw new IllegalStateException("No free netIds");
+    }
+
+    /**
+     * Reserve a new ID for a network.
+     */
+    public int reserveNetId() {
+        synchronized (mNetIdInUse) {
+            mLastNetId = getNextAvailableNetIdLocked(mLastNetId, mNetIdInUse);
+            // Make sure NetID unused.  http://b/16815182
+            mNetIdInUse.put(mLastNetId, true);
+            return mLastNetId;
+        }
+    }
+
+    /**
+     * Clear a previously reserved ID for a network.
+     */
+    public void releaseNetId(int id) {
+        synchronized (mNetIdInUse) {
+            mNetIdInUse.delete(id);
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/PinnerService.java b/services/core/java/com/android/server/PinnerService.java
index b0efd43..49ef164 100644
--- a/services/core/java/com/android/server/PinnerService.java
+++ b/services/core/java/com/android/server/PinnerService.java
@@ -25,6 +25,7 @@
 import android.app.ActivityManagerInternal;
 import android.app.IActivityManager;
 import android.app.IUidObserver;
+import android.app.SearchManager;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -94,11 +95,23 @@
 
     private static final int KEY_CAMERA = 0;
     private static final int KEY_HOME = 1;
+    private static final int KEY_ASSISTANT = 2;
+
+    // Pin the camera application.
+    private static boolean PROP_PIN_CAMERA = SystemProperties.getBoolean(
+            "pinner.pin_camera", true);
+    // Pin using pinlist.meta when pinning apps.
+    private static boolean PROP_PIN_PINLIST = SystemProperties.getBoolean(
+            "pinner.use_pinlist", true);
+    // Pin the whole odex/vdex/etc file when pinning apps.
+    private static boolean PROP_PIN_ODEX = SystemProperties.getBoolean(
+            "pinner.whole_odex", true);
 
     private static final int MAX_CAMERA_PIN_SIZE = 80 * (1 << 20); // 80MB max for camera app.
     private static final int MAX_HOME_PIN_SIZE = 6 * (1 << 20); // 6MB max for home app.
+    private static final int MAX_ASSISTANT_PIN_SIZE = 60 * (1 << 20); // 60MB max for assistant app.
 
-    @IntDef({KEY_CAMERA, KEY_HOME})
+    @IntDef({KEY_CAMERA, KEY_HOME, KEY_ASSISTANT})
     @Retention(RetentionPolicy.SOURCE)
     public @interface AppKey {}
 
@@ -107,6 +120,7 @@
     private final ActivityManagerInternal mAmInternal;
     private final IActivityManager mAm;
     private final UserManager mUserManager;
+    private SearchManager mSearchManager;
 
     /** The list of the statically pinned files. */
     @GuardedBy("this")
@@ -157,12 +171,21 @@
                 com.android.internal.R.bool.config_pinnerCameraApp);
         boolean shouldPinHome = context.getResources().getBoolean(
                 com.android.internal.R.bool.config_pinnerHomeApp);
+        boolean shouldPinAssistant = context.getResources().getBoolean(
+                com.android.internal.R.bool.config_pinnerAssistantApp);
         if (shouldPinCamera) {
-            mPinKeys.add(KEY_CAMERA);
+            if (PROP_PIN_CAMERA) {
+                mPinKeys.add(KEY_CAMERA);
+            } else if (DEBUG) {
+                Slog.i(TAG, "Pinner - skip pinning camera app");
+            }
         }
         if (shouldPinHome) {
             mPinKeys.add(KEY_HOME);
         }
+        if (shouldPinAssistant) {
+            mPinKeys.add(KEY_ASSISTANT);
+        }
         mPinnerHandler = new PinnerHandler(BackgroundThread.get().getLooper());
 
         mAtmInternal = LocalServices.getService(ActivityTaskManagerInternal.class);
@@ -193,6 +216,15 @@
         sendPinAppsMessage(UserHandle.USER_SYSTEM);
     }
 
+    @Override
+    public void onBootPhase(int phase) {
+        // SearchManagerService is started after PinnerService, wait for PHASE_SYSTEM_SERVICES_READY
+        if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
+            mSearchManager = (SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE);
+            sendPinAppsMessage(UserHandle.USER_SYSTEM);
+        }
+    }
+
     /**
      * Repin apps on user switch.
      * <p>
@@ -394,6 +426,14 @@
         return getApplicationInfoForIntent(intent, userHandle, false);
     }
 
+    private ApplicationInfo getAssistantInfo(int userHandle) {
+        if (mSearchManager != null) {
+            Intent intent = mSearchManager.getAssistIntent(false);
+            return getApplicationInfoForIntent(intent, userHandle, true);
+        }
+        return null;
+    }
+
     private ApplicationInfo getApplicationInfoForIntent(Intent intent, int userHandle,
             boolean defaultToSystemApp) {
         if (intent == null) {
@@ -506,6 +546,8 @@
                 return getCameraInfo(userHandle);
             case KEY_HOME:
                 return getHomeInfo(userHandle);
+            case KEY_ASSISTANT:
+                return getAssistantInfo(userHandle);
             default:
                 return null;
         }
@@ -520,6 +562,8 @@
                 return "Camera";
             case KEY_HOME:
                 return "Home";
+            case KEY_ASSISTANT:
+                return "Assistant";
             default:
                 return null;
         }
@@ -534,6 +578,8 @@
                 return MAX_CAMERA_PIN_SIZE;
             case KEY_HOME:
                 return MAX_HOME_PIN_SIZE;
+            case KEY_ASSISTANT:
+                return MAX_ASSISTANT_PIN_SIZE;
             default:
                 return 0;
         }
@@ -589,10 +635,16 @@
             pf = pinFile(file, pinSizeLimit, /*attemptPinIntrospection=*/false);
             if (pf != null) {
                 synchronized (this) {
-                    pinnedApp.mFiles.add(pf);
+                    if (PROP_PIN_ODEX) {
+                      pinnedApp.mFiles.add(pf);
+                    }
                 }
                 if (DEBUG) {
-                    Slog.i(TAG, "Pinned " + pf.fileName);
+                    if (PROP_PIN_ODEX) {
+                        Slog.i(TAG, "Pinned " + pf.fileName);
+                    } else {
+                        Slog.i(TAG, "Pinned [skip] " + pf.fileName);
+                    }
                 }
             }
         }
@@ -686,6 +738,13 @@
      * @return Open input stream or null on any error
      */
     private static InputStream maybeOpenPinMetaInZip(ZipFile zipFile, String fileName) {
+        if (!PROP_PIN_PINLIST) {
+            if (DEBUG) {
+                Slog.i(TAG, "Pin - skip pinlist.meta in " + fileName);
+            }
+            return null;
+        }
+
         ZipEntry pinMetaEntry = zipFile.getEntry(PIN_META_FILENAME);
         InputStream pinMetaStream = null;
         if (pinMetaEntry != null) {
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index deff7ef..4fab7c1 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -1557,10 +1557,11 @@
     }
 
     private void start() {
-        connect();
+        connectStoraged();
+        connectVold();
     }
 
-    private void connect() {
+    private void connectStoraged() {
         IBinder binder = ServiceManager.getService("storaged");
         if (binder != null) {
             try {
@@ -1569,7 +1570,7 @@
                     public void binderDied() {
                         Slog.w(TAG, "storaged died; reconnecting");
                         mStoraged = null;
-                        connect();
+                        connectStoraged();
                     }
                 }, 0);
             } catch (RemoteException e) {
@@ -1583,7 +1584,17 @@
             Slog.w(TAG, "storaged not found; trying again");
         }
 
-        binder = ServiceManager.getService("vold");
+        if (mStoraged == null) {
+            BackgroundThread.getHandler().postDelayed(() -> {
+                connectStoraged();
+            }, DateUtils.SECOND_IN_MILLIS);
+        } else {
+            onDaemonConnected();
+        }
+    }
+
+    private void connectVold() {
+        IBinder binder = ServiceManager.getService("vold");
         if (binder != null) {
             try {
                 binder.linkToDeath(new DeathRecipient() {
@@ -1591,7 +1602,7 @@
                     public void binderDied() {
                         Slog.w(TAG, "vold died; reconnecting");
                         mVold = null;
-                        connect();
+                        connectVold();
                     }
                 }, 0);
             } catch (RemoteException e) {
@@ -1611,9 +1622,9 @@
             Slog.w(TAG, "vold not found; trying again");
         }
 
-        if (mStoraged == null || mVold == null) {
+        if (mVold == null) {
             BackgroundThread.getHandler().postDelayed(() -> {
-                connect();
+                connectVold();
             }, DateUtils.SECOND_IN_MILLIS);
         } else {
             onDaemonConnected();
@@ -3208,28 +3219,28 @@
             // should be kept in sync with getFreeBytes().
             final File path = storage.findPathForUuid(volumeUuid);
 
-            final long usable = path.getUsableSpace();
-            final long lowReserved = storage.getStorageLowBytes(path);
-            final long fullReserved = storage.getStorageFullBytes(path);
+            long usable = 0;
+            long lowReserved = 0;
+            long fullReserved = 0;
+            long cacheClearable = 0;
 
-            if (stats.isQuotaSupported(volumeUuid)) {
+            if ((flags & StorageManager.FLAG_ALLOCATE_CACHE_ONLY) == 0) {
+                usable = path.getUsableSpace();
+                lowReserved = storage.getStorageLowBytes(path);
+                fullReserved = storage.getStorageFullBytes(path);
+            }
+
+            if ((flags & StorageManager.FLAG_ALLOCATE_NON_CACHE_ONLY) == 0
+                    && stats.isQuotaSupported(volumeUuid)) {
                 final long cacheTotal = stats.getCacheBytes(volumeUuid);
                 final long cacheReserved = storage.getStorageCacheBytes(path, flags);
-                final long cacheClearable = Math.max(0, cacheTotal - cacheReserved);
+                cacheClearable = Math.max(0, cacheTotal - cacheReserved);
+            }
 
-                if ((flags & StorageManager.FLAG_ALLOCATE_AGGRESSIVE) != 0) {
-                    return Math.max(0, (usable + cacheClearable) - fullReserved);
-                } else {
-                    return Math.max(0, (usable + cacheClearable) - lowReserved);
-                }
+            if ((flags & StorageManager.FLAG_ALLOCATE_AGGRESSIVE) != 0) {
+                return Math.max(0, (usable + cacheClearable) - fullReserved);
             } else {
-                // When we don't have fast quota information, we ignore cached
-                // data and only consider unused bytes.
-                if ((flags & StorageManager.FLAG_ALLOCATE_AGGRESSIVE) != 0) {
-                    return Math.max(0, usable - fullReserved);
-                } else {
-                    return Math.max(0, usable - lowReserved);
-                }
+                return Math.max(0, (usable + cacheClearable) - lowReserved);
             }
         } catch (IOException e) {
             throw new ParcelableException(e);
@@ -3242,10 +3253,17 @@
     public void allocateBytes(String volumeUuid, long bytes, int flags, String callingPackage) {
         flags = adjustAllocateFlags(flags, Binder.getCallingUid(), callingPackage);
 
-        final long allocatableBytes = getAllocatableBytes(volumeUuid, flags, callingPackage);
+        final long allocatableBytes = getAllocatableBytes(volumeUuid,
+                flags | StorageManager.FLAG_ALLOCATE_NON_CACHE_ONLY, callingPackage);
         if (bytes > allocatableBytes) {
-            throw new ParcelableException(new IOException("Failed to allocate " + bytes
-                    + " because only " + allocatableBytes + " allocatable"));
+            // If we don't have room without taking cache into account, check to see if we'd have
+            // room if we included freeable cache space.
+            final long cacheClearable = getAllocatableBytes(volumeUuid,
+                    flags | StorageManager.FLAG_ALLOCATE_CACHE_ONLY, callingPackage);
+            if (bytes > allocatableBytes + cacheClearable) {
+                throw new ParcelableException(new IOException("Failed to allocate " + bytes
+                    + " because only " + (allocatableBytes + cacheClearable) + " allocatable"));
+            }
         }
 
         final StorageManager storage = mContext.getSystemService(StorageManager.class);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 4d43e4a..7b20e55 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -2373,11 +2373,6 @@
         }
     }
 
-    @VisibleForTesting
-    public ActivityManagerService(Injector injector) {
-        this(injector, null /* handlerThread */);
-    }
-
     /**
      * Provides the basic functionality for activity task related tests when a handler thread is
      * given to initialize the dependency members.
@@ -2424,7 +2419,7 @@
     // handlers to other threads.  So take care to be explicit about the looper.
     public ActivityManagerService(Context systemContext, ActivityTaskManagerService atm) {
         LockGuard.installLock(this, LockGuard.INDEX_ACTIVITY);
-        mInjector = new Injector();
+        mInjector = new Injector(systemContext);
         mContext = systemContext;
 
         mFactoryTest = FactoryTest.getMode();
@@ -5218,6 +5213,10 @@
             }
         }
 
+        // Let the ART runtime in zygote and system_server know that the boot completed.
+        ZYGOTE_PROCESS.bootCompleted();
+        VMRuntime.bootCompleted();
+
         IntentFilter pkgFilter = new IntentFilter();
         pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
         pkgFilter.addDataScheme("package");
@@ -8522,32 +8521,6 @@
         }
     }
 
-    void setRunningRemoteAnimation(int pid, boolean runningRemoteAnimation) {
-        if (pid == Process.myPid()) {
-            Slog.wtf(TAG, "system can't run remote animation");
-            return;
-        }
-        synchronized (ActivityManagerService.this) {
-            final ProcessRecord pr;
-            synchronized (mPidsSelfLocked) {
-                pr = mPidsSelfLocked.get(pid);
-                if (pr == null) {
-                    Slog.w(TAG, "setRunningRemoteAnimation called on unknown pid: " + pid);
-                    return;
-                }
-            }
-            if (pr.runningRemoteAnimation == runningRemoteAnimation) {
-                return;
-            }
-            pr.runningRemoteAnimation = runningRemoteAnimation;
-            if (DEBUG_OOM_ADJ) {
-                Slog.i(TAG, "Setting runningRemoteAnimation=" + pr.runningRemoteAnimation
-                        + " for pid=" + pid);
-            }
-            updateOomAdjLocked(pr, true, OomAdjuster.OOM_ADJ_REASON_UI_VISIBILITY);
-        }
-    }
-
     public final void enterSafeMode() {
         synchronized(this) {
             // It only makes sense to do this before the system is ready
@@ -18102,11 +18075,6 @@
         }
 
         @Override
-        public void setRunningRemoteAnimation(int pid, boolean runningRemoteAnimation) {
-            ActivityManagerService.this.setRunningRemoteAnimation(pid, runningRemoteAnimation);
-        }
-
-        @Override
         public List<ProcessMemoryState> getMemoryStateForProcesses() {
             List<ProcessMemoryState> processMemoryStates = new ArrayList<>();
             synchronized (mPidsSelfLocked) {
@@ -18930,9 +18898,14 @@
     @VisibleForTesting
     public static class Injector {
         private NetworkManagementInternal mNmi;
+        private Context mContext;
+
+        public Injector(Context context) {
+            mContext = context;
+        }
 
         public Context getContext() {
-            return null;
+            return mContext;
         }
 
         public AppOpsService getAppOpsService(File file, Handler handler) {
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index 563b2f3..ea30842 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -20,6 +20,7 @@
 
 import static com.android.server.Watchdog.NATIVE_STACKS_OF_INTEREST;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ANR;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_OOM_ADJ;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.am.ActivityManagerService.MY_PID;
@@ -1348,6 +1349,25 @@
         }
     }
 
+    @Override
+    public void setRunningRemoteAnimation(boolean runningRemoteAnimation) {
+        if (pid == Process.myPid()) {
+            Slog.wtf(TAG, "system can't run remote animation");
+            return;
+        }
+        synchronized (mService) {
+            if (this.runningRemoteAnimation == runningRemoteAnimation) {
+                return;
+            }
+            this.runningRemoteAnimation = runningRemoteAnimation;
+            if (DEBUG_OOM_ADJ) {
+                Slog.i(TAG, "Setting runningRemoteAnimation=" + runningRemoteAnimation
+                        + " for pid=" + pid);
+            }
+            mService.updateOomAdjLocked(this, true, OomAdjuster.OOM_ADJ_REASON_UI_VISIBILITY);
+        }
+    }
+
     public long getInputDispatchingTimeout() {
         return mWindowProcessController.getInputDispatchingTimeout();
     }
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 3007016..6d6a148 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -18,9 +18,11 @@
 
 import static android.app.AppOpsManager.MAX_PRIORITY_UID_STATE;
 import static android.app.AppOpsManager.MIN_PRIORITY_UID_STATE;
+import static android.app.AppOpsManager.OP_CAMERA;
 import static android.app.AppOpsManager.OP_FLAGS_ALL;
 import static android.app.AppOpsManager.OP_NONE;
 import static android.app.AppOpsManager.OP_PLAY_AUDIO;
+import static android.app.AppOpsManager.OP_RECORD_AUDIO;
 import static android.app.AppOpsManager.UID_STATE_BACKGROUND;
 import static android.app.AppOpsManager.UID_STATE_CACHED;
 import static android.app.AppOpsManager.UID_STATE_FOREGROUND;
@@ -173,6 +175,12 @@
         UID_STATE_CACHED,               // ActivityManager.PROCESS_STATE_NONEXISTENT
     };
 
+    private static final int[] OPS_RESTRICTED_ON_SUSPEND = {
+            OP_PLAY_AUDIO,
+            OP_RECORD_AUDIO,
+            OP_CAMERA,
+    };
+
     Context mContext;
     final AtomicFile mFile;
     final Handler mHandler;
@@ -798,7 +806,9 @@
                     final String changedPkg = changedPkgs[i];
                     // We trust packagemanager to insert matching uid and packageNames in the
                     // extras
-                    notifyOpChanged(callbacks, OP_PLAY_AUDIO, changedUid, changedPkg);
+                    for (int code : OPS_RESTRICTED_ON_SUSPEND) {
+                        notifyOpChanged(callbacks, code, changedUid, changedPkg);
+                    }
                 }
             }
         }, packageSuspendFilter);
@@ -1759,6 +1769,9 @@
             return AppOpsManager.opToDefaultMode(code);
         }
 
+        if (isOpRestrictedDueToSuspend(code, packageName, uid)) {
+            return AppOpsManager.MODE_IGNORED;
+        }
         synchronized (this) {
             if (isOpRestrictedLocked(uid, code, packageName, isPrivileged)) {
                 return AppOpsManager.MODE_IGNORED;
@@ -1792,20 +1805,6 @@
     }
 
     private int checkAudioOperationImpl(int code, int usage, int uid, String packageName) {
-        boolean suspended;
-        try {
-            suspended = isPackageSuspendedForUser(packageName, uid);
-        } catch (IllegalArgumentException ex) {
-            // Package not found.
-            suspended = false;
-        }
-
-        if (suspended) {
-            Slog.i(TAG, "Audio disabled for suspended package=" + packageName
-                    + " for uid=" + uid);
-            return AppOpsManager.MODE_IGNORED;
-        }
-
         synchronized (this) {
             final int mode = checkRestrictionLocked(code, usage, uid, packageName);
             if (mode != AppOpsManager.MODE_ALLOWED) {
@@ -1815,18 +1814,6 @@
         return checkOperation(code, uid, packageName);
     }
 
-    private boolean isPackageSuspendedForUser(String pkg, int uid) {
-        final long identity = Binder.clearCallingIdentity();
-        try {
-            return AppGlobals.getPackageManager().isPackageSuspendedForUser(
-                    pkg, UserHandle.getUserId(uid));
-        } catch (RemoteException re) {
-            throw new SecurityException("Could not talk to package manager service");
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-        }
-    }
-
     private int checkRestrictionLocked(int code, int usage, int uid, String packageName) {
         final SparseArray<Restriction> usageRestrictions = mAudioRestrictions.get(code);
         if (usageRestrictions != null) {
@@ -2654,6 +2641,12 @@
         return op;
     }
 
+    private boolean isOpRestrictedDueToSuspend(int code, String packageName, int uid) {
+        final PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
+        return ArrayUtils.contains(OPS_RESTRICTED_ON_SUSPEND, code)
+                && pmi.isPackageSuspended(packageName, UserHandle.getUserId(uid));
+    }
+
     private boolean isOpRestrictedLocked(int uid, int code, String packageName,
             boolean isPrivileged) {
         int userHandle = UserHandle.getUserId(uid);
diff --git a/services/core/java/com/android/server/audio/FocusRequester.java b/services/core/java/com/android/server/audio/FocusRequester.java
index db55138..65472c9 100644
--- a/services/core/java/com/android/server/audio/FocusRequester.java
+++ b/services/core/java/com/android/server/audio/FocusRequester.java
@@ -364,28 +364,8 @@
 
                 // check enforcement by the framework
                 boolean handled = false;
-                if (focusLoss == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK
-                        && MediaFocusControl.ENFORCE_DUCKING
-                        && frWinner != null) {
-                    // candidate for enforcement by the framework
-                    if (frWinner.mCallingUid != this.mCallingUid) {
-                        if (!forceDuck && ((mGrantFlags
-                                & AudioManager.AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS) != 0)) {
-                            // the focus loser declared it would pause instead of duck, let it
-                            // handle it (the framework doesn't pause for apps)
-                            handled = false;
-                            Log.v(TAG, "not ducking uid " + this.mCallingUid + " - flags");
-                        } else if (!forceDuck && (MediaFocusControl.ENFORCE_DUCKING_FOR_NEW &&
-                                this.getSdkTarget() <= MediaFocusControl.DUCKING_IN_APP_SDK_LEVEL))
-                        {
-                            // legacy behavior, apps used to be notified when they should be ducking
-                            handled = false;
-                            Log.v(TAG, "not ducking uid " + this.mCallingUid + " - old SDK");
-                        } else {
-                            handled = mFocusController.duckPlayers(frWinner, this, forceDuck);
-                        }
-                    } // else: the focus change is within the same app, so let the dispatching
-                      //       happen as if the framework was not involved.
+                if (frWinner != null) {
+                    handled = frameworkHandleFocusLoss(focusLoss, frWinner, forceDuck);
                 }
 
                 if (handled) {
@@ -415,6 +395,47 @@
         }
     }
 
+    /**
+     * Let the framework handle the focus loss if possible
+     * @param focusLoss
+     * @param frWinner
+     * @param forceDuck
+     * @return true if the framework handled the focus loss
+     */
+    @GuardedBy("MediaFocusControl.mAudioFocusLock")
+    private boolean frameworkHandleFocusLoss(int focusLoss, @NonNull final FocusRequester frWinner,
+                                             boolean forceDuck) {
+        if (frWinner.mCallingUid != this.mCallingUid) {
+            // the focus change is within the same app, so let the dispatching
+            // happen as if the framework was not involved.
+            return false;
+        }
+
+        if (focusLoss == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK) {
+            if (!MediaFocusControl.ENFORCE_DUCKING) {
+                return false;
+            }
+
+            // candidate for enforcement by the framework
+            if (!forceDuck && ((mGrantFlags
+                    & AudioManager.AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS) != 0)) {
+                // the focus loser declared it would pause instead of duck, let it
+                // handle it (the framework doesn't pause for apps)
+                Log.v(TAG, "not ducking uid " + this.mCallingUid + " - flags");
+                return false;
+            }
+            if (!forceDuck && (MediaFocusControl.ENFORCE_DUCKING_FOR_NEW
+                    && this.getSdkTarget() <= MediaFocusControl.DUCKING_IN_APP_SDK_LEVEL)) {
+                // legacy behavior, apps used to be notified when they should be ducking
+                Log.v(TAG, "not ducking uid " + this.mCallingUid + " - old SDK");
+                return false;
+            }
+
+            return mFocusController.duckPlayers(frWinner, this, forceDuck);
+        }
+        return false;
+    }
+
     int dispatchFocusChange(int focusChange) {
         if (mFocusDispatcher == null) {
             if (MediaFocusControl.DEBUG) { Log.e(TAG, "dispatchFocusChange: no focus dispatcher"); }
diff --git a/services/core/java/com/android/server/audio/MediaFocusControl.java b/services/core/java/com/android/server/audio/MediaFocusControl.java
index 5c93071..c845981 100644
--- a/services/core/java/com/android/server/audio/MediaFocusControl.java
+++ b/services/core/java/com/android/server/audio/MediaFocusControl.java
@@ -105,12 +105,13 @@
     //=================================================================
     // PlayerFocusEnforcer implementation
     @Override
-    public boolean duckPlayers(FocusRequester winner, FocusRequester loser, boolean forceDuck) {
+    public boolean duckPlayers(@NonNull FocusRequester winner, @NonNull FocusRequester loser,
+                               boolean forceDuck) {
         return mFocusEnforcer.duckPlayers(winner, loser, forceDuck);
     }
 
     @Override
-    public void unduckPlayers(FocusRequester winner) {
+    public void unduckPlayers(@NonNull FocusRequester winner) {
         mFocusEnforcer.unduckPlayers(winner);
     }
 
@@ -742,7 +743,20 @@
         }
     }
 
-    /** @see AudioManager#requestAudioFocus(AudioManager.OnAudioFocusChangeListener, int, int, int) */
+    /** @see AudioManager#requestAudioFocus(AudioManager.OnAudioFocusChangeListener, int, int, int)
+     * @param aa
+     * @param focusChangeHint
+     * @param cb
+     * @param fd
+     * @param clientId
+     * @param callingPackageName
+     * @param flags
+     * @param sdk
+     * @param forceDuck only true if
+     *     {@link android.media.AudioFocusRequest.Builder#setFocusGain(int)} was set to true for
+     *                  accessibility.
+     * @return
+     */
     protected int requestAudioFocus(@NonNull AudioAttributes aa, int focusChangeHint, IBinder cb,
             IAudioFocusDispatcher fd, @NonNull String clientId, @NonNull String callingPackageName,
             int flags, int sdk, boolean forceDuck) {
diff --git a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
index 3a25d98..f8ba55b 100644
--- a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
+++ b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
@@ -425,7 +425,8 @@
     private final DuckingManager mDuckingManager = new DuckingManager();
 
     @Override
-    public boolean duckPlayers(FocusRequester winner, FocusRequester loser, boolean forceDuck) {
+    public boolean duckPlayers(@NonNull FocusRequester winner, @NonNull FocusRequester loser,
+                               boolean forceDuck) {
         if (DEBUG) {
             Log.v(TAG, String.format("duckPlayers: uids winner=%d loser=%d",
                     winner.getClientUid(), loser.getClientUid()));
@@ -473,7 +474,7 @@
     }
 
     @Override
-    public void unduckPlayers(FocusRequester winner) {
+    public void unduckPlayers(@NonNull FocusRequester winner) {
         if (DEBUG) { Log.v(TAG, "unduckPlayers: uids winner=" + winner.getClientUid()); }
         synchronized (mPlayerLock) {
             mDuckingManager.unduckUid(winner.getClientUid(), mPlayers);
diff --git a/services/core/java/com/android/server/audio/PlayerFocusEnforcer.java b/services/core/java/com/android/server/audio/PlayerFocusEnforcer.java
index 3c834da..89e7b782 100644
--- a/services/core/java/com/android/server/audio/PlayerFocusEnforcer.java
+++ b/services/core/java/com/android/server/audio/PlayerFocusEnforcer.java
@@ -16,6 +16,8 @@
 
 package com.android.server.audio;
 
+import android.annotation.NonNull;
+
 public interface PlayerFocusEnforcer {
 
     /**
@@ -25,11 +27,24 @@
      * @param loser
      * @return
      */
-    public boolean duckPlayers(FocusRequester winner, FocusRequester loser, boolean forceDuck);
+    boolean duckPlayers(@NonNull FocusRequester winner, @NonNull FocusRequester loser,
+                               boolean forceDuck);
 
-    public void unduckPlayers(FocusRequester winner);
+    /**
+     * Unduck the players that had been ducked with
+     * {@link #duckPlayers(FocusRequester, FocusRequester, boolean)}
+     * @param winner
+     */
+    void unduckPlayers(@NonNull FocusRequester winner);
 
-    public void mutePlayersForCall(int[] usagesToMute);
+    /**
+     * Mute players at the beginning of a call
+     * @param usagesToMute array of {@link android.media.AudioAttributes} usages to mute
+     */
+    void mutePlayersForCall(int[] usagesToMute);
 
-    public void unmutePlayersForCall();
+    /**
+     * Unmute players at the end of a call
+     */
+    void unmutePlayersForCall();
 }
\ No newline at end of file
diff --git a/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java b/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java
index 764fca9..7ab3bdd 100644
--- a/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java
+++ b/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java
@@ -31,6 +31,7 @@
 import android.util.MutableInt;
 import android.util.Slog;
 
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
@@ -186,6 +187,12 @@
 
     @Override
     public void startProgramListUpdates(ProgramList.Filter filter) throws RemoteException {
+        // If the AIDL client provides a null filter, it wants all updates, so use the most broad
+        // filter.
+        if (filter == null) {
+            filter = new ProgramList.Filter(new HashSet<Integer>(),
+                    new HashSet<android.hardware.radio.ProgramSelector.Identifier>(), true, false);
+        }
         synchronized (mLock) {
             checkNotClosedLocked();
             mProgramInfoCache = new ProgramInfoCache(filter);
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index 8d1a802..96b7cb3 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -580,10 +580,12 @@
         }
 
         if (newExpiry > 0) {
-            mLingerMessage = mConnService.makeWakeupMessage(
+            mLingerMessage = new WakeupMessage(
                     mContext, mHandler,
-                    "NETWORK_LINGER_COMPLETE." + network.netId,
-                    EVENT_NETWORK_LINGER_COMPLETE, this);
+                    "NETWORK_LINGER_COMPLETE." + network.netId /* cmdName */,
+                    EVENT_NETWORK_LINGER_COMPLETE /* cmd */,
+                    0 /* arg1 (unused) */, 0 /* arg2 (unused) */,
+                    this /* obj (NetworkAgentInfo) */);
             mLingerMessage.schedule(newExpiry);
         }
 
diff --git a/services/core/java/com/android/server/display/DisplayModeDirector.java b/services/core/java/com/android/server/display/DisplayModeDirector.java
index c45a314..7648636 100644
--- a/services/core/java/com/android/server/display/DisplayModeDirector.java
+++ b/services/core/java/com/android/server/display/DisplayModeDirector.java
@@ -680,6 +680,7 @@
         @Override
         public void onDisplayChanged(int displayId) {
             updateDisplayModes(displayId);
+            mBrightnessObserver.onDisplayChanged(displayId);
         }
 
         private void updateDisplayModes(int displayId) {
@@ -734,8 +735,6 @@
         private AmbientFilter mAmbientFilter;
 
         private final Context mContext;
-        private ScreenStateReceiver mScreenStateReceiver;
-
         // Enable light sensor only when screen is on, peak refresh rate enabled and low power mode
         // off. After initialization, these states will be updated from the same handler thread.
         private boolean mScreenOn = false;
@@ -793,11 +792,7 @@
                     mSensorManager = sensorManager;
                     mLightSensor = lightSensor;
 
-                    // Intent.ACTION_SCREEN_ON is not sticky. Check current screen status.
-                    if (mContext.getSystemService(PowerManager.class).isInteractive()) {
-                        onScreenOn(true);
-                    }
-                    mScreenStateReceiver = new ScreenStateReceiver(mContext);
+                    onScreenOn(isDefaultDisplayOn());
                 }
             }
 
@@ -822,6 +817,12 @@
             }
         }
 
+        public void onDisplayChanged(int displayId) {
+            if (displayId == Display.DEFAULT_DISPLAY) {
+                onScreenOn(isDefaultDisplayOn());
+            }
+        }
+
         public void dumpLocked(PrintWriter pw) {
             pw.println("  BrightnessObserver");
 
@@ -891,8 +892,6 @@
         }
 
         private void onScreenOn(boolean on) {
-            // Not check mShouldObserveAmbientChange because Screen status receiver is registered
-            // only when it is true.
             if (mScreenOn != on) {
                 mScreenOn = on;
                 updateSensorStatus();
@@ -913,6 +912,13 @@
             }
         }
 
+        private boolean isDefaultDisplayOn() {
+            final Display display = mContext.getSystemService(DisplayManager.class)
+                    .getDisplay(Display.DEFAULT_DISPLAY);
+            return display.getState() != Display.STATE_OFF
+                    && mContext.getSystemService(PowerManager.class).isInteractive();
+        }
+
         private final class LightSensorEventListener implements SensorEventListener {
             final private static int INJECT_EVENTS_INTERVAL_MS = LIGHT_SENSOR_RATE_MS;
             private float mLastSensorData;
@@ -991,20 +997,5 @@
                 }
             };
         };
-
-        private final class ScreenStateReceiver extends BroadcastReceiver {
-            public ScreenStateReceiver(Context context) {
-                IntentFilter filter = new IntentFilter();
-                filter.addAction(Intent.ACTION_SCREEN_OFF);
-                filter.addAction(Intent.ACTION_SCREEN_ON);
-                filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
-                context.registerReceiver(this, filter, null, mHandler);
-            }
-
-            @Override
-            public void onReceive(Context context, Intent intent) {
-                onScreenOn(Intent.ACTION_SCREEN_ON.equals(intent.getAction()));
-            }
-        }
     }
 }
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 9510db0..f1f6d50 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -182,7 +182,7 @@
     @IntDef({CHALLENGE_NONE,
             CHALLENGE_FROM_CALLER,
             CHALLENGE_INTERNAL})
-    @interface ChallengeType {};
+    @interface ChallengeType {}
 
     // Order of holding lock: mSeparateChallengeLock -> mSpManager -> this
     // Do not call into ActivityManager while holding mSpManager lock.
@@ -1853,26 +1853,11 @@
             return VerifyCredentialResponse.ERROR;
         }
 
-        boolean shouldReEnrollBaseZero = storedHash.type == CREDENTIAL_TYPE_PATTERN
-                && storedHash.isBaseZeroPattern;
-
-        byte[] credentialToVerify;
-        if (shouldReEnrollBaseZero) {
-            credentialToVerify = LockPatternUtils.patternByteArrayToBaseZero(credential);
-        } else {
-            credentialToVerify = credential;
-        }
-
-        response = verifyCredential(userId, storedHash, credentialToVerify,
+        response = verifyCredential(userId, storedHash, credential,
                 challengeType, challenge, progressCallback);
 
         if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
             mStrongAuth.reportSuccessfulStrongAuthUnlock(userId);
-            if (shouldReEnrollBaseZero) {
-                setLockCredentialInternal(credential, storedHash.type, credentialToVerify,
-                        DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, userId, false,
-                        /* isLockTiedToParent= */ false);
-            }
         }
 
         return response;
@@ -1937,46 +1922,6 @@
         // of unlocking the user, so yell if calling from the main thread.
         StrictMode.noteDiskRead();
 
-        if (storedHash.version == CredentialHash.VERSION_LEGACY) {
-            final byte[] hash;
-            if (storedHash.type == CREDENTIAL_TYPE_PATTERN) {
-                hash = LockPatternUtils.patternToHash(
-                        LockPatternUtils.byteArrayToPattern(credential));
-            } else {
-                hash = mLockPatternUtils.legacyPasswordToHash(credential, userId).getBytes();
-            }
-            if (Arrays.equals(hash, storedHash.hash)) {
-                if (storedHash.type == CREDENTIAL_TYPE_PATTERN) {
-                    unlockKeystore(LockPatternUtils.patternByteArrayToBaseZero(credential), userId);
-                } else {
-                    unlockKeystore(credential, userId);
-                }
-                // Users with legacy credentials don't have credential-backed
-                // FBE keys, so just pass through a fake token/secret
-                Slog.i(TAG, "Unlocking user with fake token: " + userId);
-                final byte[] fakeToken = String.valueOf(userId).getBytes();
-                unlockUser(userId, fakeToken, fakeToken);
-
-                // migrate credential to GateKeeper
-                setLockCredentialInternal(credential, storedHash.type, null,
-                        storedHash.type == CREDENTIAL_TYPE_PATTERN
-                                ? DevicePolicyManager.PASSWORD_QUALITY_SOMETHING
-                                : DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC
-                                /* TODO(roosa): keep the same password quality */,
-                        userId, false, /* isLockTiedToParent= */ false);
-                if (challengeType == CHALLENGE_NONE) {
-                    notifyActivePasswordMetricsAvailable(storedHash.type, credential, userId);
-                    // Use credentials to create recoverable keystore snapshot.
-                    sendCredentialsOnUnlockIfRequired(storedHash.type, credential, userId);
-                    return VerifyCredentialResponse.OK;
-                }
-                // Fall through to get the auth token. Technically this should never happen,
-                // as a user that had a legacy credential would have to unlock their device
-                // before getting to a flow with a challenge, but supporting for consistency.
-            } else {
-                return VerifyCredentialResponse.ERROR;
-            }
-        }
         GateKeeperResponse gateKeeperResponse = getGateKeeperService()
                 .verifyChallenge(userId, challenge, storedHash.hash, credential);
         VerifyCredentialResponse response = convertResponse(gateKeeperResponse);
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsStorage.java b/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
index 84ae7c7..29b8aa2 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
@@ -77,10 +77,7 @@
 
     private static final String SYSTEM_DIRECTORY = "/system/";
     private static final String LOCK_PATTERN_FILE = "gatekeeper.pattern.key";
-    private static final String BASE_ZERO_LOCK_PATTERN_FILE = "gatekeeper.gesture.key";
-    private static final String LEGACY_LOCK_PATTERN_FILE = "gesture.key";
     private static final String LOCK_PASSWORD_FILE = "gatekeeper.password.key";
-    private static final String LEGACY_LOCK_PASSWORD_FILE = "password.key";
     private static final String CHILD_PROFILE_LOCK_FILE = "gatekeeper.profile.key";
 
     private static final String SYNTHETIC_PASSWORD_DIRECTORY = "spblob/";
@@ -96,59 +93,43 @@
 
     @VisibleForTesting
     public static class CredentialHash {
-        static final int VERSION_LEGACY = 0;
-        static final int VERSION_GATEKEEPER = 1;
+        /** Deprecated private static final int VERSION_LEGACY = 0; */
+        private static final int VERSION_GATEKEEPER = 1;
 
-        private CredentialHash(byte[] hash, @CredentialType int type, int version) {
-            this(hash, type, version, false /* isBaseZeroPattern */);
-        }
-
-        private CredentialHash(
-                byte[] hash, @CredentialType int type, int version, boolean isBaseZeroPattern) {
+        private CredentialHash(byte[] hash, @CredentialType int type) {
             if (type != LockPatternUtils.CREDENTIAL_TYPE_NONE) {
                 if (hash == null) {
-                    throw new RuntimeException("Empty hash for CredentialHash");
+                    throw new IllegalArgumentException("Empty hash for CredentialHash");
                 }
             } else /* type == LockPatternUtils.CREDENTIAL_TYPE_NONE */ {
                 if (hash != null) {
-                    throw new RuntimeException("None type CredentialHash should not have hash");
+                    throw new IllegalArgumentException(
+                            "None type CredentialHash should not have hash");
                 }
             }
             this.hash = hash;
             this.type = type;
-            this.version = version;
-            this.isBaseZeroPattern = isBaseZeroPattern;
-        }
-
-        private static CredentialHash createBaseZeroPattern(byte[] hash) {
-            return new CredentialHash(hash, LockPatternUtils.CREDENTIAL_TYPE_PATTERN,
-                    VERSION_GATEKEEPER, true /* isBaseZeroPattern */);
         }
 
         static CredentialHash create(byte[] hash, int type) {
             if (type == LockPatternUtils.CREDENTIAL_TYPE_NONE) {
-                throw new RuntimeException("Bad type for CredentialHash");
+                throw new IllegalArgumentException("Bad type for CredentialHash");
             }
-            return new CredentialHash(hash, type, VERSION_GATEKEEPER);
+            return new CredentialHash(hash, type);
         }
 
         static CredentialHash createEmptyHash() {
-            return new CredentialHash(null, LockPatternUtils.CREDENTIAL_TYPE_NONE,
-                    VERSION_GATEKEEPER);
+            return new CredentialHash(null, LockPatternUtils.CREDENTIAL_TYPE_NONE);
         }
 
         byte[] hash;
         @CredentialType int type;
-        int version;
-        boolean isBaseZeroPattern;
 
         public byte[] toBytes() {
-            Preconditions.checkState(!isBaseZeroPattern, "base zero patterns are not serializable");
-
             try {
                 ByteArrayOutputStream os = new ByteArrayOutputStream();
                 DataOutputStream dos = new DataOutputStream(os);
-                dos.write(version);
+                dos.write(VERSION_GATEKEEPER);
                 dos.write(type);
                 if (hash != null && hash.length > 0) {
                     dos.writeInt(hash.length);
@@ -166,7 +147,7 @@
         public static CredentialHash fromBytes(byte[] bytes) {
             try {
                 DataInputStream is = new DataInputStream(new ByteArrayInputStream(bytes));
-                int version = is.read();
+                /* int version = */ is.read();
                 int type = is.read();
                 int hashSize = is.readInt();
                 byte[] hash = null;
@@ -174,7 +155,7 @@
                     hash = new byte[hashSize];
                     is.readFully(hash);
                 }
-                return new CredentialHash(hash, type, version);
+                return new CredentialHash(hash, type);
             } catch (IOException e) {
                 throw new RuntimeException(e);
             }
@@ -269,14 +250,7 @@
     private CredentialHash readPasswordHashIfExists(int userId) {
         byte[] stored = readFile(getLockPasswordFilename(userId));
         if (!ArrayUtils.isEmpty(stored)) {
-            return new CredentialHash(stored, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
-                    CredentialHash.VERSION_GATEKEEPER);
-        }
-
-        stored = readFile(getLegacyLockPasswordFilename(userId));
-        if (!ArrayUtils.isEmpty(stored)) {
-            return new CredentialHash(stored, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
-                    CredentialHash.VERSION_LEGACY);
+            return new CredentialHash(stored, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD);
         }
         return null;
     }
@@ -284,39 +258,22 @@
     private CredentialHash readPatternHashIfExists(int userId) {
         byte[] stored = readFile(getLockPatternFilename(userId));
         if (!ArrayUtils.isEmpty(stored)) {
-            return new CredentialHash(stored, LockPatternUtils.CREDENTIAL_TYPE_PATTERN,
-                    CredentialHash.VERSION_GATEKEEPER);
-        }
-
-        stored = readFile(getBaseZeroLockPatternFilename(userId));
-        if (!ArrayUtils.isEmpty(stored)) {
-            return CredentialHash.createBaseZeroPattern(stored);
-        }
-
-        stored = readFile(getLegacyLockPatternFilename(userId));
-        if (!ArrayUtils.isEmpty(stored)) {
-            return new CredentialHash(stored, LockPatternUtils.CREDENTIAL_TYPE_PATTERN,
-                    CredentialHash.VERSION_LEGACY);
+            return new CredentialHash(stored, LockPatternUtils.CREDENTIAL_TYPE_PATTERN);
         }
         return null;
     }
 
     public CredentialHash readCredentialHash(int userId) {
         CredentialHash passwordHash = readPasswordHashIfExists(userId);
-        CredentialHash patternHash = readPatternHashIfExists(userId);
-        if (passwordHash != null && patternHash != null) {
-            if (passwordHash.version == CredentialHash.VERSION_GATEKEEPER) {
-                return passwordHash;
-            } else {
-                return patternHash;
-            }
-        } else if (passwordHash != null) {
+        if (passwordHash != null) {
             return passwordHash;
-        } else if (patternHash != null) {
-            return patternHash;
-        } else {
-            return CredentialHash.createEmptyHash();
         }
+
+        CredentialHash patternHash = readPatternHashIfExists(userId);
+        if (patternHash != null) {
+            return patternHash;
+        }
+        return CredentialHash.createEmptyHash();
     }
 
     public void removeChildProfileLock(int userId) {
@@ -342,14 +299,11 @@
     }
 
     public boolean hasPassword(int userId) {
-        return hasFile(getLockPasswordFilename(userId)) ||
-            hasFile(getLegacyLockPasswordFilename(userId));
+        return hasFile(getLockPasswordFilename(userId));
     }
 
     public boolean hasPattern(int userId) {
-        return hasFile(getLockPatternFilename(userId)) ||
-            hasFile(getBaseZeroLockPatternFilename(userId)) ||
-            hasFile(getLegacyLockPatternFilename(userId));
+        return hasFile(getLockPatternFilename(userId));
     }
 
     public boolean hasCredential(int userId) {
@@ -470,20 +424,6 @@
     }
 
     @VisibleForTesting
-    String getLegacyLockPatternFilename(int userId) {
-        return getLockCredentialFilePathForUser(userId, LEGACY_LOCK_PATTERN_FILE);
-    }
-
-    @VisibleForTesting
-    String getLegacyLockPasswordFilename(int userId) {
-        return getLockCredentialFilePathForUser(userId, LEGACY_LOCK_PASSWORD_FILE);
-    }
-
-    private String getBaseZeroLockPatternFilename(int userId) {
-        return getLockCredentialFilePathForUser(userId, BASE_ZERO_LOCK_PATTERN_FILE);
-    }
-
-    @VisibleForTesting
     String getChildProfileLockFile(int userId) {
         return getLockCredentialFilePathForUser(userId, CHILD_PROFILE_LOCK_FILE);
     }
diff --git a/services/core/java/com/android/server/media/OWNERS b/services/core/java/com/android/server/media/OWNERS
index 4bc9373..b460cb5 100644
--- a/services/core/java/com/android/server/media/OWNERS
+++ b/services/core/java/com/android/server/media/OWNERS
@@ -2,5 +2,6 @@
 hdmoon@google.com
 insun@google.com
 jaewan@google.com
+klhyun@google.com
 lajos@google.com
 sungsoo@google.com
diff --git a/services/core/java/com/android/server/om/IdmapDaemon.java b/services/core/java/com/android/server/om/IdmapDaemon.java
new file mode 100644
index 0000000..91824c3
--- /dev/null
+++ b/services/core/java/com/android/server/om/IdmapDaemon.java
@@ -0,0 +1,194 @@
+/*
+ * 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.om;
+
+import static android.content.Context.IDMAP_SERVICE;
+
+import static com.android.server.om.OverlayManagerService.DEBUG;
+import static com.android.server.om.OverlayManagerService.TAG;
+
+import android.os.IBinder;
+import android.os.IIdmap2;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.SystemProperties;
+import android.util.Slog;
+
+import com.android.server.FgThread;
+
+import java.util.concurrent.FutureTask;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * To prevent idmap2d from continuously running, the idmap daemon will terminate after 10
+ * seconds without a transaction.
+ **/
+class IdmapDaemon {
+    // The amount of time in milliseconds to wait after a transaction to the idmap service is made
+    // before stopping the service.
+    private static final int SERVICE_TIMEOUT_MS = 10000;
+
+    // The amount of time in milliseconds to wait when attempting to connect to idmap service.
+    private static final int SERVICE_CONNECT_TIMEOUT_MS = 5000;
+
+    private static final Object IDMAP_TOKEN = new Object();
+    private static final String IDMAP_DAEMON = "idmap2d";
+
+    private static IdmapDaemon sInstance;
+    private volatile IIdmap2 mService;
+    private final AtomicInteger mOpenedCount = new AtomicInteger();
+
+    /**
+     * An {@link AutoCloseable} connection to the idmap service. When the connection is closed or
+     * finalized, the idmap service will be stopped after a period of time unless another connection
+     * to the service is open.
+     **/
+    private class Connection implements AutoCloseable {
+        private boolean mOpened = true;
+
+        private Connection() {
+            synchronized (IDMAP_TOKEN) {
+                mOpenedCount.incrementAndGet();
+            }
+        }
+
+        @Override
+        public void close() {
+            synchronized (IDMAP_TOKEN) {
+                if (!mOpened) {
+                    return;
+                }
+
+                mOpened = false;
+                if (mOpenedCount.decrementAndGet() != 0) {
+                    // Only post the callback to stop the service if the service does not have an
+                    // open connection.
+                    return;
+                }
+
+                FgThread.getHandler().postDelayed(() -> {
+                    synchronized (IDMAP_TOKEN) {
+                        // Only stop the service if the service does not have an open connection.
+                        if (mService == null || mOpenedCount.get() != 0) {
+                            return;
+                        }
+
+                        stopIdmapService();
+                        mService = null;
+                    }
+                }, IDMAP_TOKEN, SERVICE_TIMEOUT_MS);
+            }
+        }
+    }
+
+    static IdmapDaemon getInstance() {
+        if (sInstance == null) {
+            sInstance = new IdmapDaemon();
+        }
+        return sInstance;
+    }
+
+    String createIdmap(String targetPath, String overlayPath, int policies, boolean enforce,
+            int userId) throws Exception {
+        try (Connection connection = connect()) {
+            return mService.createIdmap(targetPath, overlayPath, policies, enforce, userId);
+        }
+    }
+
+    boolean removeIdmap(String overlayPath, int userId) throws Exception {
+        try (Connection connection = connect()) {
+            return mService.removeIdmap(overlayPath, userId);
+        }
+    }
+
+    boolean verifyIdmap(String overlayPath, int policies, boolean enforce, int userId)
+            throws Exception {
+        try (Connection connection = connect()) {
+            return mService.verifyIdmap(overlayPath, policies, enforce, userId);
+        }
+    }
+
+    String getIdmapPath(String overlayPath, int userId) throws Exception {
+        try (Connection connection = connect()) {
+            return mService.getIdmapPath(overlayPath, userId);
+        }
+    }
+
+    static void startIdmapService() {
+        SystemProperties.set("ctl.start", IDMAP_DAEMON);
+    }
+
+    static void stopIdmapService() {
+        SystemProperties.set("ctl.stop", IDMAP_DAEMON);
+    }
+
+    private Connection connect() throws Exception {
+        synchronized (IDMAP_TOKEN) {
+            FgThread.getHandler().removeCallbacksAndMessages(IDMAP_TOKEN);
+            if (mService != null) {
+                // Not enough time has passed to stop the idmap service. Reuse the existing
+                // interface.
+                return new Connection();
+            }
+
+            // Start the idmap service if it is not currently running.
+            startIdmapService();
+
+            // Block until the service is found.
+            FutureTask<IBinder> bindIdmap = new FutureTask<>(() -> {
+                while (true) {
+                    try {
+                        IBinder binder = ServiceManager.getService(IDMAP_SERVICE);
+                        if (binder != null) {
+                            return binder;
+                        }
+                    } catch (Exception e) {
+                        Slog.e(TAG, "service '" + IDMAP_SERVICE + "' not retrieved; "
+                                + e.getMessage());
+                    }
+                    Thread.sleep(100);
+                }
+            });
+
+            IBinder binder;
+            try {
+                FgThread.getHandler().postAtFrontOfQueue(bindIdmap);
+                binder = bindIdmap.get(SERVICE_CONNECT_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+            } catch (Exception rethrow) {
+                Slog.e(TAG, "service '" + IDMAP_SERVICE + "' not found;");
+                throw rethrow;
+            }
+
+            try {
+                binder.linkToDeath(() -> {
+                    Slog.w(TAG, "service '" + IDMAP_SERVICE + "' died");
+                }, 0);
+            } catch (RemoteException rethrow) {
+                Slog.e(TAG, "service '" + IDMAP_SERVICE + "' failed to be bound");
+                throw rethrow;
+            }
+
+            mService = IIdmap2.Stub.asInterface(binder);
+            if (DEBUG) {
+                Slog.d(TAG, "service '" + IDMAP_SERVICE + "' connected");
+            }
+
+            return new Connection();
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/om/IdmapManager.java b/services/core/java/com/android/server/om/IdmapManager.java
index 1f20968..288ef0e 100644
--- a/services/core/java/com/android/server/om/IdmapManager.java
+++ b/services/core/java/com/android/server/om/IdmapManager.java
@@ -16,9 +16,6 @@
 
 package com.android.server.om;
 
-import static android.content.Context.IDMAP_SERVICE;
-import static android.text.format.DateUtils.SECOND_IN_MILLIS;
-
 import static com.android.server.om.OverlayManagerService.DEBUG;
 import static com.android.server.om.OverlayManagerService.TAG;
 
@@ -27,15 +24,11 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.os.Build.VERSION_CODES;
-import android.os.IBinder;
 import android.os.IIdmap2;
-import android.os.RemoteException;
-import android.os.ServiceManager;
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.util.Slog;
 
-import com.android.internal.os.BackgroundThread;
 import com.android.server.om.OverlayManagerServiceImpl.PackageManagerHelper;
 import com.android.server.pm.Installer;
 
@@ -51,11 +44,6 @@
  */
 class IdmapManager {
     private static final boolean FEATURE_FLAG_IDMAP2 = true;
-
-    private final Installer mInstaller;
-    private final PackageManagerHelper mPackageManager;
-    private IIdmap2 mIdmap2Service;
-
     private static final boolean VENDOR_IS_Q_OR_LATER;
     static {
         final String value = SystemProperties.get("ro.vndk.version", "29");
@@ -70,12 +58,14 @@
         VENDOR_IS_Q_OR_LATER = isQOrLater;
     }
 
+    private final Installer mInstaller;
+    private final PackageManagerHelper mPackageManager;
+    private final IdmapDaemon mIdmapDaemon;
+
     IdmapManager(final Installer installer, final PackageManagerHelper packageManager) {
         mInstaller = installer;
         mPackageManager = packageManager;
-        if (FEATURE_FLAG_IDMAP2) {
-            connectToIdmap2d();
-        }
+        mIdmapDaemon = IdmapDaemon.getInstance();
     }
 
     boolean createIdmap(@NonNull final PackageInfo targetPackage,
@@ -91,11 +81,11 @@
             if (FEATURE_FLAG_IDMAP2) {
                 int policies = calculateFulfilledPolicies(targetPackage, overlayPackage, userId);
                 boolean enforce = enforceOverlayable(overlayPackage);
-                if (mIdmap2Service.verifyIdmap(overlayPath, policies, enforce, userId)) {
+                if (mIdmapDaemon.verifyIdmap(overlayPath, policies, enforce, userId)) {
                     return true;
                 }
-                return mIdmap2Service.createIdmap(targetPath, overlayPath, policies, enforce,
-                    userId) != null;
+                return mIdmapDaemon.createIdmap(targetPath, overlayPath, policies,
+                        enforce, userId) != null;
             } else {
                 mInstaller.idmap(targetPath, overlayPath, sharedGid);
                 return true;
@@ -113,7 +103,7 @@
         }
         try {
             if (FEATURE_FLAG_IDMAP2) {
-                return mIdmap2Service.removeIdmap(oi.baseCodePath, userId);
+                return mIdmapDaemon.removeIdmap(oi.baseCodePath, userId);
             } else {
                 mInstaller.removeIdmap(oi.baseCodePath);
                 return true;
@@ -137,7 +127,7 @@
             final int userId) {
         if (FEATURE_FLAG_IDMAP2) {
             try {
-                return mIdmap2Service.getIdmapPath(overlayPackagePath, userId);
+                return mIdmapDaemon.getIdmapPath(overlayPackagePath, userId);
             } catch (Exception e) {
                 Slog.w(TAG, "failed to get idmap path for " + overlayPackagePath + ": "
                         + e.getMessage());
@@ -151,35 +141,6 @@
         }
     }
 
-    private void connectToIdmap2d() {
-        IBinder binder = ServiceManager.getService(IDMAP_SERVICE);
-        if (binder != null) {
-            try {
-                binder.linkToDeath(new IBinder.DeathRecipient() {
-                    @Override
-                    public void binderDied() {
-                        Slog.w(TAG, "service '" + IDMAP_SERVICE + "' died; reconnecting...");
-                        connectToIdmap2d();
-                    }
-
-                }, 0);
-            } catch (RemoteException e) {
-                binder = null;
-            }
-        }
-        if (binder != null) {
-            mIdmap2Service = IIdmap2.Stub.asInterface(binder);
-            if (DEBUG) {
-                Slog.d(TAG, "service '" + IDMAP_SERVICE + "' connected");
-            }
-        } else {
-            Slog.w(TAG, "service '" + IDMAP_SERVICE + "' not found; trying again...");
-            BackgroundThread.getHandler().postDelayed(() -> {
-                connectToIdmap2d();
-            }, SECOND_IN_MILLIS);
-        }
-    }
-
     /**
      * Checks if overlayable and policies should be enforced on the specified overlay for backwards
      * compatibility with pre-Q overlays.
diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java
index da69986..ce95181 100644
--- a/services/core/java/com/android/server/om/OverlayManagerService.java
+++ b/services/core/java/com/android/server/om/OverlayManagerService.java
@@ -262,6 +262,7 @@
 
             initIfNeeded();
             onSwitchUser(UserHandle.USER_SYSTEM);
+            IdmapDaemon.stopIdmapService();
 
             publishBinderService(Context.OVERLAY_SERVICE, mService);
             publishLocalService(OverlayManagerService.class, this);
diff --git a/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java b/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
index c98a79a..714bbb9 100644
--- a/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
+++ b/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
@@ -297,19 +297,5 @@
             }
             mDs.asBinder().unlinkToDeath(this, 0);
         }
-
-        // Old methods; unused in the API flow.
-        @Override
-        public void onProgressUpdated(int progress) throws RemoteException {
-        }
-
-        @Override
-        public void onMaxProgressUpdated(int maxProgress) throws RemoteException {
-        }
-
-        @Override
-        public void onSectionComplete(String title, int status, int size, int durationMs)
-                throws RemoteException {
-        }
     }
 }
diff --git a/services/core/java/com/android/server/pm/InstantAppRegistry.java b/services/core/java/com/android/server/pm/InstantAppRegistry.java
index 8f38026..5eaddf9 100644
--- a/services/core/java/com/android/server/pm/InstantAppRegistry.java
+++ b/services/core/java/com/android/server/pm/InstantAppRegistry.java
@@ -686,7 +686,7 @@
 
         // Prune first installed instant apps
         synchronized (mService.mLock) {
-            allUsers = PackageManagerService.sUserManager.getUserIds();
+            allUsers = mService.mUserManager.getUserIds();
 
             final int packageCount = mService.mPackages.size();
             for (int i = 0; i < packageCount; i++) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 2b99221..3f6d4df 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -118,7 +118,6 @@
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
 import android.app.ActivityManager;
-import android.app.ActivityManagerInternal;
 import android.app.AppOpsManager;
 import android.app.BroadcastOptions;
 import android.app.IActivityManager;
@@ -768,6 +767,26 @@
             T produce(Injector injector, PackageManagerService packageManager);
         }
 
+        static class LocalServicesProducer<T> implements Producer<T> {
+            private final Class<T> mProducingClass;
+            LocalServicesProducer(Class<T> clazz) {
+                this.mProducingClass = clazz;
+            }
+            public T produce(Injector injector, PackageManagerService packageManager) {
+                return LocalServices.getService(mProducingClass);
+            }
+        }
+
+        static class SystemServiceProducer<T> implements Producer<T> {
+            private final Class<T> mProducingClass;
+            SystemServiceProducer(Class<T> clazz) {
+                this.mProducingClass = clazz;
+            }
+            public T produce(Injector injector, PackageManagerService packageManager) {
+                return packageManager.mContext.getSystemService(mProducingClass);
+            }
+        }
+
         @VisibleForTesting(visibility = Visibility.PRIVATE)
         static class Singleton<T> {
             private final Producer<T> mProducer;
@@ -783,6 +802,8 @@
             }
         }
 
+        private PackageManagerService mPackageManager;
+
         private final PackageAbiHelper mAbiHelper;
         private final Context mContext;
         private final Object mLock;
@@ -790,19 +811,35 @@
         private final Object mInstallLock;
 
         // ----- producers -----
-
         private final Singleton<ComponentResolver> mComponentResolverProducer;
         private final Singleton<PermissionManagerServiceInternal> mPermissionManagerProducer;
         private final Singleton<UserManagerService> mUserManagerProducer;
         private final Singleton<Settings> mSettingsProducer;
-        private PackageManagerService mPackageManager;
+        private final Singleton<ActivityTaskManagerInternal> mActivityTaskManagerProducer;
+        private final Singleton<DeviceIdleController.LocalService> mLocalDeviceIdleController;
+        private final Singleton<StorageManagerInternal> mStorageManagerInternalProducer;
+        private final Singleton<NetworkPolicyManagerInternal> mNetworkPolicyManagerProducer;
+        private final Singleton<PermissionPolicyInternal> mPermissionPolicyProducer;
+        private final Singleton<DeviceStorageMonitorInternal> mDeviceStorageMonitorProducer;
+        private final Singleton<DisplayManager> mDisplayManagerProducer;
+        private final Singleton<StorageManager> mStorageManagerProducer;
+        private final Singleton<AppOpsManager> mAppOpsManagerProducer;
 
         Injector(Context context, Object lock, Installer installer,
                 Object installLock, PackageAbiHelper abiHelper,
                 Producer<ComponentResolver> componentResolverProducer,
                 Producer<PermissionManagerServiceInternal> permissionManagerProducer,
                 Producer<UserManagerService> userManagerProducer,
-                Producer<Settings> settingsProducer) {
+                Producer<Settings> settingsProducer,
+                Producer<ActivityTaskManagerInternal> activityTaskManagerProducer,
+                Producer<DeviceIdleController.LocalService> deviceIdleControllerProducer,
+                Producer<StorageManagerInternal> storageManagerInternalProducer,
+                Producer<NetworkPolicyManagerInternal> networkPolicyManagerProducer,
+                Producer<PermissionPolicyInternal> permissionPolicyProvider,
+                Producer<DeviceStorageMonitorInternal> deviceStorageMonitorProducer,
+                Producer<DisplayManager> displayManagerProducer,
+                Producer<StorageManager> storageManagerProducer,
+                Producer<AppOpsManager> appOpsManagerProducer) {
             mContext = context;
             mLock = lock;
             mInstaller = installer;
@@ -812,6 +849,15 @@
             mPermissionManagerProducer = new Singleton<>(permissionManagerProducer);
             mUserManagerProducer = new Singleton<>(userManagerProducer);
             mSettingsProducer = new Singleton<>(settingsProducer);
+            mActivityTaskManagerProducer = new Singleton<>(activityTaskManagerProducer);
+            mLocalDeviceIdleController = new Singleton<>(deviceIdleControllerProducer);
+            mStorageManagerInternalProducer = new Singleton<>(storageManagerInternalProducer);
+            mNetworkPolicyManagerProducer = new Singleton<>(networkPolicyManagerProducer);
+            mPermissionPolicyProducer = new Singleton<>(permissionPolicyProvider);
+            mDeviceStorageMonitorProducer = new Singleton<>(deviceStorageMonitorProducer);
+            mDisplayManagerProducer = new Singleton<>(displayManagerProducer);
+            mStorageManagerProducer = new Singleton<>(storageManagerProducer);
+            mAppOpsManagerProducer = new Singleton<>(appOpsManagerProducer);
         }
 
         /**
@@ -822,7 +868,7 @@
             this.mPackageManager = pm;
         }
 
-        public UserManagerInternal getUserManager() {
+        public UserManagerInternal getUserManagerInternal() {
             return getUserManagerService().getInternalForInjectorOnly();
         }
 
@@ -861,6 +907,42 @@
         public Settings getSettings() {
             return mSettingsProducer.get(this, mPackageManager);
         }
+
+        public ActivityTaskManagerInternal getActivityTaskManagerInternal() {
+            return mActivityTaskManagerProducer.get(this, mPackageManager);
+        }
+
+        public DeviceIdleController.LocalService getLocalDeviceIdleController() {
+            return mLocalDeviceIdleController.get(this, mPackageManager);
+        }
+
+        public StorageManagerInternal getStorageManagerInternal() {
+            return mStorageManagerInternalProducer.get(this, mPackageManager);
+        }
+
+        public NetworkPolicyManagerInternal getNetworkPolicyManagerInternal() {
+            return mNetworkPolicyManagerProducer.get(this, mPackageManager);
+        }
+
+        public PermissionPolicyInternal getPermissionPolicyInternal() {
+            return mPermissionPolicyProducer.get(this, mPackageManager);
+        }
+
+        public DeviceStorageMonitorInternal getDeviceStorageMonitorInternal() {
+            return mDeviceStorageMonitorProducer.get(this, mPackageManager);
+        }
+
+        public DisplayManager getDisplayManager() {
+            return mDisplayManagerProducer.get(this, mPackageManager);
+        }
+
+        public StorageManager getStorageManager() {
+            return mStorageManagerProducer.get(this, mPackageManager);
+        }
+
+        public AppOpsManager getAppOpsManager() {
+            return mAppOpsManagerProducer.get(this, mPackageManager);
+        }
     }
 
     private final AppsFilter mAppsFilter;
@@ -1077,12 +1159,6 @@
     // List of packages names to keep cached, even if they are uninstalled for all users
     private List<String> mKeepUninstalledPackages;
 
-    private ActivityManagerInternal mActivityManagerInternal;
-    private ActivityTaskManagerInternal mActivityTaskManagerInternal;
-    private StorageManagerInternal mStorageManagerInternal;
-
-    private DeviceIdleController.LocalService mDeviceIdleController;
-
     private File mCacheDir;
 
     private Future<?> mPrepareAppDataFuture;
@@ -1173,7 +1249,8 @@
             final BroadcastOptions options = BroadcastOptions.makeBasic();
             options.setTemporaryAppWhitelistDuration(whitelistTimeout);
 
-            DeviceIdleController.LocalService idleController = getDeviceIdleController();
+            DeviceIdleController.LocalService idleController =
+                    mInjector.getLocalDeviceIdleController();
             idleController.addPowerSaveTempWhitelistApp(Process.myUid(),
                     mIntentFilterVerifierComponent.getPackageName(), whitelistTimeout,
                     UserHandle.USER_SYSTEM, true, "intent filter verifier");
@@ -1440,7 +1517,7 @@
     private static final long DEFAULT_UNUSED_STATIC_SHARED_LIB_MIN_CACHE_PERIOD =
             2 * 60 * 60 * 1000L; /* two hours */
 
-    static UserManagerService sUserManager;
+    UserManagerService mUserManager;
 
     // Stores a list of users whose package restrictions file needs to be updated
     private ArraySet<Integer> mDirtyUsers = new ArraySet<>();
@@ -2037,8 +2114,7 @@
                 // Send broadcast package appeared if external for all users
                 if (isExternal(res.pkg)) {
                     if (!update) {
-                        final StorageManager storage =
-                                mContext.getSystemService(StorageManager.class);
+                        final StorageManager storage = mInjector.getStorageManager();
                         VolumeInfo volume =
                                 storage.findVolumeByUuid(
                                         res.pkg.applicationInfo.storageUuid.toString());
@@ -2229,7 +2305,7 @@
 
                     // Clean up any users or apps that were removed or recreated
                     // while this volume was missing
-                    sUserManager.reconcileUsers(volumeUuid);
+                    mUserManager.reconcileUsers(volumeUuid);
                     reconcileApps(volumeUuid);
 
                     // Clean up any install sessions that expired or were
@@ -2314,9 +2390,9 @@
 
     void scheduleWritePackageRestrictionsLocked(int userId) {
         final int[] userIds = (userId == UserHandle.USER_ALL)
-                ? sUserManager.getUserIds() : new int[]{userId};
+                ? mUserManager.getUserIds() : new int[]{userId};
         for (int nextUserId : userIds) {
-            if (!sUserManager.exists(nextUserId)) return;
+            if (!mUserManager.exists(nextUserId)) return;
             mDirtyUsers.add(nextUserId);
             if (!mHandler.hasMessages(WRITE_PACKAGE_RESTRICTIONS)) {
                 mHandler.sendEmptyMessageDelayed(WRITE_PACKAGE_RESTRICTIONS, WRITE_SETTINGS_DELAY);
@@ -2334,8 +2410,8 @@
         final Object lock = new Object();
         final Object installLock = new Object();
 
-        Injector injector = new Injector(context, lock, installer, installLock,
-                new PackageAbiHelperImpl(),
+        Injector injector = new Injector(
+                context, lock, installer, installLock, new PackageAbiHelperImpl(),
                 (i, pm) ->
                         new ComponentResolver(i.getUserManagerService(), pm.mPmInternal, lock),
                 (i, pm) ->
@@ -2347,7 +2423,16 @@
                 (i, pm) ->
                         new Settings(Environment.getDataDirectory(),
                                 i.getPermissionManagerServiceInternal().getPermissionSettings(),
-                                lock));
+                                lock),
+                new Injector.LocalServicesProducer<>(ActivityTaskManagerInternal.class),
+                new Injector.LocalServicesProducer<>(DeviceIdleController.LocalService.class),
+                new Injector.LocalServicesProducer<>(StorageManagerInternal.class),
+                new Injector.LocalServicesProducer<>(NetworkPolicyManagerInternal.class),
+                new Injector.LocalServicesProducer<>(PermissionPolicyInternal.class),
+                new Injector.LocalServicesProducer<>(DeviceStorageMonitorInternal.class),
+                new Injector.SystemServiceProducer<>(DisplayManager.class),
+                new Injector.SystemServiceProducer<>(StorageManager.class),
+                new Injector.SystemServiceProducer<>(AppOpsManager.class));
 
         PackageManagerService m = new PackageManagerService(injector, factoryTest, onlyCore);
         t.traceEnd(); // "create package manager"
@@ -2403,9 +2488,8 @@
         }
     }
 
-    private static void getDefaultDisplayMetrics(Context context, DisplayMetrics metrics) {
-        DisplayManager displayManager = (DisplayManager) context.getSystemService(
-                Context.DISPLAY_SERVICE);
+    private static void getDefaultDisplayMetrics(
+            DisplayManager displayManager, DisplayMetrics metrics) {
         displayManager.getDisplay(Display.DEFAULT_DISPLAY).getMetrics(metrics);
     }
 
@@ -2469,13 +2553,12 @@
         // Expose private service for system components to use.
         mPmInternal = new PackageManagerInternalImpl();
         LocalServices.addService(PackageManagerInternal.class, mPmInternal);
-        sUserManager = injector.getUserManagerService();
+        mUserManager = injector.getUserManagerService();
         mComponentResolver = injector.getComponentResolver();
         mPermissionManager = injector.getPermissionManagerServiceInternal();
         mSettings = injector.getSettings();
         mPermissionManagerService = (IPermissionManager) ServiceManager.getService("permissionmgr");
 
-
         // CHECKSTYLE:ON IndentationCheck
         t.traceEnd();
 
@@ -2524,7 +2607,7 @@
 
         mViewCompiler = new ViewCompiler(mInstallLock, mInstaller);
 
-        getDefaultDisplayMetrics(mContext, mMetrics);
+        getDefaultDisplayMetrics(mInjector.getDisplayManager(), mMetrics);
 
         t.traceBegin("get system config");
         SystemConfig systemConfig = SystemConfig.getInstance();
@@ -2580,7 +2663,7 @@
             t.traceEnd();
 
             t.traceBegin("read user settings");
-            mFirstBoot = !mSettings.readLPw(sUserManager.getUsers(false));
+            mFirstBoot = !mSettings.readLPw(mUserManager.getUsers(false));
             t.traceEnd();
 
             // Clean up orphaned packages for which the code path doesn't exist
@@ -3235,7 +3318,7 @@
             // boot, then we need to initialize the default preferred apps across
             // all defined users.
             if (!mOnlyCore && (mPromoteSystemApps || mFirstBoot)) {
-                for (UserInfo user : sUserManager.getUsers(true)) {
+                for (UserInfo user : mUserManager.getUsers(true)) {
                     mSettings.applyDefaultPreferredAppsLPw(user.id);
                     primeDomainVerificationsLPw(user.id);
                 }
@@ -4121,7 +4204,7 @@
     }
 
     private PackageInfo generatePackageInfo(PackageSetting ps, int flags, int userId) {
-        if (!sUserManager.exists(userId)) return null;
+        if (!mUserManager.exists(userId)) return null;
         if (ps == null) {
             return null;
         }
@@ -4224,7 +4307,7 @@
 
     @Override
     public boolean isPackageAvailable(String packageName, int userId) {
-        if (!sUserManager.exists(userId)) return false;
+        if (!mUserManager.exists(userId)) return false;
         final int callingUid = Binder.getCallingUid();
         mPermissionManager.enforceCrossUserPermission(callingUid, userId,
                 false /*requireFullPermission*/, false /*checkShell*/, "is package available");
@@ -4267,7 +4350,7 @@
      */
     private PackageInfo getPackageInfoInternal(String packageName, long versionCode,
             int flags, int filterCallingUid, int userId) {
-        if (!sUserManager.exists(userId)) return null;
+        if (!mUserManager.exists(userId)) return null;
         flags = updateFlagsForPackage(flags, userId, packageName);
         mPermissionManager.enforceCrossUserPermission(Binder.getCallingUid(), userId,
                 false /* requireFullPermission */, false /* checkShell */, "get package info");
@@ -4568,7 +4651,7 @@
 
     @Override
     public int getPackageUid(String packageName, int flags, int userId) {
-        if (!sUserManager.exists(userId)) return -1;
+        if (!mUserManager.exists(userId)) return -1;
         final int callingUid = Binder.getCallingUid();
         flags = updateFlagsForPackage(flags, userId, packageName);
         mPermissionManager.enforceCrossUserPermission(callingUid, userId,
@@ -4598,7 +4681,7 @@
 
     @Override
     public int[] getPackageGids(String packageName, int flags, int userId) {
-        if (!sUserManager.exists(userId)) return null;
+        if (!mUserManager.exists(userId)) return null;
         final int callingUid = Binder.getCallingUid();
         flags = updateFlagsForPackage(flags, userId, packageName);
         mPermissionManager.enforceCrossUserPermission(callingUid, userId,
@@ -4642,7 +4725,7 @@
     @GuardedBy("mLock")
     private ApplicationInfo generateApplicationInfoFromSettingsLPw(String packageName, int flags,
             int filterCallingUid, int userId) {
-        if (!sUserManager.exists(userId)) return null;
+        if (!mUserManager.exists(userId)) return null;
         PackageSetting ps = mSettings.mPackages.get(packageName);
         if (ps != null) {
             if (filterSharedLibPackageLPr(ps, filterCallingUid, userId, flags)) {
@@ -4681,7 +4764,7 @@
      */
     private ApplicationInfo getApplicationInfoInternal(String packageName, int flags,
             int filterCallingUid, int userId) {
-        if (!sUserManager.exists(userId)) return null;
+        if (!mUserManager.exists(userId)) return null;
         flags = updateFlagsForApplication(flags, userId, packageName);
 
         if (!isRecentsAccessingChildProfiles(Binder.getCallingUid(), userId)) {
@@ -4795,7 +4878,7 @@
      * until the requested bytes are available.
      */
     public void freeStorage(String volumeUuid, long bytes, int storageFlags) throws IOException {
-        final StorageManager storage = mContext.getSystemService(StorageManager.class);
+        final StorageManager storage = mInjector.getStorageManager();
         final File file = storage.findPathForUuid(volumeUuid);
         if (file.getUsableSpace() >= bytes) return;
 
@@ -4878,14 +4961,14 @@
 
     private boolean pruneUnusedStaticSharedLibraries(long neededSpace, long maxCachePeriod)
             throws IOException {
-        final StorageManager storage = mContext.getSystemService(StorageManager.class);
+        final StorageManager storage = mInjector.getStorageManager();
         final File volume = storage.findPathForUuid(StorageManager.UUID_PRIVATE_INTERNAL);
 
         List<VersionedPackage> packagesToDelete = null;
         final long now = System.currentTimeMillis();
 
         synchronized (mLock) {
-            final int[] allUsers = sUserManager.getUserIds();
+            final int[] allUsers = mUserManager.getUserIds();
             final int libCount = mSharedLibraries.size();
             for (int i = 0; i < libCount; i++) {
                 final LongSparseArray<SharedLibraryInfo> versionedLib
@@ -4957,7 +5040,7 @@
             // give them what they want
         } else {
             // Caller expressed no opinion, so match based on user state
-            if (mInjector.getUserManager().isUserUnlockingOrUnlocked(userId)) {
+            if (mUserManager.isUserUnlockingOrUnlocked(userId)) {
                 flags |= PackageManager.MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE;
             } else {
                 flags |= PackageManager.MATCH_DIRECT_BOOT_AWARE;
@@ -4966,36 +5049,6 @@
         return flags;
     }
 
-    private ActivityManagerInternal getActivityManagerInternal() {
-        if (mActivityManagerInternal == null) {
-            mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
-        }
-        return mActivityManagerInternal;
-    }
-
-    private ActivityTaskManagerInternal getActivityTaskManagerInternal() {
-        if (mActivityTaskManagerInternal == null) {
-            mActivityTaskManagerInternal =
-                    LocalServices.getService(ActivityTaskManagerInternal.class);
-        }
-        return mActivityTaskManagerInternal;
-    }
-
-    private DeviceIdleController.LocalService getDeviceIdleController() {
-        if (mDeviceIdleController == null) {
-            mDeviceIdleController =
-                    LocalServices.getService(DeviceIdleController.LocalService.class);
-        }
-        return mDeviceIdleController;
-    }
-
-    private StorageManagerInternal getStorageManagerInternal() {
-        if (mStorageManagerInternal == null) {
-            mStorageManagerInternal = LocalServices.getService(StorageManagerInternal.class);
-        }
-        return mStorageManagerInternal;
-    }
-
     /**
      * Update given flags when being used to request {@link PackageInfo}.
      */
@@ -5010,7 +5063,7 @@
                     "MATCH_ANY_USER flag requires INTERACT_ACROSS_USERS permission at "
                     + Debug.getCallers(5));
         } else if ((flags & PackageManager.MATCH_UNINSTALLED_PACKAGES) != 0 && isCallerSystemUser
-                && sUserManager.hasManagedProfile(UserHandle.USER_SYSTEM)) {
+                && mUserManager.hasManagedProfile(UserHandle.USER_SYSTEM)) {
             // If the caller wants all packages and has a restricted profile associated with it,
             // then match all users. This is to make sure that launchers that need to access work
             // profile apps don't start breaking. TODO: Remove this hack when launchers stop using
@@ -5107,7 +5160,7 @@
      */
     private ActivityInfo getActivityInfoInternal(ComponentName component, int flags,
             int filterCallingUid, int userId) {
-        if (!sUserManager.exists(userId)) return null;
+        if (!mUserManager.exists(userId)) return null;
         flags = updateFlagsForComponent(flags, userId, component);
 
         if (!isRecentsAccessingChildProfiles(Binder.getCallingUid(), userId)) {
@@ -5138,7 +5191,7 @@
     }
 
     private boolean isRecentsAccessingChildProfiles(int callingUid, int targetUserId) {
-        if (!getActivityTaskManagerInternal().isCallerRecents(callingUid)) {
+        if (!mInjector.getActivityTaskManagerInternal().isCallerRecents(callingUid)) {
             return false;
         }
         final long token = Binder.clearCallingIdentity();
@@ -5147,7 +5200,7 @@
             if (ActivityManager.getCurrentUser() != callingUserId) {
                 return false;
             }
-            return sUserManager.isSameProfileGroup(callingUserId, targetUserId);
+            return mUserManager.isSameProfileGroup(callingUserId, targetUserId);
         } finally {
             Binder.restoreCallingIdentity(token);
         }
@@ -5187,7 +5240,7 @@
 
     @Override
     public ActivityInfo getReceiverInfo(ComponentName component, int flags, int userId) {
-        if (!sUserManager.exists(userId)) return null;
+        if (!mUserManager.exists(userId)) return null;
         final int callingUid = Binder.getCallingUid();
         flags = updateFlagsForComponent(flags, userId, component);
         mPermissionManager.enforceCrossUserPermission(callingUid, userId,
@@ -5213,7 +5266,7 @@
     @Override
     public ParceledListSlice<SharedLibraryInfo> getSharedLibraries(String packageName,
             int flags, int userId) {
-        if (!sUserManager.exists(userId)) return null;
+        if (!mUserManager.exists(userId)) return null;
         Preconditions.checkArgumentNonnegative(userId, "userId must be >= 0");
         if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
             return null;
@@ -5295,7 +5348,7 @@
 
         Preconditions.checkNotNull(packageName, "packageName cannot be null");
         Preconditions.checkArgumentNonnegative(userId, "userId must be >= 0");
-        if (!sUserManager.exists(userId)) {
+        if (!mUserManager.exists(userId)) {
             return null;
         }
 
@@ -5402,7 +5455,7 @@
 
     @Override
     public ServiceInfo getServiceInfo(ComponentName component, int flags, int userId) {
-        if (!sUserManager.exists(userId)) return null;
+        if (!mUserManager.exists(userId)) return null;
         final int callingUid = Binder.getCallingUid();
         flags = updateFlagsForComponent(flags, userId, component);
         mPermissionManager.enforceCrossUserPermission(callingUid, userId,
@@ -5427,7 +5480,7 @@
 
     @Override
     public ProviderInfo getProviderInfo(ComponentName component, int flags, int userId) {
-        if (!sUserManager.exists(userId)) return null;
+        if (!mUserManager.exists(userId)) return null;
         final int callingUid = Binder.getCallingUid();
         flags = updateFlagsForComponent(flags, userId, component);
         mPermissionManager.enforceCrossUserPermission(callingUid, userId,
@@ -6127,7 +6180,7 @@
         try {
             Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "resolveIntent");
 
-            if (!sUserManager.exists(userId)) return null;
+            if (!mUserManager.exists(userId)) return null;
             final int callingUid = Binder.getCallingUid();
             flags = updateFlagsForResolve(flags, userId, intent, filterCallingUid, resolveForStart);
             mPermissionManager.enforceCrossUserPermission(callingUid, userId,
@@ -6152,7 +6205,7 @@
             throw new SecurityException(
                     "findPersistentPreferredActivity can only be run by the system");
         }
-        if (!sUserManager.exists(userId)) {
+        if (!mUserManager.exists(userId)) {
             return null;
         }
         final int callingUid = Binder.getCallingUid();
@@ -6465,7 +6518,7 @@
             Slog.wtf(TAG, "Calling thread " + Thread.currentThread().getName()
                     + " is holding mPackages", new Throwable());
         }
-        if (!sUserManager.exists(userId)) return null;
+        if (!mUserManager.exists(userId)) return null;
         final int callingUid = Binder.getCallingUid();
         // Do NOT hold the packages lock; this calls up into the settings provider which
         // could cause a deadlock.
@@ -6694,7 +6747,7 @@
     private UserInfo getProfileParent(int userId) {
         final long identity = Binder.clearCallingIdentity();
         try {
-            return sUserManager.getProfileParent(userId);
+            return mUserManager.getProfileParent(userId);
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
@@ -6753,7 +6806,7 @@
     private @NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent,
             String resolvedType, int flags, int filterCallingUid, int userId,
             boolean resolveForStart, boolean allowDynamicSplits) {
-        if (!sUserManager.exists(userId)) return Collections.emptyList();
+        if (!mUserManager.exists(userId)) return Collections.emptyList();
         final String instantAppPkgName = getInstantAppPackageName(filterCallingUid);
         mPermissionManager.enforceCrossUserPermission(Binder.getCallingUid(), userId,
                 false /* requireFullPermission */, false /* checkShell */,
@@ -7027,7 +7080,7 @@
 
     private CrossProfileDomainInfo getCrossProfileDomainPreferredLpr(Intent intent,
             String resolvedType, int flags, int sourceUserId, int parentUserId) {
-        if (!sUserManager.hasUserRestriction(UserManager.ALLOW_PARENT_PROFILE_APP_LINKING,
+        if (!mUserManager.hasUserRestriction(UserManager.ALLOW_PARENT_PROFILE_APP_LINKING,
                 sourceUserId)) {
             return null;
         }
@@ -7088,7 +7141,7 @@
     private boolean isUserEnabled(int userId) {
         long callingId = Binder.clearCallingIdentity();
         try {
-            UserInfo userInfo = sUserManager.getUserInfo(userId);
+            UserInfo userInfo = mUserManager.getUserInfo(userId);
             return userInfo != null && userInfo.isEnabled();
         } finally {
             Binder.restoreCallingIdentity(callingId);
@@ -7493,7 +7546,7 @@
         long ident = Binder.clearCallingIdentity();
         boolean targetIsProfile;
         try {
-            targetIsProfile = sUserManager.getUserInfo(targetUserId).isManagedProfile();
+            targetIsProfile = mUserManager.getUserInfo(targetUserId).isManagedProfile();
         } finally {
             Binder.restoreCallingIdentity(ident);
         }
@@ -7532,7 +7585,7 @@
     private @NonNull List<ResolveInfo> queryIntentActivityOptionsInternal(ComponentName caller,
             Intent[] specifics, String[] specificTypes, Intent intent,
             String resolvedType, int flags, int userId) {
-        if (!sUserManager.exists(userId)) return Collections.emptyList();
+        if (!mUserManager.exists(userId)) return Collections.emptyList();
         final int callingUid = Binder.getCallingUid();
         flags = updateFlagsForResolve(flags, userId, intent, callingUid,
                 false /*includeInstantApps*/);
@@ -7715,7 +7768,7 @@
 
     private @NonNull List<ResolveInfo> queryIntentReceiversInternal(Intent intent,
             String resolvedType, int flags, int userId, boolean allowDynamicSplits) {
-        if (!sUserManager.exists(userId)) return Collections.emptyList();
+        if (!mUserManager.exists(userId)) return Collections.emptyList();
         final int callingUid = Binder.getCallingUid();
         mPermissionManager.enforceCrossUserPermission(callingUid, userId,
                 false /*requireFullPermission*/, false /*checkShell*/,
@@ -7805,7 +7858,7 @@
 
     private ResolveInfo resolveServiceInternal(Intent intent, String resolvedType, int flags,
             int userId, int callingUid) {
-        if (!sUserManager.exists(userId)) return null;
+        if (!mUserManager.exists(userId)) return null;
         flags = updateFlagsForResolve(
                 flags, userId, intent, callingUid, false /*includeInstantApps*/);
         List<ResolveInfo> query = queryIntentServicesInternal(
@@ -7831,7 +7884,7 @@
     private @NonNull List<ResolveInfo> queryIntentServicesInternal(Intent intent,
             String resolvedType, int flags, int userId, int callingUid,
             boolean includeInstantApps) {
-        if (!sUserManager.exists(userId)) return Collections.emptyList();
+        if (!mUserManager.exists(userId)) return Collections.emptyList();
         mPermissionManager.enforceCrossUserPermission(callingUid, userId,
                 false /*requireFullPermission*/, false /*checkShell*/,
                 "query intent receivers");
@@ -7950,7 +8003,7 @@
 
     private @NonNull List<ResolveInfo> queryIntentContentProvidersInternal(
             Intent intent, String resolvedType, int flags, int userId) {
-        if (!sUserManager.exists(userId)) return Collections.emptyList();
+        if (!mUserManager.exists(userId)) return Collections.emptyList();
         final int callingUid = Binder.getCallingUid();
         final String instantAppPkgName = getInstantAppPackageName(callingUid);
         flags = updateFlagsForResolve(flags, userId, intent, callingUid,
@@ -8065,7 +8118,7 @@
         if (getInstantAppPackageName(callingUid) != null) {
             return ParceledListSlice.emptyList();
         }
-        if (!sUserManager.exists(userId)) return ParceledListSlice.emptyList();
+        if (!mUserManager.exists(userId)) return ParceledListSlice.emptyList();
         flags = updateFlagsForPackage(flags, userId, null);
         final boolean listUninstalled = (flags & MATCH_KNOWN_PACKAGES) != 0;
         final boolean listApex = (flags & MATCH_APEX) != 0;
@@ -8165,7 +8218,7 @@
     @Override
     public ParceledListSlice<PackageInfo> getPackagesHoldingPermissions(
             String[] permissions, int flags, int userId) {
-        if (!sUserManager.exists(userId)) return ParceledListSlice.emptyList();
+        if (!mUserManager.exists(userId)) return ParceledListSlice.emptyList();
         flags = updateFlagsForPackage(flags, userId, permissions);
         mPermissionManager.enforceCrossUserPermission(Binder.getCallingUid(), userId,
                 true /* requireFullPermission */, false /* checkShell */,
@@ -8207,7 +8260,7 @@
         if (getInstantAppPackageName(callingUid) != null) {
             return Collections.emptyList();
         }
-        if (!sUserManager.exists(userId)) return Collections.emptyList();
+        if (!mUserManager.exists(userId)) return Collections.emptyList();
         flags = updateFlagsForApplication(flags, userId, null);
         final boolean listUninstalled = (flags & MATCH_KNOWN_PACKAGES) != 0;
 
@@ -8437,7 +8490,7 @@
     }
 
     private ProviderInfo resolveContentProviderInternal(String name, int flags, int userId) {
-        if (!sUserManager.exists(userId)) return null;
+        if (!mUserManager.exists(userId)) return null;
         flags = updateFlagsForComponent(flags, userId, name);
         final int callingUid = Binder.getCallingUid();
         final ProviderInfo providerInfo = mComponentResolver.queryProvider(name, flags, userId);
@@ -8476,7 +8529,7 @@
         final int callingUid = Binder.getCallingUid();
         final int userId = processName != null ? UserHandle.getUserId(uid)
                 : UserHandle.getCallingUserId();
-        if (!sUserManager.exists(userId)) return ParceledListSlice.emptyList();
+        if (!mUserManager.exists(userId)) return ParceledListSlice.emptyList();
         flags = updateFlagsForComponent(flags, userId, processName);
         ArrayList<ProviderInfo> finalList = null;
         final List<ProviderInfo> matchList =
@@ -9852,7 +9905,7 @@
     }
 
     private int[] resolveUserIds(int userId) {
-        return (userId == UserHandle.USER_ALL) ? sUserManager.getUserIds() : new int[] { userId };
+        return (userId == UserHandle.USER_ALL) ? mUserManager.getUserIds() : new int[] { userId };
     }
 
     private void clearAppDataLIF(PackageParser.Package pkg, int userId, int flags) {
@@ -10248,7 +10301,7 @@
                     if (!pkg.isSystem() || pkg.isUpdatedSystemApp()) {
                         final int flags = pkg.isUpdatedSystemApp()
                                 ? PackageManager.DELETE_KEEP_DATA : 0;
-                        deletePackageLIF(pkg.packageName, null, true, sUserManager.getUserIds(),
+                        deletePackageLIF(pkg.packageName, null, true, mUserManager.getUserIds(),
                                 flags , null, true, null);
                     }
                     Slog.e(TAG, "updateAllSharedLibrariesLPw failed: " + e.getMessage());
@@ -10588,14 +10641,15 @@
         final String realPkgName = request.realPkgName;
         final List<String> changedAbiCodePath = result.changedAbiCodePath;
         final PackageSetting pkgSetting;
+        if (request.pkgSetting != null && request.pkgSetting.sharedUser != null
+                && request.pkgSetting.sharedUser != result.pkgSetting.sharedUser) {
+            // shared user changed, remove from old shared user
+            request.pkgSetting.sharedUser.removePackage(request.pkgSetting);
+        }
         if (result.existingSettingCopied) {
             pkgSetting = request.pkgSetting;
             pkgSetting.updateFrom(result.pkgSetting);
             pkg.mExtras = pkgSetting;
-            if (pkgSetting.sharedUser != null
-                    && pkgSetting.sharedUser.removePackage(result.pkgSetting)) {
-                pkgSetting.sharedUser.addPackage(pkgSetting);
-            }
         } else {
             pkgSetting = result.pkgSetting;
             if (originalPkgSetting != null) {
@@ -10605,6 +10659,9 @@
                 mTransferedPackages.add(originalPkgSetting.name);
             }
         }
+        if (pkgSetting.sharedUser != null) {
+            pkgSetting.sharedUser.addPackage(pkgSetting);
+        }
         // TODO(toddke): Consider a method specifically for modifying the Package object
         // post scan; or, moving this stuff out of the Package object since it has nothing
         // to do with the package on disk.
@@ -10817,7 +10874,7 @@
             boolean isUnderFactoryTest, long currentTime)
             throws PackageManagerException {
         final PackageAbiHelper packageAbiHelper = injector.getAbiHelper();
-        final UserManagerInternal userManager = injector.getUserManager();
+        final UserManagerInternal userManager = injector.getUserManagerInternal();
         final PackageParser.Package pkg = request.pkg;
         PackageSetting pkgSetting = request.pkgSetting;
         final PackageSetting disabledPkgSetting = request.disabledPkgSetting;
@@ -12385,10 +12442,10 @@
      * automatically without needing an explicit launch.
      * Send it a LOCKED_BOOT_COMPLETED/BOOT_COMPLETED if it would ordinarily have gotten ones.
      */
-    private void sendBootCompletedBroadcastToSystemApp(String packageName, boolean includeStopped,
-            int userId) {
+    private void sendBootCompletedBroadcastToSystemApp(
+            String packageName, boolean includeStopped, int userId) {
         // If user is not running, the app didn't miss any broadcast
-        if (!mInjector.getUserManager().isUserRunning(userId)) {
+        if (!mUserManager.isUserRunning(userId)) {
             return;
         }
         final IActivityManager am = ActivityManager.getService();
@@ -12404,7 +12461,7 @@
                     android.app.AppOpsManager.OP_NONE, null, false, false, userId);
 
             // Deliver BOOT_COMPLETED only if user is unlocked
-            if (mInjector.getUserManager().isUserUnlockingOrUnlocked(userId)) {
+            if (mUserManager.isUserUnlockingOrUnlocked(userId)) {
                 Intent bcIntent = new Intent(Intent.ACTION_BOOT_COMPLETED).setPackage(packageName);
                 if (includeStopped) {
                     bcIntent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
@@ -12682,7 +12739,7 @@
                     // only allow the existing package to be used if it's installed as a full
                     // application for at least one user
                     boolean installAllowed = false;
-                    for (int checkUserId : sUserManager.getUserIds()) {
+                    for (int checkUserId : mUserManager.getUserIds()) {
                         installAllowed = !pkgSetting.getInstantApp(checkUserId);
                         if (installAllowed) {
                             break;
@@ -12764,7 +12821,7 @@
                 pkgSetting.setInstantApp(false /*instantApp*/, userId);
             }
         } else {
-            for (int currentUserId : injector.getUserManager().getUserIds()) {
+            for (int currentUserId : injector.getUserManagerInternal().getUserIds()) {
                 if (instantApp && !pkgSetting.getInstantApp(currentUserId)) {
                     pkgSetting.setInstantApp(true /*instantApp*/, currentUserId);
                 } else if (fullApp && pkgSetting.getInstantApp(currentUserId)) {
@@ -12775,7 +12832,7 @@
     }
 
     boolean isUserRestricted(int userId, String restrictionKey) {
-        Bundle restrictions = sUserManager.getUserRestrictions(userId);
+        Bundle restrictions = mUserManager.getUserRestrictions(userId);
         if (restrictions.getBoolean(restrictionKey, false)) {
             Log.w(TAG, "User is restricted: " + restrictionKey);
             return true;
@@ -13013,7 +13070,7 @@
      * @param affectedUser The user for which the changes are taking place.
      */
     void unsuspendForSuspendingPackage(final String packageName, int affectedUser) {
-        final int[] userIds = (affectedUser == UserHandle.USER_ALL) ? sUserManager.getUserIds()
+        final int[] userIds = (affectedUser == UserHandle.USER_ALL) ? mUserManager.getUserIds()
                 : new int[] {affectedUser};
         for (int userId : userIds) {
             unsuspendForSuspendingPackages(packageName::equals, userId);
@@ -13369,7 +13426,7 @@
      * @return default verification response code
      */
     private int getDefaultVerificationResponse(UserHandle user) {
-        if (sUserManager.hasUserRestriction(UserManager.ENSURE_VERIFY_APPS, user.getIdentifier())) {
+        if (mUserManager.hasUserRestriction(UserManager.ENSURE_VERIFY_APPS, user.getIdentifier())) {
             return PackageManager.VERIFICATION_REJECT;
         }
         return android.provider.Settings.Global.getInt(mContext.getContentResolver(),
@@ -13415,7 +13472,7 @@
                         && mInstantAppInstallerActivity.packageName.equals(
                                 mRequiredVerifierPackage)) {
                     try {
-                        mContext.getSystemService(AppOpsManager.class)
+                        mInjector.getAppOpsManager()
                                 .checkPackage(installerUid, mRequiredVerifierPackage);
                         if (DEBUG_VERIFY) {
                             Slog.i(TAG, "disable verification for instant app");
@@ -13636,7 +13693,7 @@
         if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
             throw new SecurityException("Instant applications don't have access to this method");
         }
-        mContext.getSystemService(AppOpsManager.class).checkPackage(Binder.getCallingUid(),
+        mInjector.getAppOpsManager().checkPackage(Binder.getCallingUid(),
                 callerPackageName);
         synchronized (mLock) {
             PackageSetting ps = mSettings.mPackages.get(packageName);
@@ -13781,7 +13838,7 @@
 
             final String packageName = res.pkg.applicationInfo.packageName;
             final String seInfo = res.pkg.applicationInfo.seInfo;
-            final int[] allUsers = sUserManager.getUserIds();
+            final int[] allUsers = mUserManager.getUserIds();
             final int[] installedUsers;
 
             final PackageSetting ps;
@@ -14454,7 +14511,8 @@
                     final List<ComponentName> sufficientVerifiers = matchVerifiers(pkgLite,
                             receivers, verificationState);
 
-                    DeviceIdleController.LocalService idleController = getDeviceIdleController();
+                    DeviceIdleController.LocalService idleController =
+                            mInjector.getLocalDeviceIdleController();
                     final long idleDuration = getVerificationTimeout();
 
                     /*
@@ -14526,7 +14584,7 @@
                     synchronized (mLock) {
                         PackageSetting ps = mSettings.getPackageLPr(pkgLite.packageName);
                         if (ps != null) {
-                            installedUsers = ps.queryInstalledUsers(sUserManager.getUserIds(),
+                            installedUsers = ps.queryInstalledUsers(mUserManager.getUserIds(),
                                     true);
                         } else {
                             installedUsers = new int[0];
@@ -15046,7 +15104,7 @@
             final File codeFile = new File(Environment.getDataAppDirectory(volumeUuid),
                     move.dataAppName);
             Slog.d(TAG, "Cleaning up " + move.packageName + " on " + volumeUuid);
-            final int[] userIds = sUserManager.getUserIds();
+            final int[] userIds = mUserManager.getUserIds();
             synchronized (mInstallLock) {
                 // Clean up both app data and code
                 // All package moves are frozen until finished
@@ -15327,7 +15385,7 @@
 
                 // Set install reason for users that are having the package newly installed.
                 if (userId == UserHandle.USER_ALL) {
-                    for (int currentUserId : sUserManager.getUserIds()) {
+                    for (int currentUserId : mUserManager.getUserIds()) {
                         if (!previousUserIds.contains(currentUserId)) {
                             ps.setInstallReason(installReason, currentUserId);
                         }
@@ -15960,7 +16018,7 @@
 
             final PackageSetting ps = mSettings.mPackages.get(packageName);
             if (ps != null) {
-                res.newUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true);
+                res.newUsers = ps.queryInstalledUsers(mUserManager.getUserIds(), true);
                 ps.setUpdateAvailable(false /*updateAvailable*/);
             }
             final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
@@ -15971,7 +16029,7 @@
                 PackageSetting childPs = mSettings.getPackageLPr(childPkg.packageName);
                 if (childPs != null) {
                     childRes.newUsers = childPs.queryInstalledUsers(
-                            sUserManager.getUserIds(), true);
+                            mUserManager.getUserIds(), true);
                 }
             }
             if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
@@ -16091,7 +16149,7 @@
                 try {
                     Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "commitPackages");
                     commitRequest = new CommitRequest(reconciledPackages,
-                            sUserManager.getUserIds());
+                            mUserManager.getUserIds());
                     commitPackagesLocked(commitRequest);
                     success = true;
                 } finally {
@@ -16387,7 +16445,7 @@
                     PackageSetting childPs = mSettings.getPackageLPr(childPkg.packageName);
                     if (childPs != null) {
                         childRes.origUsers = childPs.queryInstalledUsers(
-                                sUserManager.getUserIds(), true);
+                                mUserManager.getUserIds(), true);
                     }
                     if ((mPackages.containsKey(childPkg.packageName))) {
                         childRes.removedInfo = new PackageRemovedInfo(this);
@@ -16552,7 +16610,7 @@
                     systemApp = (ps.pkg.applicationInfo.flags &
                             ApplicationInfo.FLAG_SYSTEM) != 0;
                 }
-                res.origUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true);
+                res.origUsers = ps.queryInstalledUsers(mUserManager.getUserIds(), true);
             }
 
 
@@ -16811,7 +16869,7 @@
                     }
 
                     // In case of rollback, remember per-user/profile install state
-                    allUsers = sUserManager.getUserIds();
+                    allUsers = mUserManager.getUserIds();
                     installedUsers = ps.queryInstalledUsers(allUsers, true);
 
 
@@ -17322,7 +17380,7 @@
             return;
         }
         final boolean deleteAllUsers = (deleteFlags & PackageManager.DELETE_ALL_USERS) != 0;
-        final int[] users = deleteAllUsers ? sUserManager.getUserIds() : new int[]{userId};
+        final int[] users = deleteAllUsers ? mUserManager.getUserIds() : new int[]{userId};
         if (UserHandle.getUserId(uid) != userId || (deleteAllUsers && users.length > 1)) {
             mContext.enforceCallingOrSelfPermission(
                     android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
@@ -17572,7 +17630,7 @@
                 // Does it contain a device admin for any user?
                 int[] users;
                 if (userId == UserHandle.USER_ALL) {
-                    users = sUserManager.getUserIds();
+                    users = mUserManager.getUserIds();
                 } else {
                     users = new int[]{userId};
                 }
@@ -17649,7 +17707,7 @@
             // allow removing a package if it provides a lib others depend on.
             pkg = mPackages.get(packageName);
 
-            allUsers = sUserManager.getUserIds();
+            allUsers = mUserManager.getUserIds();
 
             if (pkg != null && pkg.staticSharedLibName != null) {
                 SharedLibraryInfo libraryInfo = getSharedLibraryInfoLPr(pkg.staticSharedLibName,
@@ -17899,7 +17957,7 @@
             outInfo.isStaticSharedLib = deletedPkg != null
                     && deletedPkg.staticSharedLibName != null;
             outInfo.populateUsers(deletedPs == null ? null
-                    : deletedPs.queryInstalledUsers(sUserManager.getUserIds(), true), deletedPs);
+                    : deletedPs.queryInstalledUsers(mUserManager.getUserIds(), true), deletedPs);
         }
 
         removePackageLI(deletedPs.name, (flags & PackageManager.DELETE_CHATTY) != 0);
@@ -17998,7 +18056,8 @@
         if (removedAppId != -1) {
             // A user ID was deleted here. Go through all users and remove it
             // from KeyStore.
-            removeKeystoreDataIfNeeded(UserHandle.USER_ALL, removedAppId);
+            removeKeystoreDataIfNeeded(
+                    mInjector.getUserManagerInternal(), UserHandle.USER_ALL, removedAppId);
         }
     }
 
@@ -18505,7 +18564,7 @@
                 if (!systemApp) {
                     // Do not uninstall the APK if an app should be cached
                     boolean keepUninstalledPackage = shouldKeepUninstalledPackageLPr(packageName);
-                    if (ps.isAnyInstalled(sUserManager.getUserIds()) || keepUninstalledPackage) {
+                    if (ps.isAnyInstalled(mUserManager.getUserIds()) || keepUninstalledPackage) {
                         // Other users still have this package installed, so all
                         // we need to do is clear this user's data and save that
                         // it is uninstalled.
@@ -18619,7 +18678,7 @@
     @GuardedBy("mLock")
     private void markPackageUninstalledForUserLPw(PackageSetting ps, UserHandle user) {
         final int[] userIds = (user == null || user.getIdentifier() == UserHandle.USER_ALL)
-                ? sUserManager.getUserIds() : new int[] {user.getIdentifier()};
+                ? mUserManager.getUserIds() : new int[] {user.getIdentifier()};
         for (int nextUserId : userIds) {
             if (DEBUG_REMOVE) {
                 Slog.d(TAG, "Marking package:" + ps.name + " uninstalled for user:" + nextUserId);
@@ -18656,7 +18715,7 @@
 
         destroyAppProfilesLIF(pkg);
 
-        final int[] userIds = (userId == UserHandle.USER_ALL) ? sUserManager.getUserIds()
+        final int[] userIds = (userId == UserHandle.USER_ALL) ? mUserManager.getUserIds()
                 : new int[] {userId};
         for (int nextUserId : userIds) {
             if (DEBUG_REMOVE) {
@@ -18667,7 +18726,7 @@
             destroyAppDataLIF(pkg, nextUserId,
                     FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL);
             clearDefaultBrowserIfNeededForUser(ps.name, nextUserId);
-            removeKeystoreDataIfNeeded(nextUserId, ps.appId);
+            removeKeystoreDataIfNeeded(mInjector.getUserManagerInternal(), nextUserId, ps.appId);
             final SparseBooleanArray changedUsers = new SparseBooleanArray();
             clearPackagePreferredActivitiesLPw(ps.name, changedUsers, nextUserId);
             if (changedUsers.size() > 0) {
@@ -18800,9 +18859,9 @@
                 FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL);
 
         final int appId = UserHandle.getAppId(pkg.applicationInfo.uid);
-        removeKeystoreDataIfNeeded(userId, appId);
+        removeKeystoreDataIfNeeded(mInjector.getUserManagerInternal(), userId, appId);
 
-        UserManagerInternal umInternal = mInjector.getUserManager();
+        UserManagerInternal umInternal = mInjector.getUserManagerInternal();
         final int flags;
         if (umInternal.isUserUnlockingOrUnlocked(userId)) {
             flags = StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE;
@@ -18817,14 +18876,14 @@
     }
 
     private void resetNetworkPolicies(int userId) {
-        LocalServices.getService(NetworkPolicyManagerInternal.class).resetUserState(userId);
+        mInjector.getNetworkPolicyManagerInternal().resetUserState(userId);
     }
 
     /**
      * Remove entries from the keystore daemon. Will only remove it if the
      * {@code appId} is valid.
      */
-    private static void removeKeystoreDataIfNeeded(int userId, int appId) {
+    private static void removeKeystoreDataIfNeeded(UserManagerInternal um, int userId, int appId) {
         if (appId < 0) {
             return;
         }
@@ -18832,7 +18891,7 @@
         final KeyStore keyStore = KeyStore.getInstance();
         if (keyStore != null) {
             if (userId == UserHandle.USER_ALL) {
-                for (final int individual : sUserManager.getUserIds()) {
+                for (final int individual : um.getUserIds()) {
                     keyStore.clearUid(UserHandle.getUid(individual, appId));
                 }
             } else {
@@ -19233,8 +19292,8 @@
     void clearIntentFilterVerificationsLPw(String packageName, int userId) {
         if (userId == UserHandle.USER_ALL) {
             if (mSettings.removeIntentFilterVerificationLPw(packageName,
-                    sUserManager.getUserIds())) {
-                for (int oneUserId : sUserManager.getUserIds()) {
+                    mUserManager.getUserIds())) {
+                for (int oneUserId : mUserManager.getUserIds()) {
                     scheduleWritePackageRestrictionsLocked(oneUserId);
                 }
             }
@@ -19247,7 +19306,7 @@
 
     /** Clears state for all users, and touches intent filter verification policy */
     void clearDefaultBrowserIfNeeded(String packageName) {
-        for (int oneUserId : sUserManager.getUserIds()) {
+        for (int oneUserId : mUserManager.getUserIds()) {
             clearDefaultBrowserIfNeededForUser(packageName, oneUserId);
         }
     }
@@ -19614,7 +19673,7 @@
                         android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
         int callingUid = Binder.getCallingUid();
         enforceOwnerRights(ownerPackage, callingUid);
-        PackageManagerServiceUtils.enforceShellRestriction(
+        PackageManagerServiceUtils.enforceShellRestriction(mInjector.getUserManagerInternal(),
                 UserManager.DISALLOW_DEBUGGING_FEATURES, callingUid, sourceUserId);
         if (intentFilter.countActions() == 0) {
             Slog.w(TAG, "Cannot set a crossProfile intent filter with no filter actions");
@@ -19646,7 +19705,7 @@
                         android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
         final int callingUid = Binder.getCallingUid();
         enforceOwnerRights(ownerPackage, callingUid);
-        PackageManagerServiceUtils.enforceShellRestriction(
+        PackageManagerServiceUtils.enforceShellRestriction(mInjector.getUserManagerInternal(),
                 UserManager.DISALLOW_DEBUGGING_FEATURES, callingUid, sourceUserId);
         synchronized (mLock) {
             CrossProfileIntentResolver resolver =
@@ -19995,7 +20054,7 @@
     @Override
     public void setApplicationEnabledSetting(String appPackageName,
             int newState, int flags, int userId, String callingPackage) {
-        if (!sUserManager.exists(userId)) return;
+        if (!mUserManager.exists(userId)) return;
         if (callingPackage == null) {
             callingPackage = Integer.toString(Binder.getCallingUid());
         }
@@ -20016,7 +20075,7 @@
     @Override
     public void setComponentEnabledSetting(ComponentName componentName,
             int newState, int flags, int userId) {
-        if (!sUserManager.exists(userId)) return;
+        if (!mUserManager.exists(userId)) return;
         setEnabledSetting(componentName.getPackageName(),
                 componentName.getClassName(), newState, flags, userId, null);
     }
@@ -20243,7 +20302,7 @@
         if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
             return;
         }
-        if (!sUserManager.exists(userId)) {
+        if (!mUserManager.exists(userId)) {
             return;
         }
         mPermissionManager.enforceCrossUserPermission(Binder.getCallingUid(), userId, false /* requireFullPermission*/,
@@ -20284,7 +20343,7 @@
 
     @Override
     public void setPackageStoppedState(String packageName, boolean stopped, int userId) {
-        if (!sUserManager.exists(userId)) return;
+        if (!mUserManager.exists(userId)) return;
         final int callingUid = Binder.getCallingUid();
         if (getInstantAppPackageName(callingUid) != null) {
             return;
@@ -20334,7 +20393,7 @@
 
     @Override
     public int getApplicationEnabledSetting(String packageName, int userId) {
-        if (!sUserManager.exists(userId)) return COMPONENT_ENABLED_STATE_DISABLED;
+        if (!mUserManager.exists(userId)) return COMPONENT_ENABLED_STATE_DISABLED;
         int callingUid = Binder.getCallingUid();
         mPermissionManager.enforceCrossUserPermission(callingUid, userId,
                 false /* requireFullPermission */, false /* checkShell */, "get enabled");
@@ -20351,7 +20410,7 @@
     @Override
     public int getComponentEnabledSetting(@NonNull ComponentName component, int userId) {
         if (component == null) return COMPONENT_ENABLED_STATE_DEFAULT;
-        if (!sUserManager.exists(userId)) return COMPONENT_ENABLED_STATE_DISABLED;
+        if (!mUserManager.exists(userId)) return COMPONENT_ENABLED_STATE_DISABLED;
         int callingUid = Binder.getCallingUid();
         mPermissionManager.enforceCrossUserPermission(callingUid, userId,
                 false /*requireFullPermission*/, false /*checkShell*/, "getComponentEnabled");
@@ -20449,7 +20508,7 @@
             }
         }
 
-        sUserManager.systemReady();
+        mUserManager.systemReady();
 
         // Now that we've scanned all packages, and granted any default
         // permissions, ensure permissions are updated. Beware of dragons if you
@@ -20458,7 +20517,7 @@
             mPermissionManager.updateAllPermissions(StorageManager.UUID_PRIVATE_INTERNAL, false);
 
             final PermissionPolicyInternal permissionPolicyInternal =
-                    LocalServices.getService(PermissionPolicyInternal.class);
+                    mInjector.getPermissionPolicyInternal();
             permissionPolicyInternal.setOnInitializedCallback(userId -> {
                 // The SDK updated case is already handled when we run during the ctor.
                 synchronized (mPackages) {
@@ -20469,14 +20528,14 @@
         }
 
         // Watch for external volumes that come and go over time
-        final StorageManager storage = mContext.getSystemService(StorageManager.class);
+        final StorageManager storage = mInjector.getStorageManager();
         storage.registerListener(mStorageListener);
 
         mInstallerService.systemReady();
         mApexManager.systemReady();
         mPackageDexOptimizer.systemReady();
 
-        getStorageManagerInternal().addExternalStoragePolicy(
+        mInjector.getStorageManagerInternal().addExternalStoragePolicy(
                 new StorageManagerInternal.ExternalStorageMountPolicy() {
             @Override
             public int getMountMode(int uid, String packageName) {
@@ -20499,7 +20558,7 @@
         });
 
         // Now that we're mostly running, clean up stale users and apps
-        sUserManager.reconcileUsers(StorageManager.UUID_PRIVATE_INTERNAL);
+        mUserManager.reconcileUsers(StorageManager.UUID_PRIVATE_INTERNAL);
         reconcileApps(StorageManager.UUID_PRIVATE_INTERNAL);
 
         mPermissionManager.systemReady();
@@ -20977,7 +21036,7 @@
                             pw.println(prefix + "No app verification established.");
                             pw.println();
                         }
-                        for (int userId : sUserManager.getUserIds()) {
+                        for (int userId : mUserManager.getUserIds()) {
                             pw.println("App linkages for user " + userId + ":");
                             pw.println();
                             count = 0;
@@ -21142,7 +21201,7 @@
         }
         for (String packageName : apkList) {
             setSystemAppHiddenUntilInstalled(packageName, true);
-            for (UserInfo user : sUserManager.getUsers(false)) {
+            for (UserInfo user : mUserManager.getUsers(false)) {
                 setSystemAppInstallState(packageName, false, user.id);
             }
         }
@@ -21428,10 +21487,9 @@
         }
 
         // Reconcile app data for all started/unlocked users
-        final StorageManager sm = mContext.getSystemService(StorageManager.class);
-        final UserManager um = mContext.getSystemService(UserManager.class);
-        UserManagerInternal umInternal = mInjector.getUserManager();
-        for (UserInfo user : um.getUsers()) {
+        final StorageManager sm = mInjector.getStorageManager();
+        UserManagerInternal umInternal = mInjector.getUserManagerInternal();
+        for (UserInfo user : mUserManager.getUsers(false /* includeDying */)) {
             final int flags;
             if (umInternal.isUserUnlockingOrUnlocked(user.id)) {
                 flags = StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE;
@@ -21621,7 +21679,7 @@
      * correct for all installed apps on all mounted volumes.
      */
     void reconcileAppsData(int userId, int flags, boolean migrateAppsData) {
-        final StorageManager storage = mContext.getSystemService(StorageManager.class);
+        final StorageManager storage = mInjector.getStorageManager();
         for (VolumeInfo vol : storage.getWritablePrivateVolumes()) {
             final String volumeUuid = vol.getFsUuid();
             synchronized (mInstallLock) {
@@ -21750,9 +21808,8 @@
             mSettings.writeKernelMappingLPr(ps);
         }
 
-        final UserManager um = mContext.getSystemService(UserManager.class);
-        UserManagerInternal umInternal = mInjector.getUserManager();
-        for (UserInfo user : um.getUsers()) {
+        UserManagerInternal umInternal = mInjector.getUserManagerInternal();
+        for (UserInfo user : mUserManager.getUsers(false /*excludeDying*/)) {
             final int flags;
             if (umInternal.isUserUnlockingOrUnlocked(user.id)) {
                 flags = StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE;
@@ -22083,7 +22140,7 @@
     private void movePackageInternal(final String packageName, final String volumeUuid,
             final int moveId, final int callingUid, UserHandle user)
                     throws PackageManagerException {
-        final StorageManager storage = mContext.getSystemService(StorageManager.class);
+        final StorageManager storage = mInjector.getStorageManager();
         final PackageManager pm = mContext.getPackageManager();
 
         final String currentVolumeUuid;
@@ -22152,7 +22209,7 @@
             label = String.valueOf(pm.getApplicationLabel(pkg.applicationInfo));
             targetSdkVersion = pkg.applicationInfo.targetSdkVersion;
             freezer = freezePackage(packageName, "movePackageInternal");
-            installedUserIds = ps.queryInstalledUsers(sUserManager.getUserIds(), true);
+            installedUserIds = ps.queryInstalledUsers(mUserManager.getUserIds(), true);
         }
 
         final Bundle extras = new Bundle();
@@ -22319,7 +22376,7 @@
             return;
         }
 
-        final StorageManager storage = mContext.getSystemService(StorageManager.class);
+        final StorageManager storage = mInjector.getStorageManager();
         VolumeInfo volume = storage.findVolumeByUuid(pkg.applicationInfo.storageUuid.toString());
         int packageExternalStorageType = getPackageExternalStorageType(volume, isExternal(pkg));
 
@@ -22357,7 +22414,7 @@
             }
         };
 
-        final StorageManager storage = mContext.getSystemService(StorageManager.class);
+        final StorageManager storage = mInjector.getStorageManager();
         storage.setPrimaryStorageUuid(volumeUuid, callback);
         return realMoveId;
     }
@@ -22503,7 +22560,7 @@
         final long token = Binder.clearCallingIdentity();
         try {
             final DeviceStorageMonitorInternal
-                    dsm = LocalServices.getService(DeviceStorageMonitorInternal.class);
+                    dsm = mInjector.getDeviceStorageMonitorInternal();
             if (dsm != null) {
                 return dsm.isMemoryLow();
             } else {
@@ -22533,7 +22590,7 @@
             final UserInfo userInfo;
             final long token = Binder.clearCallingIdentity();
             try {
-                userInfo = sUserManager.getUserInfo(userId);
+                userInfo = mUserManager.getUserInfo(userId);
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
@@ -22658,7 +22715,7 @@
         if (ps == null) {
             return;
         }
-        if (!ps.isAnyInstalled(sUserManager.getUserIds())) {
+        if (!ps.isAnyInstalled(mUserManager.getUserIds())) {
             // TODO Implement atomic delete if package is unused
             // It is currently possible that the package will be deleted even if it is installed
             // after this method returns.
@@ -23941,8 +23998,8 @@
                 return false;
             }
         }
-        if (sUserManager.hasUserRestriction(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, userId)
-                  || sUserManager.hasUserRestriction(
+        if (mUserManager.hasUserRestriction(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, userId)
+                  || mUserManager.hasUserRestriction(
                         UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY, userId)) {
             return false;
         }
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index 4c7db9a..ef47410 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -47,6 +47,7 @@
 import android.os.RemoteException;
 import android.os.SystemProperties;
 import android.os.UserHandle;
+import android.os.UserManagerInternal;
 import android.service.pm.PackageServiceDumpProto;
 import android.system.ErrnoException;
 import android.system.Os;
@@ -375,10 +376,12 @@
         }
     }
 
-    public static void enforceShellRestriction(String restriction, int callingUid, int userHandle) {
+    /** Enforces that if the caller is shell, it does not have the provided user restriction. */
+    public static void enforceShellRestriction(
+            UserManagerInternal userManager, String restriction, int callingUid, int userHandle) {
         if (callingUid == Process.SHELL_UID) {
             if (userHandle >= 0
-                    && PackageManagerService.sUserManager.hasUserRestriction(
+                    && userManager.hasUserRestriction(
                             restriction, userHandle)) {
                 throw new SecurityException("Shell does not have permission to access user "
                         + userHandle);
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 2f30863..a707aa8 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -1557,11 +1557,7 @@
     /** @return a specific user restriction that's in effect currently. */
     @Override
     public boolean hasUserRestriction(String restrictionKey, int userId) {
-        if (!UserRestrictionsUtils.isValidRestriction(restrictionKey)) {
-            return false;
-        }
-        Bundle restrictions = getEffectiveUserRestrictions(userId);
-        return restrictions != null && restrictions.getBoolean(restrictionKey);
+        return mLocalService.hasUserRestriction(restrictionKey, userId);
     }
 
     /** @return if any user has the given restriction. */
@@ -4128,6 +4124,15 @@
             return UserRestrictionsUtils.isSettingRestrictedForUser(mContext, setting, userId,
                     value, callingUid);
         }
+
+        @Override
+        public boolean hasUserRestriction(String restrictionKey, int userId) {
+            if (!UserRestrictionsUtils.isValidRestriction(restrictionKey)) {
+                return false;
+            }
+            Bundle restrictions = getEffectiveUserRestrictions(userId);
+            return restrictions != null && restrictions.getBoolean(restrictionKey);
+        }
     }
 
     /* Remove all the users except of the system one. */
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 210a7af..e2644ff 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -1197,7 +1197,8 @@
 
         final PackageParser.Package pkg = mPackageManagerInt.getPackage(packageName);
         if (pkg == null || pkg.mExtras == null) {
-            throw new IllegalArgumentException("Unknown package: " + packageName);
+            Log.e(TAG, "Unknown package: " + packageName);
+            return;
         }
         final BasePermission bp;
         synchronized (mLock) {
@@ -1357,7 +1358,8 @@
 
         final PackageParser.Package pkg = mPackageManagerInt.getPackage(packageName);
         if (pkg == null || pkg.mExtras == null) {
-            throw new IllegalArgumentException("Unknown package: " + packageName);
+            Log.e(TAG, "Unknown package: " + packageName);
+            return;
         }
         if (mPackageManagerInt.filterAppAccess(pkg, callingUid, userId)) {
             throw new IllegalArgumentException("Unknown package: " + packageName);
@@ -3928,7 +3930,7 @@
             throw new IllegalArgumentException("Invalid userId " + userId);
         }
         if (checkShell) {
-            PackageManagerServiceUtils.enforceShellRestriction(
+            PackageManagerServiceUtils.enforceShellRestriction(mUserManagerInt,
                     UserManager.DISALLOW_DEBUGGING_FEATURES, callingUid, userId);
         }
         if (!requirePermissionWhenSameUser && userId == UserHandle.getUserId(callingUid)) return;
diff --git a/services/core/java/com/android/server/power/AttentionDetector.java b/services/core/java/com/android/server/power/AttentionDetector.java
index 56d8396..4e9b724 100644
--- a/services/core/java/com/android/server/power/AttentionDetector.java
+++ b/services/core/java/com/android/server/power/AttentionDetector.java
@@ -161,7 +161,7 @@
 
         context.getContentResolver().registerContentObserver(Settings.System.getUriFor(
                 Settings.System.ADAPTIVE_SLEEP),
-                false, new ContentObserver(new Handler()) {
+                false, new ContentObserver(new Handler(context.getMainLooper())) {
                     @Override
                     public void onChange(boolean selfChange) {
                         updateEnabledFromSettings(context);
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index d599441..e57f436 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -2723,6 +2723,14 @@
                 return true;
             }
         }
+
+        if (mDisplayPowerRequest.policy == DisplayPowerRequest.POLICY_DOZE
+                && mDisplayPowerRequest.dozeScreenState == Display.STATE_ON) {
+            // Although we are in DOZE and would normally allow the device to suspend,
+            // the doze service has explicitly requested the display to remain in the ON
+            // state which means we should hold the display suspend blocker.
+            return true;
+        }
         if (mScreenBrightnessBoostInProgress) {
             return true;
         }
@@ -4854,7 +4862,8 @@
         }
     }
 
-    private final class LocalService extends PowerManagerInternal {
+    @VisibleForTesting
+    final class LocalService extends PowerManagerInternal {
         @Override
         public void setScreenBrightnessOverrideFromWindowManager(int screenBrightness) {
             if (screenBrightness < PowerManager.BRIGHTNESS_DEFAULT
diff --git a/services/core/java/com/android/server/role/RoleUserState.java b/services/core/java/com/android/server/role/RoleUserState.java
index 6375b48..d33c10c 100644
--- a/services/core/java/com/android/server/role/RoleUserState.java
+++ b/services/core/java/com/android/server/role/RoleUserState.java
@@ -121,8 +121,6 @@
      */
     public int getVersion() {
         synchronized (mLock) {
-            throwIfDestroyedLocked();
-
             return mVersion;
         }
     }
@@ -134,8 +132,6 @@
      */
     public void setVersion(int version) {
         synchronized (mLock) {
-            throwIfDestroyedLocked();
-
             if (mVersion == version) {
                 return;
             }
@@ -163,8 +159,6 @@
      */
     public void setPackagesHash(@Nullable String packagesHash) {
         synchronized (mLock) {
-            throwIfDestroyedLocked();
-
             if (Objects.equals(mPackagesHash, packagesHash)) {
                 return;
             }
@@ -182,8 +176,6 @@
      */
     public boolean isRoleAvailable(@NonNull String roleName) {
         synchronized (mLock) {
-            throwIfDestroyedLocked();
-
             return mRoles.containsKey(roleName);
         }
     }
@@ -198,8 +190,6 @@
     @Nullable
     public ArraySet<String> getRoleHolders(@NonNull String roleName) {
         synchronized (mLock) {
-            throwIfDestroyedLocked();
-
             ArraySet<String> packageNames = mRoles.get(roleName);
             if (packageNames == null) {
                 return null;
@@ -217,8 +207,6 @@
      */
     public boolean addRoleName(@NonNull String roleName) {
         synchronized (mLock) {
-            throwIfDestroyedLocked();
-
             if (!mRoles.containsKey(roleName)) {
                 mRoles.put(roleName, new ArraySet<>());
                 Slog.i(LOG_TAG, "Added new role: " + roleName);
@@ -237,8 +225,6 @@
      */
     public void setRoleNames(@NonNull List<String> roleNames) {
         synchronized (mLock) {
-            throwIfDestroyedLocked();
-
             boolean changed = false;
 
             for (int i = mRoles.size() - 1; i >= 0; i--) {
@@ -279,8 +265,6 @@
         boolean changed;
 
         synchronized (mLock) {
-            throwIfDestroyedLocked();
-
             ArraySet<String> roleHolders = mRoles.get(roleName);
             if (roleHolders == null) {
                 Slog.e(LOG_TAG, "Cannot add role holder for unknown role, role: " + roleName
@@ -312,8 +296,6 @@
         boolean changed;
 
         synchronized (mLock) {
-            throwIfDestroyedLocked();
-
             ArraySet<String> roleHolders = mRoles.get(roleName);
             if (roleHolders == null) {
                 Slog.e(LOG_TAG, "Cannot remove role holder for unknown role, role: " + roleName
@@ -338,14 +320,16 @@
      */
     @NonNull
     public List<String> getHeldRoles(@NonNull String packageName) {
-        ArrayList<String> result = new ArrayList<>();
-        int size = mRoles.size();
-        for (int i = 0; i < size; i++) {
-            if (mRoles.valueAt(i).contains(packageName)) {
-                result.add(mRoles.keyAt(i));
+        synchronized (mLock) {
+            List<String> roleNames = new ArrayList<>();
+            int size = mRoles.size();
+            for (int i = 0; i < size; i++) {
+                if (mRoles.valueAt(i).contains(packageName)) {
+                    roleNames.add(mRoles.keyAt(i));
+                }
             }
+            return roleNames;
         }
-        return result;
     }
 
     /**
@@ -353,7 +337,9 @@
      */
     @GuardedBy("mLock")
     private void scheduleWriteFileLocked() {
-        throwIfDestroyedLocked();
+        if (mDestroyed) {
+            return;
+        }
 
         if (!mWriteScheduled) {
             mWriteHandler.sendMessageDelayed(PooledLambda.obtainMessage(RoleUserState::writeFile,
@@ -537,8 +523,6 @@
         String packagesHash;
         ArrayMap<String, ArraySet<String>> roles;
         synchronized (mLock) {
-            throwIfDestroyedLocked();
-
             version = mVersion;
             packagesHash = mPackagesHash;
             roles = snapshotRolesLocked();
@@ -602,20 +586,15 @@
      */
     public void destroy() {
         synchronized (mLock) {
-            throwIfDestroyedLocked();
+            if (mDestroyed) {
+                throw new IllegalStateException("This RoleUserState has already been destroyed");
+            }
             mWriteHandler.removeCallbacksAndMessages(null);
             getFile(mUserId).delete();
             mDestroyed = true;
         }
     }
 
-    @GuardedBy("mLock")
-    private void throwIfDestroyedLocked() {
-        if (mDestroyed) {
-            throw new IllegalStateException("This RoleUserState has already been destroyed");
-        }
-    }
-
     @NonNull
     private static File getFile(@UserIdInt int userId) {
         return new File(Environment.getUserSystemDirectory(userId), ROLES_FILE_NAME);
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
index cfa370b..f0cf9cf 100644
--- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
+++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
@@ -388,7 +388,7 @@
 
         // Get a context for the caller to use to install the downgraded
         // version of the package.
-        Context context = null;
+        final Context context;
         try {
             context = mContext.createPackageContext(callerPackageName, 0);
         } catch (PackageManager.NameNotFoundException e) {
@@ -434,7 +434,6 @@
                 }
                 int sessionId = packageInstaller.createSession(params);
                 PackageInstaller.Session session = packageInstaller.openSession(sessionId);
-
                 File[] packageCodePaths = RollbackStore.getPackageCodePaths(
                         data, info.getPackageName());
                 if (packageCodePaths == null) {
@@ -504,8 +503,10 @@
 
                             Intent broadcast = new Intent(Intent.ACTION_ROLLBACK_COMMITTED);
 
-                            mContext.sendBroadcastAsUser(broadcast, UserHandle.SYSTEM,
-                                    Manifest.permission.MANAGE_ROLLBACKS);
+                            for (UserInfo userInfo : UserManager.get(mContext).getUsers(true)) {
+                                mContext.sendBroadcastAsUser(broadcast, userInfo.getUserHandle(),
+                                        Manifest.permission.MANAGE_ROLLBACKS);
+                            }
                         });
                     }
             );
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 20ccfa8..a3ab27e 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -1458,16 +1458,18 @@
             @Nullable IRecentsAnimationRunner recentsAnimationRunner) {
         enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "startRecentsActivity()");
         final int callingPid = Binder.getCallingPid();
+        final int callingUid = Binder.getCallingUid();
         final long origId = Binder.clearCallingIdentity();
         try {
             synchronized (mGlobalLock) {
                 final ComponentName recentsComponent = mRecentTasks.getRecentsComponent();
                 final int recentsUid = mRecentTasks.getRecentsComponentUid();
+                final WindowProcessController caller = getProcessController(callingPid, callingUid);
 
                 // Start a new recents animation
                 final RecentsAnimation anim = new RecentsAnimation(this, mStackSupervisor,
                         getActivityStartController(), mWindowManager, intent, recentsComponent,
-                        recentsUid, callingPid);
+                        recentsUid, caller);
                 if (recentsAnimationRunner == null) {
                     anim.preloadRecentsActivity();
                 } else {
@@ -4581,7 +4583,7 @@
     public void registerRemoteAnimations(IBinder token, RemoteAnimationDefinition definition) {
         mAmInternal.enforceCallingPermission(CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS,
                 "registerRemoteAnimations");
-        definition.setCallingPid(Binder.getCallingPid());
+        definition.setCallingPidUid(Binder.getCallingPid(), Binder.getCallingUid());
         synchronized (mGlobalLock) {
             final ActivityRecord r = ActivityRecord.isInStackLocked(token);
             if (r == null) {
@@ -4601,7 +4603,7 @@
             RemoteAnimationAdapter adapter) {
         mAmInternal.enforceCallingPermission(CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS,
                 "registerRemoteAnimationForNextActivityStart");
-        adapter.setCallingPid(Binder.getCallingPid());
+        adapter.setCallingPidUid(Binder.getCallingPid(), Binder.getCallingUid());
         synchronized (mGlobalLock) {
             final long origId = Binder.clearCallingIdentity();
             try {
@@ -4618,7 +4620,7 @@
             RemoteAnimationDefinition definition) {
         mAmInternal.enforceCallingPermission(CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS,
                 "registerRemoteAnimations");
-        definition.setCallingPid(Binder.getCallingPid());
+        definition.setCallingPidUid(Binder.getCallingPid(), Binder.getCallingUid());
         synchronized (mGlobalLock) {
             final ActivityDisplay display = mRootActivityContainer.getActivityDisplay(displayId);
             if (display == null) {
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 4f4da4c..c8e806e 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -67,6 +67,7 @@
 import static android.view.WindowManager.LayoutParams.TYPE_DREAM;
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
+import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
 import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG;
 import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
@@ -136,6 +137,8 @@
 import static com.android.server.wm.WindowManagerService.WINDOW_FREEZE_TIMEOUT_DURATION;
 import static com.android.server.wm.WindowManagerService.dipToPixel;
 import static com.android.server.wm.WindowManagerService.logSurface;
+import static com.android.server.wm.WindowState.EXCLUSION_LEFT;
+import static com.android.server.wm.WindowState.EXCLUSION_RIGHT;
 import static com.android.server.wm.WindowState.RESIZE_HANDLE_WIDTH_IN_DP;
 import static com.android.server.wm.WindowStateAnimator.DRAW_PENDING;
 import static com.android.server.wm.WindowStateAnimator.READY_TO_SHOW;
@@ -328,6 +331,8 @@
     private final RemoteCallbackList<ISystemGestureExclusionListener>
             mSystemGestureExclusionListeners = new RemoteCallbackList<>();
     private final Region mSystemGestureExclusion = new Region();
+    private boolean mSystemGestureExclusionWasRestricted = false;
+    private final Region mSystemGestureExclusionUnrestricted = new Region();
     private int mSystemGestureExclusionLimit;
 
     /**
@@ -5165,16 +5170,21 @@
             return false;
         }
 
-        final Region systemGestureExclusion = calculateSystemGestureExclusion();
+        final Region systemGestureExclusion = Region.obtain();
+        mSystemGestureExclusionWasRestricted = calculateSystemGestureExclusion(
+                systemGestureExclusion, mSystemGestureExclusionUnrestricted);
         try {
             if (mSystemGestureExclusion.equals(systemGestureExclusion)) {
                 return false;
             }
             mSystemGestureExclusion.set(systemGestureExclusion);
+            final Region unrestrictedOrNull = mSystemGestureExclusionWasRestricted
+                    ? mSystemGestureExclusionUnrestricted : null;
             for (int i = mSystemGestureExclusionListeners.beginBroadcast() - 1; i >= 0; --i) {
                 try {
                     mSystemGestureExclusionListeners.getBroadcastItem(i)
-                            .onSystemGestureExclusionChanged(mDisplayId, systemGestureExclusion);
+                            .onSystemGestureExclusionChanged(mDisplayId, systemGestureExclusion,
+                                    unrestrictedOrNull);
                 } catch (RemoteException e) {
                     Slog.e(TAG, "Failed to notify SystemGestureExclusionListener", e);
                 }
@@ -5186,8 +5196,22 @@
         }
     }
 
+    /**
+     * Calculates the system gesture exclusion.
+     *
+     * @param outExclusion will be set to the gesture exclusion region
+     * @param outExclusionUnrestricted will be set to the gesture exclusion region without
+     *                                 any restrictions applied.
+     * @return whether any restrictions were applied, i.e. outExclusion and outExclusionUnrestricted
+     *         differ.
+     */
     @VisibleForTesting
-    Region calculateSystemGestureExclusion() {
+    boolean calculateSystemGestureExclusion(Region outExclusion, @Nullable
+            Region outExclusionUnrestricted) {
+        outExclusion.setEmpty();
+        if (outExclusionUnrestricted != null) {
+            outExclusionUnrestricted.setEmpty();
+        }
         final Region unhandled = Region.obtain();
         unhandled.set(0, 0, mDisplayFrames.mDisplayWidth, mDisplayFrames.mDisplayHeight);
 
@@ -5196,7 +5220,6 @@
         final Rect rightEdge = mInsetsStateController.getSourceProvider(TYPE_RIGHT_GESTURES)
                 .getSource().getFrame();
 
-        final Region global = Region.obtain();
         final Region touchableRegion = Region.obtain();
         final Region local = Region.obtain();
         final int[] remainingLeftRight =
@@ -5234,28 +5257,39 @@
             if (needsGestureExclusionRestrictions(w, mLastDispatchedSystemUiVisibility)) {
 
                 // Processes the region along the left edge.
-                remainingLeftRight[0] = addToGlobalAndConsumeLimit(local, global, leftEdge,
-                        remainingLeftRight[0]);
+                remainingLeftRight[0] = addToGlobalAndConsumeLimit(local, outExclusion, leftEdge,
+                        remainingLeftRight[0], w, EXCLUSION_LEFT);
 
                 // Processes the region along the right edge.
-                remainingLeftRight[1] = addToGlobalAndConsumeLimit(local, global, rightEdge,
-                        remainingLeftRight[1]);
+                remainingLeftRight[1] = addToGlobalAndConsumeLimit(local, outExclusion, rightEdge,
+                        remainingLeftRight[1], w, EXCLUSION_RIGHT);
 
                 // Adds the middle (unrestricted area)
                 final Region middle = Region.obtain(local);
                 middle.op(leftEdge, Op.DIFFERENCE);
                 middle.op(rightEdge, Op.DIFFERENCE);
-                global.op(middle, Op.UNION);
+                outExclusion.op(middle, Op.UNION);
                 middle.recycle();
             } else {
-                global.op(local, Op.UNION);
+                boolean loggable = needsGestureExclusionRestrictions(w, 0 /* lastSysUiVis */);
+                if (loggable) {
+                    addToGlobalAndConsumeLimit(local, outExclusion, leftEdge,
+                            Integer.MAX_VALUE, w, EXCLUSION_LEFT);
+                    addToGlobalAndConsumeLimit(local, outExclusion, rightEdge,
+                            Integer.MAX_VALUE, w, EXCLUSION_RIGHT);
+                }
+                outExclusion.op(local, Op.UNION);
+            }
+            if (outExclusionUnrestricted != null) {
+                outExclusionUnrestricted.op(local, Op.UNION);
             }
             unhandled.op(touchableRegion, Op.DIFFERENCE);
         }, true /* topToBottom */);
         local.recycle();
         touchableRegion.recycle();
         unhandled.recycle();
-        return global;
+        return remainingLeftRight[0] < mSystemGestureExclusionLimit
+                || remainingLeftRight[1] < mSystemGestureExclusionLimit;
     }
 
     /**
@@ -5273,31 +5307,57 @@
     }
 
     /**
+     * @return Whether gesture exclusion area should be logged for the given window
+     */
+    static boolean logsGestureExclusionRestrictions(WindowState win) {
+        if (win.mWmService.mSystemGestureExclusionLogDebounceTimeoutMillis <= 0) {
+            return false;
+        }
+        final WindowManager.LayoutParams attrs = win.getAttrs();
+        final int type = attrs.type;
+        return type != TYPE_WALLPAPER
+                && type != TYPE_APPLICATION_STARTING
+                && type != TYPE_NAVIGATION_BAR
+                && (attrs.flags & FLAG_NOT_TOUCHABLE) == 0
+                && needsGestureExclusionRestrictions(win, 0 /* sysUiVisibility */)
+                && win.getDisplayContent().mDisplayPolicy.hasSideGestures();
+    }
+
+    /**
      * Adds a local gesture exclusion area to the global area while applying a limit per edge.
      *
      * @param local The gesture exclusion area to add.
      * @param global The destination.
      * @param edge Only processes the part in that region.
      * @param limit How much limit in pixels we have.
-     * @return How much of the limit are remaining.
+     * @param win The WindowState that is being processed
+     * @param side The side that is being processed, either {@link WindowState#EXCLUSION_LEFT} or
+     *             {@link WindowState#EXCLUSION_RIGHT}
+     * @return How much of the limit is remaining.
      */
     private static int addToGlobalAndConsumeLimit(Region local, Region global, Rect edge,
-            int limit) {
+            int limit, WindowState win, int side) {
         final Region r = Region.obtain(local);
         r.op(edge, Op.INTERSECT);
 
         final int[] remaining = {limit};
+        final int[] requestedExclusion = {0};
         forEachRectReverse(r, rect -> {
             if (remaining[0] <= 0) {
                 return;
             }
             final int height = rect.height();
+            requestedExclusion[0] += height;
             if (height > remaining[0]) {
                 rect.top = rect.bottom - remaining[0];
             }
             remaining[0] -= height;
             global.op(rect, Op.UNION);
         });
+
+        final int grantedExclusion = limit - remaining[0];
+        win.setLastExclusionHeights(side, requestedExclusion[0], grantedExclusion);
+
         r.recycle();
         return remaining[0];
     }
@@ -5312,10 +5372,13 @@
         }
 
         if (!changed) {
+            final Region unrestrictedOrNull = mSystemGestureExclusionWasRestricted
+                    ? mSystemGestureExclusionUnrestricted : null;
             // If updateSystemGestureExclusion changed the exclusion, it will already have
             // notified the listener. Otherwise, we'll do it here.
             try {
-                listener.onSystemGestureExclusionChanged(mDisplayId, mSystemGestureExclusion);
+                listener.onSystemGestureExclusionChanged(mDisplayId, mSystemGestureExclusion,
+                        unrestrictedOrNull);
             } catch (RemoteException e) {
                 Slog.e(TAG, "Failed to notify SystemGestureExclusionListener during register", e);
             }
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 1576873..e35ef25 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -480,9 +480,10 @@
 
                     @Override
                     public void onSwipeFromRight() {
-                        final Region excludedRegion;
+                        final Region excludedRegion = Region.obtain();
                         synchronized (mLock) {
-                            excludedRegion = mDisplayContent.calculateSystemGestureExclusion();
+                            mDisplayContent.calculateSystemGestureExclusion(
+                                    excludedRegion, null /* outUnrestricted */);
                         }
                         final boolean sideAllowed = mNavigationBarAlwaysShowOnSideGesture
                                 || mNavigationBarPosition == NAV_BAR_RIGHT;
@@ -490,13 +491,15 @@
                                 && !mSystemGestures.currentGestureStartedInRegion(excludedRegion)) {
                             requestTransientBars(mNavigationBar);
                         }
+                        excludedRegion.recycle();
                     }
 
                     @Override
                     public void onSwipeFromLeft() {
-                        final Region excludedRegion;
+                        final Region excludedRegion = Region.obtain();
                         synchronized (mLock) {
-                            excludedRegion = mDisplayContent.calculateSystemGestureExclusion();
+                            mDisplayContent.calculateSystemGestureExclusion(
+                                    excludedRegion, null /* outUnrestricted */);
                         }
                         final boolean sideAllowed = mNavigationBarAlwaysShowOnSideGesture
                                 || mNavigationBarPosition == NAV_BAR_LEFT;
@@ -504,6 +507,7 @@
                                 && !mSystemGestures.currentGestureStartedInRegion(excludedRegion)) {
                             requestTransientBars(mNavigationBar);
                         }
+                        excludedRegion.recycle();
                     }
 
                     @Override
@@ -676,6 +680,10 @@
         return mHasStatusBar;
     }
 
+    boolean hasSideGestures() {
+        return mHasNavigationBar && mSideGestureInset > 0;
+    }
+
     public boolean navigationBarCanMove() {
         return mNavigationBarCanMove;
     }
@@ -2830,7 +2838,11 @@
         mHandler.post(() -> {
             final int displayId = getDisplayId();
             getStatusBarManagerInternal().onDisplayReady(displayId);
-            LocalServices.getService(WallpaperManagerInternal.class).onDisplayReady(displayId);
+            final WallpaperManagerInternal wpMgr = LocalServices
+                    .getService(WallpaperManagerInternal.class);
+            if (wpMgr != null) {
+                wpMgr.onDisplayReady(displayId);
+            }
         });
     }
 
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index 85ba95f..422b6e5 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -90,11 +90,24 @@
     }
 
     /**
-     * @return true if either 1) AOD is showing, or 2) Keyguard is showing, not going away, and not
-     *         being occluded on the given display, false otherwise.
+     * @return true if either Keyguard or AOD are showing, not going away, and not being occluded
+     *         on the given display, false otherwise.
      */
     boolean isKeyguardOrAodShowing(int displayId) {
-        return mAodShowing || isKeyguardShowing(displayId);
+        return (mKeyguardShowing || mAodShowing) && !mKeyguardGoingAway
+                && !isDisplayOccluded(displayId);
+    }
+
+    /**
+     * @return {@code true} for default display when AOD is showing. Otherwise, same as
+     *         {@link #isKeyguardOrAodShowing(int)}
+     * TODO(b/125198167): Replace isKeyguardOrAodShowing() by this logic.
+     */
+    boolean isKeyguardUnoccludedOrAodShowing(int displayId) {
+        if (displayId == DEFAULT_DISPLAY && mAodShowing) {
+            return true;
+        }
+        return isKeyguardOrAodShowing(displayId);
     }
 
     /**
@@ -102,7 +115,7 @@
      *         display, false otherwise
      */
     boolean isKeyguardShowing(int displayId) {
-        return mKeyguardShowing && !mKeyguardGoingAway && !isKeyguardOccluded(displayId);
+        return mKeyguardShowing && !mKeyguardGoingAway && !isDisplayOccluded(displayId);
     }
 
     /**
@@ -315,7 +328,7 @@
             return;
         }
 
-        mWindowManager.onKeyguardOccludedChanged(isKeyguardOccluded(DEFAULT_DISPLAY));
+        mWindowManager.onKeyguardOccludedChanged(isDisplayOccluded(DEFAULT_DISPLAY));
         if (isKeyguardLocked()) {
             mWindowManager.deferSurfaceLayout();
             try {
@@ -360,7 +373,7 @@
         }
     }
 
-    private boolean isKeyguardOccluded(int displayId) {
+    private boolean isDisplayOccluded(int displayId) {
         return getDisplay(displayId).mOccluded;
     }
 
@@ -378,13 +391,13 @@
         if (mBeforeUnoccludeTransit != TRANSIT_UNSET
                 && dc.mAppTransition.getAppTransition() == TRANSIT_KEYGUARD_UNOCCLUDE
                 // TODO(b/113840485): Handle app transition for individual display.
-                && isKeyguardOccluded(DEFAULT_DISPLAY)) {
+                && isDisplayOccluded(DEFAULT_DISPLAY)) {
 
             // Reuse old transit in case we are occluding Keyguard again, meaning that we never
             // actually occclude/unocclude Keyguard, but just run a normal transition.
             return mBeforeUnoccludeTransit;
             // TODO(b/113840485): Handle app transition for individual display.
-        } else if (!isKeyguardOccluded(DEFAULT_DISPLAY)) {
+        } else if (!isDisplayOccluded(DEFAULT_DISPLAY)) {
 
             // Save transit in case we dismiss/occlude Keyguard shortly after.
             mBeforeUnoccludeTransit = dc.mAppTransition.getAppTransition();
@@ -396,7 +409,7 @@
 
     private void dismissDockedStackIfNeeded() {
         // TODO(b/113840485): Handle docked stack for individual display.
-        if (mKeyguardShowing && isKeyguardOccluded(DEFAULT_DISPLAY)) {
+        if (mKeyguardShowing && isDisplayOccluded(DEFAULT_DISPLAY)) {
             // The lock screen is currently showing, but is occluded by a window that can
             // show on top of the lock screen. In this can we want to dismiss the docked
             // stack since it will be complicated/risky to try to put the activity on top
@@ -421,9 +434,9 @@
 
     private void updateKeyguardSleepToken(int displayId) {
         final KeyguardDisplayState state = getDisplay(displayId);
-        if (isKeyguardOrAodShowing(displayId) && state.mSleepToken == null) {
+        if (isKeyguardUnoccludedOrAodShowing(displayId) && state.mSleepToken == null) {
             state.acquiredSleepToken();
-        } else if (!isKeyguardOrAodShowing(displayId) && state.mSleepToken != null) {
+        } else if (!isKeyguardUnoccludedOrAodShowing(displayId) && state.mSleepToken != null) {
             state.releaseSleepToken();
         }
     }
diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java
index 541a8bb..fb6b5da 100644
--- a/services/core/java/com/android/server/wm/RecentTasks.java
+++ b/services/core/java/com/android/server/wm/RecentTasks.java
@@ -126,6 +126,7 @@
     // iterating through the recents list
     private static final ActivityInfo NO_ACTIVITY_INFO_TOKEN = new ActivityInfo();
     private static final ApplicationInfo NO_APPLICATION_INFO_TOKEN = new ApplicationInfo();
+    private TaskChangeNotificationController mTaskNotificationController;
 
     /**
      * Callbacks made when manipulating the list.
@@ -228,6 +229,7 @@
         mTaskPersister = taskPersister;
         mGlobalMaxNumTasks = ActivityTaskManager.getMaxRecentTasksStatic();
         mHasVisibleRecentTasks = true;
+        mTaskNotificationController = service.getTaskChangeNotificationController();
     }
 
     RecentTasks(ActivityTaskManagerService service, ActivityStackSupervisor stackSupervisor) {
@@ -238,6 +240,7 @@
         mTaskPersister = new TaskPersister(systemDir, stackSupervisor, service, this,
                 stackSupervisor.mPersisterQueue);
         mGlobalMaxNumTasks = ActivityTaskManager.getMaxRecentTasksStatic();
+        mTaskNotificationController = service.getTaskChangeNotificationController();
         mHasVisibleRecentTasks = res.getBoolean(com.android.internal.R.bool.config_hasRecents);
         loadParametersFromResources(res);
     }
@@ -298,7 +301,7 @@
         // Resume trimming tasks
         trimInactiveRecentTasks();
 
-        mService.getTaskChangeNotificationController().notifyTaskStackChanged();
+        mTaskNotificationController.notifyTaskStackChanged();
     }
 
     /**
@@ -427,12 +430,14 @@
         for (int i = 0; i < mCallbacks.size(); i++) {
             mCallbacks.get(i).onRecentTaskAdded(task);
         }
+        mTaskNotificationController.notifyTaskListUpdated();
     }
 
     private void notifyTaskRemoved(TaskRecord task, boolean wasTrimmed, boolean killProcess) {
         for (int i = 0; i < mCallbacks.size(); i++) {
             mCallbacks.get(i).onRecentTaskRemoved(task, wasTrimmed, killProcess);
         }
+        mTaskNotificationController.notifyTaskListUpdated();
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java
index 0a3e7a4..036bef7 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimation.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimation.java
@@ -33,6 +33,7 @@
 import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_TOP;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_RECENTS_ANIMATIONS;
 
+import android.annotation.Nullable;
 import android.app.ActivityOptions;
 import android.content.ComponentName;
 import android.content.Intent;
@@ -60,7 +61,7 @@
     private final Intent mTargetIntent;
     private final ComponentName mRecentsComponent;
     private final int mRecentsUid;
-    private final int mCallingPid;
+    private final @Nullable WindowProcessController mCaller;
     private final int mUserId;
     private final int mTargetActivityType;
 
@@ -76,7 +77,8 @@
 
     RecentsAnimation(ActivityTaskManagerService atm, ActivityStackSupervisor stackSupervisor,
             ActivityStartController activityStartController, WindowManagerService wm,
-            Intent targetIntent, ComponentName recentsComponent, int recentsUid, int callingPid) {
+            Intent targetIntent, ComponentName recentsComponent, int recentsUid,
+            @Nullable WindowProcessController caller) {
         mService = atm;
         mStackSupervisor = stackSupervisor;
         mDefaultDisplay = mService.mRootActivityContainer.getDefaultDisplay();
@@ -85,7 +87,7 @@
         mTargetIntent = targetIntent;
         mRecentsComponent = recentsComponent;
         mRecentsUid = recentsUid;
-        mCallingPid = callingPid;
+        mCaller = caller;
         mUserId = atm.getCurrentUserId();
         mTargetActivityType = targetIntent.getComponent() != null
                 && recentsComponent.equals(targetIntent.getComponent())
@@ -190,7 +192,9 @@
 
         mStackSupervisor.getActivityMetricsLogger().notifyActivityLaunching(mTargetIntent);
 
-        mService.mH.post(() -> mService.mAmInternal.setRunningRemoteAnimation(mCallingPid, true));
+        if (mCaller != null) {
+            mCaller.setRunningRecentsAnimation(true);
+        }
 
         mWindowManager.deferSurfaceLayout();
         try {
@@ -286,8 +290,9 @@
                 mService.stopAppSwitches();
             }
 
-            mService.mH.post(
-                    () -> mService.mAmInternal.setRunningRemoteAnimation(mCallingPid, false));
+            if (mCaller != null) {
+                mCaller.setRunningRecentsAnimation(false);
+            }
 
             mWindowManager.inSurfaceTransaction(() -> {
                 Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER,
@@ -453,7 +458,7 @@
     /**
      * Called only when the animation should be canceled prior to starting.
      */
-    private void notifyAnimationCancelBeforeStart(IRecentsAnimationRunner recentsAnimationRunner) {
+    static void notifyAnimationCancelBeforeStart(IRecentsAnimationRunner recentsAnimationRunner) {
         try {
             recentsAnimationRunner.onAnimationCanceled(false /* deferredWithScreenshot */);
         } catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/wm/RemoteAnimationController.java b/services/core/java/com/android/server/wm/RemoteAnimationController.java
index b4bfedd..a1bc406 100644
--- a/services/core/java/com/android/server/wm/RemoteAnimationController.java
+++ b/services/core/java/com/android/server/wm/RemoteAnimationController.java
@@ -129,7 +129,7 @@
                 writeStartDebugStatement();
             }
         });
-        sendRunningRemoteAnimation(true);
+        setRunningRemoteAnimation(true);
     }
 
     void cancelAnimation(String reason) {
@@ -216,7 +216,7 @@
                 mService.closeSurfaceTransaction("RemoteAnimationController#finished");
             }
         }
-        sendRunningRemoteAnimation(false);
+        setRunningRemoteAnimation(false);
         if (DEBUG_REMOTE_ANIMATIONS) Slog.i(TAG, "Finishing remote animation");
     }
 
@@ -235,12 +235,18 @@
         }
     }
 
-    private void sendRunningRemoteAnimation(boolean running) {
+    private void setRunningRemoteAnimation(boolean running) {
         final int pid = mRemoteAnimationAdapter.getCallingPid();
+        final int uid = mRemoteAnimationAdapter.getCallingUid();
         if (pid == 0) {
             throw new RuntimeException("Calling pid of remote animation was null");
         }
-        mService.sendSetRunningRemoteAnimation(pid, running);
+        final WindowProcessController wpc = mService.mAtmService.getProcessController(pid, uid);
+        if (wpc == null) {
+            Slog.w(TAG, "Unable to find process with pid=" + pid + " uid=" + uid);
+            return;
+        }
+        wpc.setRunningRemoteAnimation(running);
     }
 
     private void linkToDeathOfRunner() throws RemoteException {
@@ -417,7 +423,7 @@
                 mHandler.removeCallbacks(mTimeoutRunnable);
                 releaseFinishedCallback();
                 invokeAnimationCancelled();
-                sendRunningRemoteAnimation(false);
+                setRunningRemoteAnimation(false);
             }
         }
 
diff --git a/services/core/java/com/android/server/wm/SafeActivityOptions.java b/services/core/java/com/android/server/wm/SafeActivityOptions.java
index ac90283..a7b5368 100644
--- a/services/core/java/com/android/server/wm/SafeActivityOptions.java
+++ b/services/core/java/com/android/server/wm/SafeActivityOptions.java
@@ -122,17 +122,20 @@
         if (mOriginalOptions != null) {
             checkPermissions(intent, aInfo, callerApp, supervisor, mOriginalOptions,
                     mOriginalCallingPid, mOriginalCallingUid);
-            setCallingPidForRemoteAnimationAdapter(mOriginalOptions, mOriginalCallingPid);
+            setCallingPidUidForRemoteAnimationAdapter(mOriginalOptions, mOriginalCallingPid,
+                    mOriginalCallingUid);
         }
         if (mCallerOptions != null) {
             checkPermissions(intent, aInfo, callerApp, supervisor, mCallerOptions,
                     mRealCallingPid, mRealCallingUid);
-            setCallingPidForRemoteAnimationAdapter(mCallerOptions, mRealCallingPid);
+            setCallingPidUidForRemoteAnimationAdapter(mCallerOptions, mRealCallingPid,
+                    mRealCallingUid);
         }
         return mergeActivityOptions(mOriginalOptions, mCallerOptions);
     }
 
-    private void setCallingPidForRemoteAnimationAdapter(ActivityOptions options, int callingPid) {
+    private void setCallingPidUidForRemoteAnimationAdapter(ActivityOptions options,
+            int callingPid, int callingUid) {
         final RemoteAnimationAdapter adapter = options.getRemoteAnimationAdapter();
         if (adapter == null) {
             return;
@@ -141,7 +144,7 @@
             Slog.wtf(TAG, "Safe activity options constructed after clearing calling id");
             return;
         }
-        adapter.setCallingPid(callingPid);
+        adapter.setCallingPidUid(callingPid, callingUid);
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/TaskChangeNotificationController.java b/services/core/java/com/android/server/wm/TaskChangeNotificationController.java
index f776062..c2c4767 100644
--- a/services/core/java/com/android/server/wm/TaskChangeNotificationController.java
+++ b/services/core/java/com/android/server/wm/TaskChangeNotificationController.java
@@ -56,6 +56,7 @@
     private static final int NOTIFY_BACK_PRESSED_ON_TASK_ROOT = 21;
     private static final int NOTIFY_SINGLE_TASK_DISPLAY_DRAWN = 22;
     private static final int NOTIFY_TASK_DISPLAY_CHANGED_LISTENERS_MSG = 23;
+    private static final int NOTIFY_TASK_LIST_UPDATED_LISTENERS_MSG = 24;
 
     // Delay in notifying task stack change listeners (in millis)
     private static final int NOTIFY_TASK_STACK_CHANGE_LISTENERS_DELAY = 100;
@@ -164,6 +165,10 @@
         l.onTaskDisplayChanged(m.arg1, m.arg2);
     };
 
+    private final TaskStackConsumer mNotifyTaskListUpdated = (l, m) -> {
+        l.onRecentTaskListUpdated();
+    };
+
     @FunctionalInterface
     public interface TaskStackConsumer {
         void accept(ITaskStackListener t, Message m) throws RemoteException;
@@ -249,6 +254,9 @@
                 case NOTIFY_TASK_DISPLAY_CHANGED_LISTENERS_MSG:
                     forAllRemoteListeners(mNotifyTaskDisplayChanged, msg);
                     break;
+                case NOTIFY_TASK_LIST_UPDATED_LISTENERS_MSG:
+                    forAllRemoteListeners(mNotifyTaskListUpdated, msg);
+                    break;
             }
         }
     }
@@ -513,4 +521,13 @@
         forAllLocalListeners(mNotifyTaskStackChanged, msg);
         msg.sendToTarget();
     }
+
+    /**
+     * Called when any additions or deletions to the recent tasks list have been made.
+     */
+    void notifyTaskListUpdated() {
+        final Message msg = mHandler.obtainMessage(NOTIFY_TASK_LIST_UPDATED_LISTENERS_MSG);
+        forAllLocalListeners(mNotifyTaskListUpdated, msg);
+        msg.sendToTarget();
+    }
 }
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 8fb23a4..3221aef 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -34,6 +34,7 @@
 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
 import static android.provider.DeviceConfig.WindowManager.KEY_SYSTEM_GESTURES_EXCLUDED_BY_PRE_Q_STICKY_IMMERSIVE;
 import static android.provider.DeviceConfig.WindowManager.KEY_SYSTEM_GESTURE_EXCLUSION_LIMIT_DP;
+import static android.provider.DeviceConfig.WindowManager.KEY_SYSTEM_GESTURE_EXCLUSION_LOG_DEBOUNCE_MILLIS;
 import static android.provider.Settings.Global.DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.Display.INVALID_DISPLAY;
@@ -848,6 +849,16 @@
     int mSystemGestureExclusionLimitDp;
     boolean mSystemGestureExcludedByPreQStickyImmersive;
 
+    /**
+     * The minimum duration between gesture exclusion logging for a given window in
+     * milliseconds.
+     *
+     * Events that happen in-between will be silently dropped.
+     *
+     * A non-positive value disables logging.
+     */
+    public long mSystemGestureExclusionLogDebounceTimeoutMillis;
+
     public interface WindowChangeListener {
         public void windowsChanged();
         public void focusChanged();
@@ -1147,6 +1158,9 @@
         mSystemGestureExclusionLimitDp = Math.max(MIN_GESTURE_EXCLUSION_LIMIT_DP,
                 DeviceConfig.getInt(DeviceConfig.NAMESPACE_WINDOW_MANAGER,
                         KEY_SYSTEM_GESTURE_EXCLUSION_LIMIT_DP, 0));
+        mSystemGestureExclusionLogDebounceTimeoutMillis =
+                DeviceConfig.getInt(DeviceConfig.NAMESPACE_WINDOW_MANAGER,
+                        KEY_SYSTEM_GESTURE_EXCLUSION_LOG_DEBOUNCE_MILLIS, 0);
         mSystemGestureExcludedByPreQStickyImmersive =
                 DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_WINDOW_MANAGER,
                         KEY_SYSTEM_GESTURES_EXCLUDED_BY_PRE_Q_STICKY_IMMERSIVE, false);
@@ -1164,6 +1178,10 @@
                             mSystemGestureExcludedByPreQStickyImmersive = excludedByPreQSticky;
                             mRoot.forAllDisplays(DisplayContent::updateSystemGestureExclusionLimit);
                         }
+
+                        mSystemGestureExclusionLogDebounceTimeoutMillis =
+                                DeviceConfig.getInt(DeviceConfig.NAMESPACE_WINDOW_MANAGER,
+                                        KEY_SYSTEM_GESTURE_EXCLUSION_LOG_DEBOUNCE_MILLIS, 0);
                     }
                 });
 
@@ -4531,7 +4549,6 @@
         public static final int SEAMLESS_ROTATION_TIMEOUT = 54;
         public static final int RESTORE_POINTER_ICON = 55;
         public static final int SET_HAS_OVERLAY_UI = 58;
-        public static final int SET_RUNNING_REMOTE_ANIMATION = 59;
         public static final int ANIMATION_FAILSAFE = 60;
         public static final int RECOMPUTE_FOCUS = 61;
         public static final int ON_POINTER_DOWN_OUTSIDE_FOCUS = 62;
@@ -4888,10 +4905,6 @@
                     mAmInternal.setHasOverlayUi(msg.arg1, msg.arg2 == 1);
                     break;
                 }
-                case SET_RUNNING_REMOTE_ANIMATION: {
-                    mAmInternal.setRunningRemoteAnimation(msg.arg1, msg.arg2 == 1);
-                    break;
-                }
                 case ANIMATION_FAILSAFE: {
                     synchronized (mGlobalLock) {
                         if (mRecentsAnimationController != null) {
@@ -7576,11 +7589,6 @@
         return mSurfaceBuilderFactory.make(s);
     }
 
-    void sendSetRunningRemoteAnimation(int pid, boolean runningRemoteAnimation) {
-        mH.obtainMessage(H.SET_RUNNING_REMOTE_ANIMATION, pid, runningRemoteAnimation ? 1 : 0)
-                .sendToTarget();
-    }
-
     void startSeamlessRotation() {
         // We are careful to reset this in case a window was removed before it finished
         // seamless rotation.
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index d7a519c..cf8e1e8 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -58,6 +58,7 @@
 import android.util.Log;
 import android.util.Slog;
 import android.util.proto.ProtoOutputStream;
+import android.view.IRemoteAnimationRunner;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.HeavyWeightSwitcherActivity;
@@ -180,6 +181,12 @@
     // Registered display id as a listener to override config change
     private int mDisplayId;
 
+    /** Whether our process is currently running a {@link RecentsAnimation} */
+    private boolean mRunningRecentsAnimation;
+
+    /** Whether our process is currently running a {@link IRemoteAnimationRunner} */
+    private boolean mRunningRemoteAnimation;
+
     public WindowProcessController(ActivityTaskManagerService atm, ApplicationInfo info,
             String name, int uid, int userId, Object owner, WindowProcessListener listener) {
         mInfo = info;
@@ -1098,6 +1105,30 @@
         }
     }
 
+    void setRunningRecentsAnimation(boolean running) {
+        if (mRunningRecentsAnimation == running) {
+            return;
+        }
+        mRunningRecentsAnimation = running;
+        updateRunningRemoteOrRecentsAnimation();
+    }
+
+    void setRunningRemoteAnimation(boolean running) {
+        if (mRunningRemoteAnimation == running) {
+            return;
+        }
+        mRunningRemoteAnimation = running;
+        updateRunningRemoteOrRecentsAnimation();
+    }
+
+    private void updateRunningRemoteOrRecentsAnimation() {
+
+        // Posting on handler so WM lock isn't held when we call into AM.
+        mAtm.mH.sendMessage(PooledLambda.obtainMessage(
+                WindowProcessListener::setRunningRemoteAnimation, mListener,
+                mRunningRecentsAnimation || mRunningRemoteAnimation));
+    }
+
     @Override
     public String toString() {
         return mOwner != null ? mOwner.toString() : null;
diff --git a/services/core/java/com/android/server/wm/WindowProcessListener.java b/services/core/java/com/android/server/wm/WindowProcessListener.java
index 527d54a..23d7a6a 100644
--- a/services/core/java/com/android/server/wm/WindowProcessListener.java
+++ b/services/core/java/com/android/server/wm/WindowProcessListener.java
@@ -17,6 +17,8 @@
 package com.android.server.wm;
 
 import android.util.proto.ProtoOutputStream;
+import android.view.IRemoteAnimationRunner;
+import android.view.RemoteAnimationAdapter;
 
 /**
  * Interface used by the owner/creator of a process that owns windows to listen to changes from the
@@ -60,4 +62,14 @@
     /** App died :(...oh well */
     void appDied();
     void writeToProto(ProtoOutputStream proto, long fieldId);
+
+    /**
+     * Sets if the process is currently running a remote animation, which is taken a signal for
+     * determining oom adjustment and scheduling behavior.
+     *
+     * @param runningRemoteAnimation True if the process is running a remote animation, false
+     *                               otherwise.
+     * @see RemoteAnimationAdapter
+     */
+    void setRunningRemoteAnimation(boolean runningRemoteAnimation);
 }
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 9f9ef24..e14514b 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -20,6 +20,8 @@
 import static android.app.AppOpsManager.MODE_ALLOWED;
 import static android.app.AppOpsManager.MODE_DEFAULT;
 import static android.app.AppOpsManager.OP_NONE;
+import static android.app.WindowConfiguration.isSplitScreenWindowingMode;
+import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
 import static android.os.PowerManager.DRAW_WAKE_LOCK;
 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
 import static android.view.SurfaceControl.Transaction;
@@ -79,6 +81,7 @@
 import static com.android.server.policy.WindowManagerPolicy.TRANSIT_EXIT;
 import static com.android.server.policy.WindowManagerPolicy.TRANSIT_PREVIEW_DONE;
 import static com.android.server.wm.AnimationSpecProto.MOVE;
+import static com.android.server.wm.DisplayContent.logsGestureExclusionRestrictions;
 import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER;
 import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_FREEFORM;
 import static com.android.server.wm.IdentifierProto.HASH_CODE;
@@ -173,6 +176,7 @@
 import android.util.DisplayMetrics;
 import android.util.MergedConfiguration;
 import android.util.Slog;
+import android.util.StatsLog;
 import android.util.TimeUtils;
 import android.util.proto.ProtoOutputStream;
 import android.view.Display;
@@ -226,6 +230,9 @@
     // to capture touch events in that area.
     static final int RESIZE_HANDLE_WIDTH_IN_DP = 30;
 
+    static final int EXCLUSION_LEFT = 0;
+    static final int EXCLUSION_RIGHT = 1;
+
     final WindowManagerPolicy mPolicy;
     final Context mContext;
     final Session mSession;
@@ -396,6 +403,13 @@
      */
     private final List<Rect> mExclusionRects = new ArrayList<>();
 
+    // 0 = left, 1 = right
+    private final int[] mLastRequestedExclusionHeight = {0, 0};
+    private final int[] mLastGrantedExclusionHeight = {0, 0};
+    private final long[] mLastExclusionLogUptimeMillis = {0, 0};
+
+    private boolean mLastShownChangedReported;
+
     // If a window showing a wallpaper: the requested offset for the
     // wallpaper; if a wallpaper window: the currently applied offset.
     float mWallpaperX = -1;
@@ -678,6 +692,20 @@
                 && mAppToken != null && mAppToken.mTargetSdk < Build.VERSION_CODES.Q;
     }
 
+    void setLastExclusionHeights(int side, int requested, int granted) {
+        boolean changed = mLastGrantedExclusionHeight[side] != granted
+                || mLastRequestedExclusionHeight[side] != requested;
+
+        if (changed) {
+            if (mLastShownChangedReported) {
+                logExclusionRestrictions(side);
+            }
+
+            mLastGrantedExclusionHeight[side] = granted;
+            mLastRequestedExclusionHeight[side] = requested;
+        }
+    }
+
     interface PowerManagerWrapper {
         void wakeUp(long time, @WakeReason int reason, String details);
 
@@ -2961,6 +2989,49 @@
         mAnimatingExit = false;
     }
 
+    void onSurfaceShownChanged(boolean shown) {
+        if (mLastShownChangedReported == shown) {
+            return;
+        }
+        mLastShownChangedReported = shown;
+
+        if (shown) {
+            initExclusionRestrictions();
+        } else {
+            logExclusionRestrictions(EXCLUSION_LEFT);
+            logExclusionRestrictions(EXCLUSION_RIGHT);
+        }
+    }
+
+    private void logExclusionRestrictions(int side) {
+        if (!logsGestureExclusionRestrictions(this)
+                || SystemClock.uptimeMillis() < mLastExclusionLogUptimeMillis[side]
+                + mWmService.mSystemGestureExclusionLogDebounceTimeoutMillis) {
+            // Drop the log if we have just logged; this is okay, because what we would have logged
+            // was true only for a short duration.
+            return;
+        }
+
+        final long now = SystemClock.uptimeMillis();
+        final long duration = now - mLastExclusionLogUptimeMillis[side];
+        mLastExclusionLogUptimeMillis[side] = now;
+
+        final int requested = mLastRequestedExclusionHeight[side];
+        final int granted = mLastGrantedExclusionHeight[side];
+
+        StatsLog.write(StatsLog.EXCLUSION_RECT_STATE_CHANGED,
+                mAttrs.packageName, requested, requested - granted /* rejected */,
+                side + 1 /* Sides are 1-indexed in atoms.proto */,
+                (getConfiguration().orientation == ORIENTATION_LANDSCAPE),
+                isSplitScreenWindowingMode(getWindowingMode()), (int) duration);
+    }
+
+    private void initExclusionRestrictions() {
+        final long now = SystemClock.uptimeMillis();
+        mLastExclusionLogUptimeMillis[EXCLUSION_LEFT] = now;
+        mLastExclusionLogUptimeMillis[EXCLUSION_RIGHT] = now;
+    }
+
     @Override
     public boolean isDefaultDisplay() {
         final DisplayContent displayContent = getDisplayContent();
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index d90e66e..ae3a10a 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -329,9 +329,14 @@
             }
             mDrawState = COMMIT_DRAW_PENDING;
             layoutNeeded = true;
-        }
-        if (postDrawTransaction != null) {
-            mPostDrawTransaction.merge(postDrawTransaction);
+
+            if (postDrawTransaction != null) {
+                mPostDrawTransaction.merge(postDrawTransaction);
+            }
+        } else if (postDrawTransaction != null) {
+            // If draw state is not pending we may delay applying this transaction from the client,
+            // so apply it now.
+            postDrawTransaction.apply();
         }
 
         return layoutNeeded;
@@ -1296,7 +1301,7 @@
         // if we are transparent.
         if (mPendingDestroySurface != null && mDestroyPreservedSurfaceUponRedraw) {
             final SurfaceControl pendingSurfaceControl = mPendingDestroySurface.mSurfaceControl;
-            mPostDrawTransaction.hide(pendingSurfaceControl);
+            mPostDrawTransaction.reparent(pendingSurfaceControl, null);
             mPostDrawTransaction.reparentChildren(pendingSurfaceControl,
                     mSurfaceController.mSurfaceControl);
         }
diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java
index a616e06..bcefa8f 100644
--- a/services/core/java/com/android/server/wm/WindowSurfaceController.java
+++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java
@@ -499,6 +499,8 @@
 
         mService.updateNonSystemOverlayWindowsVisibilityIfNeeded(mAnimator.mWin, surfaceShown);
 
+        mAnimator.mWin.onSurfaceShownChanged(surfaceShown);
+
         if (mWindowSession != null) {
             mWindowSession.onWindowSurfaceVisibilityChanged(this, mSurfaceShown, mWindowType);
         }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
index cfa9944..59996cc 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
@@ -16,6 +16,7 @@
 package com.android.server.devicepolicy;
 
 import android.app.admin.IDevicePolicyManager;
+import android.content.ComponentName;
 
 import com.android.server.SystemService;
 
@@ -56,4 +57,9 @@
 
     public void clearSystemUpdatePolicyFreezePeriodRecord() {
     }
+
+    public boolean setKeyGrantForApp(ComponentName admin, String callerPackage, String alias,
+            String packageName, boolean hasGrant) {
+        return false;
+    }
 }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index ba06369..f800cca 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -5727,6 +5727,59 @@
         return false;
     }
 
+    @Override
+    public boolean setKeyGrantForApp(
+            ComponentName who, String callerPackage, String alias, String packageName,
+            boolean hasGrant) {
+        enforceCanManageScope(who, callerPackage, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER,
+                DELEGATION_CERT_SELECTION);
+
+        if (TextUtils.isEmpty(alias)) {
+            throw new IllegalArgumentException("Alias to grant cannot be empty.");
+        }
+
+        if (TextUtils.isEmpty(packageName)) {
+            throw new IllegalArgumentException("Package to grant to cannot be empty.");
+        }
+
+        final int userId = mInjector.userHandleGetCallingUserId();
+        final int granteeUid;
+        try {
+            ApplicationInfo ai = mInjector.getIPackageManager().getApplicationInfo(
+                    packageName, 0, userId);
+            if (ai == null) {
+                throw new IllegalArgumentException(
+                        String.format("Provided package %s is not installed", packageName));
+            }
+            granteeUid = ai.uid;
+        } catch (RemoteException e) {
+            throw new IllegalStateException("Failure getting grantee uid", e);
+        }
+
+        final int callingUid = mInjector.binderGetCallingUid();
+        final long id = mInjector.binderClearCallingIdentity();
+        try {
+            final KeyChainConnection keyChainConnection =
+                    KeyChain.bindAsUser(mContext, UserHandle.getUserHandleForUid(callingUid));
+            try {
+                IKeyChainService keyChain = keyChainConnection.getService();
+                keyChain.setGrant(granteeUid, alias, hasGrant);
+                return true;
+            } catch (RemoteException e) {
+                Log.e(LOG_TAG, "Setting grant for package.", e);
+                return  false;
+            } finally {
+                keyChainConnection.close();
+            }
+        } catch (InterruptedException e) {
+            Log.w(LOG_TAG, "Interrupted while setting key grant", e);
+            Thread.currentThread().interrupt();
+        } finally {
+            mInjector.binderRestoreCallingIdentity(id);
+        }
+        return false;
+    }
+
     /**
      * Enforce one the following conditions are met:
      * (1) The device has a Device Owner, and one of the following holds:
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 6e0d834..83b3194 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -1476,6 +1476,8 @@
                 t.traceBegin("StartWallpaperManagerService");
                 mSystemServiceManager.startService(WALLPAPER_SERVICE_CLASS);
                 t.traceEnd();
+            } else {
+                Slog.i(TAG, "Wallpaper service disabled by config");
             }
 
             t.traceBegin("StartAudioService");
diff --git a/services/net/java/android/net/dhcp/DhcpServerCallbacks.java b/services/net/java/android/net/dhcp/DhcpServerCallbacks.java
index bb56876..7c413779 100644
--- a/services/net/java/android/net/dhcp/DhcpServerCallbacks.java
+++ b/services/net/java/android/net/dhcp/DhcpServerCallbacks.java
@@ -21,13 +21,11 @@
  * @hide
  */
 public abstract class DhcpServerCallbacks extends IDhcpServerCallbacks.Stub {
-    // TODO: add @Override here once the API is versioned
-
     /**
      * Get the version of the aidl interface implemented by the callbacks.
      */
+    @Override
     public int getInterfaceVersion() {
-        // TODO: return IDhcpServerCallbacks.VERSION;
-        return 0;
+        return IDhcpServerCallbacks.VERSION;
     }
 }
diff --git a/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceTest.java b/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceTest.java
index be93d6ba..0d99561 100644
--- a/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceTest.java
@@ -26,12 +26,18 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 import static org.robolectric.Shadows.shadowOf;
 import static org.testng.Assert.expectThrows;
 
+import static java.util.Collections.emptySet;
+
 import android.annotation.UserIdInt;
 import android.app.Application;
 import android.app.backup.IBackupManagerMonitor;
@@ -49,6 +55,7 @@
 import com.android.server.backup.testing.TransportData;
 import com.android.server.testing.shadows.ShadowApplicationPackageManager;
 import com.android.server.testing.shadows.ShadowBinder;
+import com.android.server.testing.shadows.ShadowSystemServiceRegistry;
 
 import org.junit.After;
 import org.junit.Before;
@@ -69,7 +76,12 @@
 
 /** Tests for the user-aware backup/restore system service {@link BackupManagerService}. */
 @RunWith(RobolectricTestRunner.class)
-@Config(shadows = {ShadowApplicationPackageManager.class, ShadowBinder.class})
+@Config(
+        shadows = {
+            ShadowApplicationPackageManager.class,
+            ShadowBinder.class,
+            ShadowSystemServiceRegistry.class
+        })
 @Presubmit
 public class BackupManagerServiceTest {
     private static final String TEST_PACKAGE = "package";
@@ -121,7 +133,7 @@
     public void testConstructor_doesNotRegisterUsers() throws Exception {
         BackupManagerService backupManagerService = createService();
 
-        assertThat(backupManagerService.getServiceUsers().size()).isEqualTo(0);
+        assertThat(backupManagerService.getUserServices().size()).isEqualTo(0);
     }
 
     /** Test that the constructor handles {@code null} parameters. */
@@ -150,9 +162,9 @@
     public void testStartServiceForUser_registersUser() throws Exception {
         BackupManagerService backupManagerService = createService();
 
-        backupManagerService.startServiceForUser(mUserOneId);
+        backupManagerService.startServiceForUser(mUserOneId, emptySet());
 
-        SparseArray<UserBackupManagerService> serviceUsers = backupManagerService.getServiceUsers();
+        SparseArray<UserBackupManagerService> serviceUsers = backupManagerService.getUserServices();
         assertThat(serviceUsers.size()).isEqualTo(1);
         assertThat(serviceUsers.get(mUserOneId)).isNotNull();
     }
@@ -164,7 +176,7 @@
 
         backupManagerService.startServiceForUser(mUserOneId, mUserOneService);
 
-        SparseArray<UserBackupManagerService> serviceUsers = backupManagerService.getServiceUsers();
+        SparseArray<UserBackupManagerService> serviceUsers = backupManagerService.getUserServices();
         assertThat(serviceUsers.size()).isEqualTo(1);
         assertThat(serviceUsers.get(mUserOneId)).isEqualTo(mUserOneService);
     }
@@ -178,7 +190,7 @@
 
         backupManagerService.stopServiceForUser(mUserOneId);
 
-        SparseArray<UserBackupManagerService> serviceUsers = backupManagerService.getServiceUsers();
+        SparseArray<UserBackupManagerService> serviceUsers = backupManagerService.getUserServices();
         assertThat(serviceUsers.size()).isEqualTo(1);
         assertThat(serviceUsers.get(mUserOneId)).isNull();
         assertThat(serviceUsers.get(mUserTwoId)).isEqualTo(mUserTwoService);
@@ -204,7 +216,7 @@
 
         backupManagerService.stopServiceForUser(mUserOneId);
 
-        SparseArray<UserBackupManagerService> serviceUsers = backupManagerService.getServiceUsers();
+        SparseArray<UserBackupManagerService> serviceUsers = backupManagerService.getUserServices();
         assertThat(serviceUsers.size()).isEqualTo(0);
     }
 
@@ -1500,6 +1512,48 @@
     }
 
     // ---------------------------------------------
+    //  Lifecycle tests
+    // ---------------------------------------------
+
+
+    /** testOnStart_publishesService */
+    @Test
+    public void testOnStart_publishesService() {
+        Trampoline trampoline = mock(Trampoline.class);
+        BackupManagerService.Lifecycle lifecycle =
+                spy(new BackupManagerService.Lifecycle(mContext, trampoline));
+        doNothing().when(lifecycle).publishService(anyString(), any());
+
+        lifecycle.onStart();
+
+        verify(lifecycle).publishService(Context.BACKUP_SERVICE, trampoline);
+    }
+
+    /** testOnUnlockUser_forwards */
+    @Test
+    public void testOnUnlockUser_forwards() {
+        Trampoline trampoline = mock(Trampoline.class);
+        BackupManagerService.Lifecycle lifecycle =
+                new BackupManagerService.Lifecycle(mContext, trampoline);
+
+        lifecycle.onUnlockUser(UserHandle.USER_SYSTEM);
+
+        verify(trampoline).onUnlockUser(UserHandle.USER_SYSTEM);
+    }
+
+    /** testOnStopUser_forwards */
+    @Test
+    public void testOnStopUser_forwards() {
+        Trampoline trampoline = mock(Trampoline.class);
+        BackupManagerService.Lifecycle lifecycle =
+                new BackupManagerService.Lifecycle(mContext, trampoline);
+
+        lifecycle.onStopUser(UserHandle.USER_SYSTEM);
+
+        verify(trampoline).onStopUser(UserHandle.USER_SYSTEM);
+    }
+
+    // ---------------------------------------------
     //  Service tests
     // ---------------------------------------------
 
diff --git a/services/robotests/backup/src/com/android/server/backup/FullBackupJobTest.java b/services/robotests/backup/src/com/android/server/backup/FullBackupJobTest.java
index 9a78d0b3..dbc0da7 100644
--- a/services/robotests/backup/src/com/android/server/backup/FullBackupJobTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/FullBackupJobTest.java
@@ -25,6 +25,8 @@
 import android.os.UserHandle;
 import android.platform.test.annotations.Presubmit;
 
+import com.android.server.testing.shadows.ShadowSystemServiceRegistry;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -36,7 +38,7 @@
 import org.robolectric.shadows.ShadowJobScheduler;
 
 @RunWith(RobolectricTestRunner.class)
-@Config(shadows = {ShadowJobScheduler.class})
+@Config(shadows = {ShadowJobScheduler.class, ShadowSystemServiceRegistry.class})
 @Presubmit
 public class FullBackupJobTest {
     private Context mContext;
diff --git a/services/robotests/backup/src/com/android/server/backup/KeyValueBackupJobTest.java b/services/robotests/backup/src/com/android/server/backup/KeyValueBackupJobTest.java
index 8d9e44f..1c5fac2 100644
--- a/services/robotests/backup/src/com/android/server/backup/KeyValueBackupJobTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/KeyValueBackupJobTest.java
@@ -24,14 +24,18 @@
 import android.os.UserHandle;
 import android.platform.test.annotations.Presubmit;
 
+import com.android.server.testing.shadows.ShadowSystemServiceRegistry;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
 
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {ShadowSystemServiceRegistry.class})
 @Presubmit
 public class KeyValueBackupJobTest {
     private Context mContext;
diff --git a/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java b/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java
index 74fe81c..84e810d 100644
--- a/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java
@@ -63,6 +63,7 @@
 import com.android.server.testing.shadows.ShadowBinder;
 import com.android.server.testing.shadows.ShadowKeyValueBackupJob;
 import com.android.server.testing.shadows.ShadowKeyValueBackupTask;
+import com.android.server.testing.shadows.ShadowSystemServiceRegistry;
 
 import org.junit.After;
 import org.junit.Before;
@@ -88,7 +89,12 @@
  * UserBackupManagerService} that performs operations for its target user.
  */
 @RunWith(RobolectricTestRunner.class)
-@Config(shadows = {ShadowAppBackupUtils.class, ShadowApplicationPackageManager.class})
+@Config(
+        shadows = {
+            ShadowAppBackupUtils.class,
+            ShadowApplicationPackageManager.class,
+            ShadowSystemServiceRegistry.class
+        })
 @Presubmit
 public class UserBackupManagerServiceTest {
     private static final String TAG = "BMSTest";
diff --git a/services/robotests/backup/src/com/android/server/backup/internal/SetupObserverTest.java b/services/robotests/backup/src/com/android/server/backup/internal/SetupObserverTest.java
index 44e9e6a..e49425b 100644
--- a/services/robotests/backup/src/com/android/server/backup/internal/SetupObserverTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/internal/SetupObserverTest.java
@@ -32,6 +32,7 @@
 import com.android.server.backup.UserBackupManagerService;
 import com.android.server.backup.testing.BackupManagerServiceTestUtils;
 import com.android.server.testing.shadows.ShadowApplicationPackageManager;
+import com.android.server.testing.shadows.ShadowSystemServiceRegistry;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -51,7 +52,12 @@
  * UserBackupManagerService}.
  */
 @RunWith(RobolectricTestRunner.class)
-@Config(shadows = {ShadowApplicationPackageManager.class, ShadowJobScheduler.class})
+@Config(
+        shadows = {
+            ShadowApplicationPackageManager.class,
+            ShadowJobScheduler.class,
+            ShadowSystemServiceRegistry.class
+        })
 @Presubmit
 public class SetupObserverTest {
     private static final String TAG = "SetupObserverTest";
diff --git a/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java b/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java
index 43691e0..6a90d0b 100644
--- a/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java
@@ -94,7 +94,6 @@
 import android.os.Looper;
 import android.os.Message;
 import android.os.ParcelFileDescriptor;
-import android.os.PowerManager;
 import android.os.RemoteException;
 import android.platform.test.annotations.Presubmit;
 import android.util.Pair;
@@ -121,6 +120,7 @@
 import com.android.server.testing.shadows.ShadowBackupDataInput;
 import com.android.server.testing.shadows.ShadowBackupDataOutput;
 import com.android.server.testing.shadows.ShadowEventLog;
+import com.android.server.testing.shadows.ShadowSystemServiceRegistry;
 
 import com.google.common.truth.IterableSubject;
 
@@ -164,10 +164,11 @@
             ShadowBackupDataInput.class,
             ShadowBackupDataOutput.class,
             ShadowEventLog.class,
-            ShadowQueuedWork.class
+            ShadowQueuedWork.class,
+            ShadowSystemServiceRegistry.class
         })
 @Presubmit
-public class KeyValueBackupTaskTest {
+public class KeyValueBackupTaskTest  {
     private static final PackageData PACKAGE_1 = keyValuePackage(1);
     private static final PackageData PACKAGE_2 = keyValuePackage(2);
     private static final String BACKUP_AGENT_SHARED_PREFS_SYNCHRONIZER_CLASS =
@@ -184,7 +185,7 @@
     private TransportData mTransport;
     private ShadowLooper mShadowBackupLooper;
     private Handler mBackupHandler;
-    private PowerManager.WakeLock mWakeLock;
+    private UserBackupManagerService.BackupWakeLock mWakeLock;
     private KeyValueBackupReporter mReporter;
     private PackageManager mPackageManager;
     private ShadowPackageManager mShadowPackageManager;
diff --git a/services/robotests/backup/src/com/android/server/backup/restore/ActiveRestoreSessionTest.java b/services/robotests/backup/src/com/android/server/backup/restore/ActiveRestoreSessionTest.java
index f4cea7a..3fc421d 100644
--- a/services/robotests/backup/src/com/android/server/backup/restore/ActiveRestoreSessionTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/restore/ActiveRestoreSessionTest.java
@@ -18,7 +18,7 @@
 
 import static com.android.server.backup.testing.BackupManagerServiceTestUtils.createBackupWakeLock;
 import static com.android.server.backup.testing.BackupManagerServiceTestUtils.setUpBackupManagerServiceBasics;
-import static com.android.server.backup.testing.BackupManagerServiceTestUtils.startBackupThreadAndGetLooper;
+import static com.android.server.backup.testing.BackupManagerServiceTestUtils.startBackupThread;
 import static com.android.server.backup.testing.TestUtils.assertEventLogged;
 import static com.android.server.backup.testing.TestUtils.assertEventNotLogged;
 import static com.android.server.backup.testing.TransportData.backupTransport;
@@ -44,8 +44,8 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.os.Handler;
+import android.os.HandlerThread;
 import android.os.Looper;
-import android.os.PowerManager;
 import android.os.RemoteException;
 import android.platform.test.annotations.Presubmit;
 
@@ -98,7 +98,7 @@
     @Mock private IBackupManagerMonitor mMonitor;
     private ShadowLooper mShadowBackupLooper;
     private ShadowApplication mShadowApplication;
-    private PowerManager.WakeLock mWakeLock;
+    private UserBackupManagerService.BackupWakeLock mWakeLock;
     private TransportData mTransport;
     private RestoreSet mRestoreSet1;
     private RestoreSet mRestoreSet2;
@@ -118,7 +118,8 @@
 
         mShadowPackageManager = shadowOf(application.getPackageManager());
 
-        Looper backupLooper = startBackupThreadAndGetLooper();
+        HandlerThread handlerThread = startBackupThread(null);
+        Looper backupLooper = handlerThread.getLooper();
         mShadowBackupLooper = shadowOf(backupLooper);
 
         Handler mainHandler = new Handler(Looper.getMainLooper());
@@ -129,7 +130,7 @@
         // We need to mock BMS timeout parameters before initializing the BackupHandler since
         // the constructor of BackupHandler relies on it.
         when(mBackupManagerService.getAgentTimeoutParameters()).thenReturn(agentTimeoutParameters);
-        BackupHandler backupHandler = new BackupHandler(mBackupManagerService, backupLooper);
+        BackupHandler backupHandler = new BackupHandler(mBackupManagerService, handlerThread);
 
         mWakeLock = createBackupWakeLock(application);
 
diff --git a/services/robotests/backup/src/com/android/server/backup/testing/BackupManagerServiceTestUtils.java b/services/robotests/backup/src/com/android/server/backup/testing/BackupManagerServiceTestUtils.java
index 47abcc5..392d182 100644
--- a/services/robotests/backup/src/com/android/server/backup/testing/BackupManagerServiceTestUtils.java
+++ b/services/robotests/backup/src/com/android/server/backup/testing/BackupManagerServiceTestUtils.java
@@ -113,7 +113,7 @@
             TransportManager transportManager,
             PackageManager packageManager,
             Handler backupHandler,
-            PowerManager.WakeLock wakeLock,
+            UserBackupManagerService.BackupWakeLock wakeLock,
             BackupAgentTimeoutParameters agentTimeoutParameters) {
 
         when(backupManagerService.getContext()).thenReturn(application);
@@ -161,10 +161,12 @@
                 });
     }
 
-    public static PowerManager.WakeLock createBackupWakeLock(Application application) {
+    public static UserBackupManagerService.BackupWakeLock createBackupWakeLock(
+            Application application) {
         PowerManager powerManager =
                 (PowerManager) application.getSystemService(Context.POWER_SERVICE);
-        return powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*backup*");
+        return new UserBackupManagerService.BackupWakeLock(
+                powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*backup*"));
     }
 
     /**
diff --git a/services/robotests/src/com/android/server/testing/shadows/ShadowSystemServiceRegistry.java b/services/robotests/src/com/android/server/testing/shadows/ShadowSystemServiceRegistry.java
new file mode 100644
index 0000000..c59798fc92
--- /dev/null
+++ b/services/robotests/src/com/android/server/testing/shadows/ShadowSystemServiceRegistry.java
@@ -0,0 +1,48 @@
+/*
+ * 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.testing.shadows;
+
+import android.app.SystemServiceRegistry;
+import android.app.job.JobSchedulerFrameworkInitializer;
+
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+import org.robolectric.util.ReflectionHelpers;
+
+/**
+ * Shadow of {@link SystemServiceRegistry}
+ *
+ * <p>JobSchedulerFrameworkInitializer contains a static initializer registering JobScheduler as a
+ * system service. We need to make sure the initializer is run before the tests that use
+ * JobScheduler. And we're putting this on the static initializer of SystemServiceRegistry since
+ * other services are registered here.
+ */
+@Implements(className = "android.app.SystemServiceRegistry")
+public class ShadowSystemServiceRegistry {
+    @Implementation
+    protected static void __staticInitializer__() {
+        // Make sure the static init in the real class is still executed.
+        ReflectionHelpers.callStaticMethod(SystemServiceRegistry.class, "__staticInitializer__");
+        try {
+            Class.forName(JobSchedulerFrameworkInitializer.class.getCanonicalName());
+        } catch (ClassNotFoundException e) {
+            // Rethrowing as an unchecked exception because checked exceptions are not allowed in
+            // static blocks.
+            throw new ExceptionInInitializerError(e);
+        }
+    }
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/AppCompactorTest.java b/services/tests/mockingservicestests/src/com/android/server/am/AppCompactorTest.java
index 4a33739..48e459f 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/AppCompactorTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/AppCompactorTest.java
@@ -21,12 +21,17 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import android.content.Context;
 import android.os.Handler;
 import android.os.HandlerThread;
+import android.os.Process;
 import android.platform.test.annotations.Presubmit;
 import android.provider.DeviceConfig;
 import android.text.TextUtils;
 
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.server.ServiceThread;
 import com.android.server.appop.AppOpsService;
 import com.android.server.testables.TestableDeviceConfig;
 
@@ -54,6 +59,8 @@
 @RunWith(MockitoJUnitRunner.class)
 public final class AppCompactorTest {
 
+    private ServiceThread mThread;
+
     @Mock
     private AppOpsService mAppOpsService;
     private AppCompactor mCompactorUnderTest;
@@ -70,7 +77,14 @@
         mHandlerThread = new HandlerThread("");
         mHandlerThread.start();
         mHandler = new Handler(mHandlerThread.getLooper());
-        ActivityManagerService ams = new ActivityManagerService(new TestInjector());
+
+        mThread = new ServiceThread("TestServiceThread", Process.THREAD_PRIORITY_DEFAULT,
+                true /* allowIo */);
+        mThread.start();
+
+        ActivityManagerService ams = new ActivityManagerService(
+                new TestInjector(InstrumentationRegistry.getInstrumentation().getContext()),
+                mThread);
         mCompactorUnderTest = new AppCompactor(ams,
                 new AppCompactor.PropertyChangedCallbackForTest() {
                     @Override
@@ -85,6 +99,7 @@
     @After
     public void tearDown() {
         mHandlerThread.quit();
+        mThread.quit();
         mCountDown = null;
     }
 
@@ -647,6 +662,11 @@
     }
 
     private class TestInjector extends Injector {
+
+        TestInjector(Context context) {
+            super(context);
+        }
+
         @Override
         public AppOpsService getAppOpsService(File file, Handler handler) {
             return mAppOpsService;
diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp
index b37e460..83e20fb 100644
--- a/services/tests/servicestests/Android.bp
+++ b/services/tests/servicestests/Android.bp
@@ -83,6 +83,8 @@
     optimize: {
         enabled: false,
     },
+
+    data: [":JobTestApp"],
 }
 
 java_library {
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityManagerInternalTest.java b/services/tests/servicestests/src/com/android/server/am/ActivityManagerInternalTest.java
index 5dafe07..d57fd4b 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityManagerInternalTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityManagerInternalTest.java
@@ -18,13 +18,17 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doReturn;
 
 import android.app.ActivityManagerInternal;
 import android.os.SystemClock;
 
 import androidx.test.filters.MediumTest;
+import androidx.test.platform.app.InstrumentationRegistry;
 
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
@@ -43,6 +47,8 @@
     private static final long TEST_PROC_STATE_SEQ2 = 1112;
     private static final long TEST_PROC_STATE_SEQ3 = 1113;
 
+    @Rule public ServiceThreadRule mServiceThreadRule = new ServiceThreadRule();
+
     @Mock private ActivityManagerService.Injector mMockInjector;
 
     private ActivityManagerService mAms;
@@ -52,7 +58,11 @@
     public void setUp() {
         MockitoAnnotations.initMocks(this);
 
-        mAms = new ActivityManagerService(mMockInjector);
+        doReturn(InstrumentationRegistry.getInstrumentation().getContext()).when(mMockInjector)
+                .getContext();
+        doReturn(mServiceThreadRule.getThread().getThreadHandler()).when(mMockInjector)
+                .getUiHandler(any());
+        mAms = new ActivityManagerService(mMockInjector, mServiceThreadRule.getThread());
         mAmi = mAms.new LocalService();
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java
index 3df6976..29244f0 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java
@@ -70,13 +70,14 @@
 import androidx.test.filters.MediumTest;
 import androidx.test.filters.SmallTest;
 
-import com.android.server.appop.AppOpsService;
 import com.android.server.am.ProcessList.IsolatedUidRange;
 import com.android.server.am.ProcessList.IsolatedUidRangeAllocator;
+import com.android.server.appop.AppOpsService;
 import com.android.server.wm.ActivityTaskManagerService;
 
 import org.junit.After;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.mockito.Mock;
 import org.mockito.Mockito;
@@ -114,6 +115,8 @@
         UidRecord.CHANGE_ACTIVE
     };
 
+    @Rule public ServiceThreadRule mServiceThreadRule = new ServiceThreadRule();
+
     private Context mContext = getInstrumentation().getTargetContext();
     @Mock private AppOpsService mAppOpsService;
     @Mock private PackageManager mPackageManager;
@@ -130,8 +133,8 @@
         mHandlerThread = new HandlerThread(TAG);
         mHandlerThread.start();
         mHandler = new TestHandler(mHandlerThread.getLooper());
-        mInjector = new TestInjector();
-        mAms = new ActivityManagerService(mInjector);
+        mInjector = new TestInjector(mContext);
+        mAms = new ActivityManagerService(mInjector, mServiceThreadRule.getThread());
         mAms.mWaitForNetworkTimeoutMs = 2000;
         mAms.mActivityTaskManager = new ActivityTaskManagerService(mContext);
         mAms.mActivityTaskManager.initialize(null, null, mHandler.getLooper());
@@ -917,9 +920,8 @@
     private class TestInjector extends Injector {
         private boolean mRestricted = true;
 
-        @Override
-        public Context getContext() {
-            return mContext;
+        TestInjector(Context context) {
+            super(context);
         }
 
         @Override
diff --git a/services/tests/servicestests/src/com/android/server/am/AppErrorDialogTest.java b/services/tests/servicestests/src/com/android/server/am/AppErrorDialogTest.java
index 1dfce51..377bfd1 100644
--- a/services/tests/servicestests/src/com/android/server/am/AppErrorDialogTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/AppErrorDialogTest.java
@@ -29,6 +29,7 @@
 import com.android.server.wm.ActivityTaskManagerService;
 
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 
 import java.io.File;
@@ -41,13 +42,16 @@
 @FlakyTest(bugId = 113616538)
 public class AppErrorDialogTest {
 
+    @Rule
+    public ServiceThreadRule mServiceThreadRule = new ServiceThreadRule();
+
     private Context mContext;
     private ActivityManagerService mService;
 
     @Before
     public void setUp() throws Exception {
         mContext = getInstrumentation().getTargetContext();
-        mService = new ActivityManagerService(new ActivityManagerService.Injector() {
+        mService = new ActivityManagerService(new ActivityManagerService.Injector(mContext) {
             @Override
             public AppOpsService getAppOpsService(File file, Handler handler) {
                 return null;
@@ -55,14 +59,14 @@
 
             @Override
             public Handler getUiHandler(ActivityManagerService service) {
-                return null;
+                return mServiceThreadRule.getThread().getThreadHandler();
             }
 
             @Override
             public boolean isNetworkRestrictedForUid(int uid) {
                 return false;
             }
-        });
+        }, mServiceThreadRule.getThread());
         mService.mActivityTaskManager = new ActivityTaskManagerService(mContext);
         mService.mActivityTaskManager.initialize(null, null, mContext.getMainLooper());
     }
diff --git a/services/tests/servicestests/src/com/android/server/am/CoreSettingsObserverTest.java b/services/tests/servicestests/src/com/android/server/am/CoreSettingsObserverTest.java
index cbdc6c3..4221575 100644
--- a/services/tests/servicestests/src/com/android/server/am/CoreSettingsObserverTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/CoreSettingsObserverTest.java
@@ -23,9 +23,11 @@
 import static com.google.common.truth.Truth.assertWithMessage;
 
 import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
 import android.content.Context;
+import android.content.res.Resources;
 import android.os.Bundle;
 import android.os.Handler;
 import android.provider.Settings;
@@ -39,6 +41,7 @@
 import org.junit.AfterClass;
 import org.junit.Before;
 import org.junit.BeforeClass;
+import org.junit.Rule;
 import org.junit.Test;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
@@ -61,6 +64,8 @@
     private static final float TEST_FLOAT = 3.14f;
     private static final String TEST_STRING = "testString";
 
+    @Rule public ServiceThreadRule mServiceThreadRule = new ServiceThreadRule();
+
     private ActivityManagerService mAms;
     @Mock private Context mContext;
 
@@ -89,8 +94,10 @@
         mContentResolver = new MockContentResolver(mContext);
         mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
         when(mContext.getContentResolver()).thenReturn(mContentResolver);
+        when(mContext.getResources()).thenReturn(mock(Resources.class));
 
-        mAms = new ActivityManagerService(new TestInjector());
+        mAms = new ActivityManagerService(new TestInjector(mContext),
+                mServiceThreadRule.getThread());
         mCoreSettingsObserver = new CoreSettingsObserver(mAms);
     }
 
@@ -155,9 +162,9 @@
     }
 
     private class TestInjector extends Injector {
-        @Override
-        public Context getContext() {
-            return mContext;
+
+        TestInjector(Context context) {
+            super(context);
         }
 
         @Override
@@ -167,7 +174,7 @@
 
         @Override
         public Handler getUiHandler(ActivityManagerService service) {
-            return null;
+            return mServiceThreadRule.getThread().getThreadHandler();
         }
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/am/ServiceThreadRule.java b/services/tests/servicestests/src/com/android/server/am/ServiceThreadRule.java
new file mode 100644
index 0000000..e86ce7e
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/am/ServiceThreadRule.java
@@ -0,0 +1,51 @@
+/*
+ * 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.am;
+
+import android.os.Process;
+
+import com.android.server.ServiceThread;
+
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+class ServiceThreadRule implements TestRule {
+
+    private ServiceThread mThread;
+
+    ServiceThread getThread() {
+        return mThread;
+    }
+
+    @Override
+    public Statement apply(Statement base, Description description) {
+        return new Statement() {
+            @Override
+            public void evaluate() throws Throwable {
+                mThread = new ServiceThread("TestServiceThread", Process.THREAD_PRIORITY_DEFAULT,
+                        true /* allowIo */);
+                mThread.start();
+                try {
+                    base.evaluate();
+                } finally {
+                    mThread.getThreadHandler().runWithScissors(mThread::quit, 0 /* timeout */);
+                }
+            }
+        };
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java b/services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java
index 29cbf98..8668a3c 100644
--- a/services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java
+++ b/services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java
@@ -18,11 +18,11 @@
 
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertFalse;
-import static junit.framework.Assert.assertNotNull;
 import static junit.framework.Assert.assertNull;
 import static junit.framework.Assert.assertTrue;
 import static junit.framework.Assert.fail;
 
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
@@ -44,6 +44,7 @@
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.content.pm.UserInfo;
+import android.os.ConditionVariable;
 import android.os.IBinder;
 import android.os.ParcelFileDescriptor;
 import android.os.Process;
@@ -70,7 +71,8 @@
 import java.io.FileDescriptor;
 import java.io.IOException;
 import java.io.PrintWriter;
-import java.util.concurrent.LinkedBlockingQueue;
+import java.util.Set;
+import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.TimeUnit;
 
 @SmallTest
@@ -136,7 +138,7 @@
         SparseArray<UserBackupManagerService> serviceUsers = new SparseArray<>();
         serviceUsers.append(UserHandle.USER_SYSTEM, mUserBackupManagerService);
         serviceUsers.append(NON_USER_SYSTEM, mUserBackupManagerService);
-        when(mBackupManagerServiceMock.getServiceUsers()).thenReturn(serviceUsers);
+        when(mBackupManagerServiceMock.getUserServices()).thenReturn(serviceUsers);
 
         when(mUserManagerMock.getUserInfo(UserHandle.USER_SYSTEM)).thenReturn(mUserInfoMock);
         when(mUserManagerMock.getUserInfo(NON_USER_SYSTEM)).thenReturn(mUserInfoMock);
@@ -182,37 +184,78 @@
     }
 
     @Test
-    public void initializeService_successfullyInitializesBackupService() {
-        mTrampoline.initializeService();
-
+    public void testIsBackupServiceActive_whenBackupsNotDisabledAndSuppressFileDoesNotExist() {
         assertTrue(mTrampoline.isBackupServiceActive(UserHandle.USER_SYSTEM));
     }
 
     @Test
-    public void initializeService_globallyDisabled_nonInitialized() {
+    public void testOnUnlockUser_forNonSystemUserWhenBackupsDisabled_doesNotStartUser() {
+        when(mBackupManagerServiceMock.getUserServices()).thenReturn(new SparseArray<>());
         TrampolineTestable.sBackupDisabled = true;
         TrampolineTestable trampoline = new TrampolineTestable(mContextMock);
+        ConditionVariable unlocked = new ConditionVariable(false);
 
-        trampoline.initializeService();
+        trampoline.onUnlockUser(NON_USER_SYSTEM);
+
+        trampoline.getBackupHandler().post(unlocked::open);
+        unlocked.block();
+        assertNull(trampoline.getUserService(NON_USER_SYSTEM));
+    }
+
+    @Test
+    public void testOnUnlockUser_forSystemUserWhenBackupsDisabled_doesNotStartUser() {
+        when(mBackupManagerServiceMock.getUserServices()).thenReturn(new SparseArray<>());
+        TrampolineTestable.sBackupDisabled = true;
+        TrampolineTestable trampoline = new TrampolineTestable(mContextMock);
+        ConditionVariable unlocked = new ConditionVariable(false);
+
+        trampoline.onUnlockUser(UserHandle.USER_SYSTEM);
+
+        trampoline.getBackupHandler().post(unlocked::open);
+        unlocked.block();
+        assertNull(trampoline.getUserService(UserHandle.USER_SYSTEM));
+    }
+
+    @Test
+    public void testOnUnlockUser_whenBackupNotActivated_doesNotStartUser() {
+        when(mBackupManagerServiceMock.getUserServices()).thenReturn(new SparseArray<>());
+        TrampolineTestable.sBackupDisabled = false;
+        TrampolineTestable trampoline = new TrampolineTestable(mContextMock);
+        trampoline.setBackupServiceActive(NON_USER_SYSTEM, false);
+        ConditionVariable unlocked = new ConditionVariable(false);
+
+        trampoline.onUnlockUser(NON_USER_SYSTEM);
+
+        trampoline.getBackupHandler().post(unlocked::open);
+        unlocked.block();
+        assertNull(trampoline.getUserService(NON_USER_SYSTEM));
+        //noinspection unchecked
+        verify(mBackupManagerServiceMock, never()).startServiceForUser(
+                eq(NON_USER_SYSTEM), any(Set.class));
+    }
+
+    @Test
+    public void testIsBackupServiceActive_forSystemUserWhenBackupDisabled_returnsTrue()
+            throws Exception {
+        TrampolineTestable.sBackupDisabled = true;
+        Trampoline trampoline = new TrampolineTestable(mContextMock);
+        trampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
 
         assertFalse(trampoline.isBackupServiceActive(UserHandle.USER_SYSTEM));
     }
 
     @Test
-    public void initializeService_doesNotStartServiceForUsers() {
-        mTrampoline.initializeService();
+    public void testIsBackupServiceActive_forNonSystemUserWhenBackupDisabled_returnsTrue()
+            throws Exception {
+        TrampolineTestable.sBackupDisabled = true;
+        Trampoline trampoline = new TrampolineTestable(mContextMock);
+        trampoline.setBackupServiceActive(NON_USER_SYSTEM, true);
 
-        verify(mBackupManagerServiceMock, never()).startServiceForUser(anyInt());
-    }
-
-    @Test
-    public void isBackupServiceActive_calledBeforeInitialize_returnsFalse() {
-        assertFalse(mTrampoline.isBackupServiceActive(UserHandle.USER_SYSTEM));
+        assertFalse(trampoline.isBackupServiceActive(NON_USER_SYSTEM));
     }
 
     @Test
     public void isBackupServiceActive_forSystemUser_returnsTrueWhenActivated() throws Exception {
-        mTrampoline.initializeService();
         mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
 
         assertTrue(mTrampoline.isBackupServiceActive(UserHandle.USER_SYSTEM));
@@ -220,7 +263,6 @@
 
     @Test
     public void isBackupServiceActive_forSystemUser_returnsFalseWhenDeactivated() throws Exception {
-        mTrampoline.initializeService();
         mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, false);
 
         assertFalse(mTrampoline.isBackupServiceActive(UserHandle.USER_SYSTEM));
@@ -229,7 +271,6 @@
     @Test
     public void isBackupServiceActive_forNonSystemUser_returnsFalseWhenSystemUserDeactivated()
             throws Exception {
-        mTrampoline.initializeService();
         mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, false);
         mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, true);
 
@@ -239,7 +280,6 @@
     @Test
     public void isBackupServiceActive_forNonSystemUser_returnsFalseWhenNonSystemUserDeactivated()
             throws Exception {
-        mTrampoline.initializeService();
         mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
         // Don't activate non-system user.
 
@@ -250,7 +290,6 @@
     public void
             isBackupServiceActive_forNonSystemUser_returnsTrueWhenSystemAndNonSystemUserActivated()
                 throws Exception {
-        mTrampoline.initializeService();
         mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
         mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, true);
 
@@ -261,7 +300,6 @@
     public void
             isBackupServiceActive_forUnstartedNonSystemUser_returnsTrueWhenSystemAndUserActivated()
             throws Exception {
-        mTrampoline.initializeService();
         mTrampoline.setBackupServiceActive(UNSTARTED_NON_USER_SYSTEM, true);
 
         assertTrue(mTrampoline.isBackupServiceActive(UNSTARTED_NON_USER_SYSTEM));
@@ -269,7 +307,6 @@
 
     @Test
     public void setBackupServiceActive_forSystemUserAndCallerSystemUid_serviceCreated() {
-        mTrampoline.initializeService();
         TrampolineTestable.sCallingUid = Process.SYSTEM_UID;
 
         mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
@@ -279,7 +316,6 @@
 
     @Test
     public void setBackupServiceActive_forSystemUserAndCallerRootUid_serviceCreated() {
-        mTrampoline.initializeService();
         TrampolineTestable.sCallingUid = Process.ROOT_UID;
 
         mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
@@ -289,7 +325,6 @@
 
     @Test
     public void setBackupServiceActive_forSystemUserAndCallerNonRootNonSystem_throws() {
-        mTrampoline.initializeService();
         TrampolineTestable.sCallingUid = Process.FIRST_APPLICATION_UID;
 
         try {
@@ -302,7 +337,6 @@
     @Test
     public void setBackupServiceActive_forManagedProfileAndCallerSystemUid_serviceCreated() {
         when(mUserInfoMock.isManagedProfile()).thenReturn(true);
-        mTrampoline.initializeService();
         TrampolineTestable.sCallingUid = Process.SYSTEM_UID;
 
         mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, true);
@@ -313,7 +347,6 @@
     @Test
     public void setBackupServiceActive_forManagedProfileAndCallerRootUid_serviceCreated() {
         when(mUserInfoMock.isManagedProfile()).thenReturn(true);
-        mTrampoline.initializeService();
         TrampolineTestable.sCallingUid = Process.ROOT_UID;
 
         mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, true);
@@ -324,7 +357,6 @@
     @Test
     public void setBackupServiceActive_forManagedProfileAndCallerNonRootNonSystem_throws() {
         when(mUserInfoMock.isManagedProfile()).thenReturn(true);
-        mTrampoline.initializeService();
         TrampolineTestable.sCallingUid = Process.FIRST_APPLICATION_UID;
 
         try {
@@ -339,7 +371,6 @@
         doThrow(new SecurityException())
                 .when(mContextMock)
                 .enforceCallingOrSelfPermission(eq(Manifest.permission.BACKUP), anyString());
-        mTrampoline.initializeService();
 
         try {
             mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, true);
@@ -354,7 +385,6 @@
                 .when(mContextMock)
                 .enforceCallingOrSelfPermission(
                         eq(Manifest.permission.INTERACT_ACROSS_USERS_FULL), anyString());
-        mTrampoline.initializeService();
 
         try {
             mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, true);
@@ -367,7 +397,6 @@
     public void setBackupServiceActive_backupDisabled_ignored() {
         TrampolineTestable.sBackupDisabled = true;
         TrampolineTestable trampoline = new TrampolineTestable(mContextMock);
-        trampoline.initializeService();
 
         trampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
 
@@ -376,19 +405,15 @@
 
     @Test
     public void setBackupServiceActive_alreadyActive_ignored() {
-        mTrampoline.initializeService();
         mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
         assertTrue(mTrampoline.isBackupServiceActive(UserHandle.USER_SYSTEM));
-        assertEquals(1, mTrampoline.getCreateServiceCallsCount());
 
         mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
         assertTrue(mTrampoline.isBackupServiceActive(UserHandle.USER_SYSTEM));
-        assertEquals(1, mTrampoline.getCreateServiceCallsCount());
     }
 
     @Test
     public void setBackupServiceActive_makeNonActive_alreadyNonActive_ignored() {
-        mTrampoline.initializeService();
         mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, false);
         mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, false);
 
@@ -397,7 +422,6 @@
 
     @Test
     public void setBackupServiceActive_makeActive_serviceCreatedAndSuppressFileDeleted() {
-        mTrampoline.initializeService();
         mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
 
         assertTrue(mTrampoline.isBackupServiceActive(UserHandle.USER_SYSTEM));
@@ -406,7 +430,6 @@
     @Test
     public void setBackupServiceActive_makeNonActive_serviceDeletedAndSuppressFileCreated()
             throws IOException {
-        mTrampoline.initializeService();
         assertTrue(mTrampoline.isBackupServiceActive(UserHandle.USER_SYSTEM));
 
         mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, false);
@@ -416,7 +439,6 @@
 
     @Test
     public void setBackupActive_nonSystemUser_disabledForSystemUser_ignored() {
-        mTrampoline.initializeService();
         mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, false);
         mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, true);
 
@@ -425,7 +447,6 @@
 
     @Test
     public void setBackupServiceActive_forOneNonSystemUser_doesNotActivateForAllNonSystemUsers() {
-        mTrampoline.initializeService();
         int otherUser = NON_USER_SYSTEM + 1;
         File activateFile = new File(mTestDir, "activate-" + otherUser);
         TrampolineTestable.sActivatedFiles.append(otherUser, activateFile);
@@ -440,7 +461,6 @@
 
     @Test
     public void setBackupServiceActive_forNonSystemUser_remembersActivated() {
-        mTrampoline.initializeService();
 
         mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, true);
 
@@ -450,7 +470,6 @@
 
     @Test
     public void setBackupServiceActiveFalse_forNonSystemUser_remembersActivated() {
-        mTrampoline.initializeService();
 
         mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, false);
 
@@ -460,8 +479,6 @@
 
     @Test
     public void setBackupServiceActiveTwice_forNonSystemUser_remembersLastActivated() {
-        mTrampoline.initializeService();
-
         mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, true);
         mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, false);
 
@@ -470,15 +487,7 @@
     }
 
     @Test
-    public void dataChanged_calledBeforeInitialize_ignored() throws Exception {
-        mTrampoline.dataChanged(PACKAGE_NAME);
-        verifyNoMoreInteractions(mBackupManagerServiceMock);
-    }
-
-    @Test
     public void dataChangedForUser_forwarded() throws Exception {
-        mTrampoline.initializeService();
-
         mTrampoline.dataChangedForUser(mUserId, PACKAGE_NAME);
 
         verify(mBackupManagerServiceMock).dataChanged(mUserId, PACKAGE_NAME);
@@ -487,7 +496,6 @@
     @Test
     public void dataChanged_forwarded() throws Exception {
         TrampolineTestable.sCallingUserId = mUserId;
-        mTrampoline.initializeService();
 
         mTrampoline.dataChanged(PACKAGE_NAME);
 
@@ -495,14 +503,7 @@
     }
 
     @Test
-    public void clearBackupData_calledBeforeInitialize_ignored() throws Exception {
-        mTrampoline.clearBackupData(TRANSPORT_NAME, PACKAGE_NAME);
-        verifyNoMoreInteractions(mBackupManagerServiceMock);
-    }
-
-    @Test
     public void clearBackupDataForUser_forwarded() throws Exception {
-        mTrampoline.initializeService();
 
         mTrampoline.clearBackupDataForUser(mUserId, TRANSPORT_NAME, PACKAGE_NAME);
 
@@ -512,7 +513,6 @@
     @Test
     public void clearBackupData_forwarded() throws Exception {
         TrampolineTestable.sCallingUserId = mUserId;
-        mTrampoline.initializeService();
 
         mTrampoline.clearBackupData(TRANSPORT_NAME, PACKAGE_NAME);
 
@@ -520,14 +520,7 @@
     }
 
     @Test
-    public void agentConnected_calledBeforeInitialize_ignored() throws Exception {
-        mTrampoline.agentConnected(PACKAGE_NAME, mAgentMock);
-        verifyNoMoreInteractions(mBackupManagerServiceMock);
-    }
-
-    @Test
     public void agentConnectedForUser_forwarded() throws Exception {
-        mTrampoline.initializeService();
 
         mTrampoline.agentConnectedForUser(mUserId, PACKAGE_NAME, mAgentMock);
 
@@ -537,7 +530,6 @@
     @Test
     public void agentConnected_forwarded() throws Exception {
         TrampolineTestable.sCallingUserId = mUserId;
-        mTrampoline.initializeService();
 
         mTrampoline.agentConnected(PACKAGE_NAME, mAgentMock);
 
@@ -545,14 +537,7 @@
     }
 
     @Test
-    public void agentDisconnected_calledBeforeInitialize_ignored() throws Exception {
-        mTrampoline.agentDisconnected(PACKAGE_NAME);
-        verifyNoMoreInteractions(mBackupManagerServiceMock);
-    }
-
-    @Test
     public void agentDisconnectedForUser_forwarded() throws Exception {
-        mTrampoline.initializeService();
 
         mTrampoline.agentDisconnectedForUser(mUserId, PACKAGE_NAME);
 
@@ -562,7 +547,6 @@
     @Test
     public void agentDisconnected_forwarded() throws Exception {
         TrampolineTestable.sCallingUserId = mUserId;
-        mTrampoline.initializeService();
 
         mTrampoline.agentDisconnected(PACKAGE_NAME);
 
@@ -570,14 +554,7 @@
     }
 
     @Test
-    public void restoreAtInstall_calledBeforeInitialize_ignored() throws Exception {
-        mTrampoline.restoreAtInstall(PACKAGE_NAME, 123);
-        verifyNoMoreInteractions(mBackupManagerServiceMock);
-    }
-
-    @Test
     public void restoreAtInstallForUser_forwarded() throws Exception {
-        mTrampoline.initializeService();
 
         mTrampoline.restoreAtInstallForUser(mUserId, PACKAGE_NAME, 123);
 
@@ -587,7 +564,6 @@
     @Test
     public void restoreAtInstall_forwarded() throws Exception {
         TrampolineTestable.sCallingUserId = mUserId;
-        mTrampoline.initializeService();
 
         mTrampoline.restoreAtInstall(PACKAGE_NAME, 123);
 
@@ -595,14 +571,7 @@
     }
 
     @Test
-    public void setBackupEnabled_calledBeforeInitialize_ignored() throws Exception {
-        mTrampoline.setBackupEnabled(true);
-        verifyNoMoreInteractions(mBackupManagerServiceMock);
-    }
-
-    @Test
     public void setBackupEnabledForUser_forwarded() throws Exception {
-        mTrampoline.initializeService();
 
         mTrampoline.setBackupEnabledForUser(mUserId, true);
 
@@ -612,7 +581,6 @@
     @Test
     public void setBackupEnabled_forwardedToCallingUserId() throws Exception {
         TrampolineTestable.sCallingUserId = mUserId;
-        mTrampoline.initializeService();
 
         mTrampoline.setBackupEnabled(true);
 
@@ -620,14 +588,7 @@
     }
 
     @Test
-    public void setAutoRestore_calledBeforeInitialize_ignored() throws Exception {
-        mTrampoline.setAutoRestore(true);
-        verifyNoMoreInteractions(mBackupManagerServiceMock);
-    }
-
-    @Test
     public void setAutoRestoreForUser_forwarded() throws Exception {
-        mTrampoline.initializeService();
 
         mTrampoline.setAutoRestoreForUser(mUserId, true);
 
@@ -637,7 +598,6 @@
     @Test
     public void setAutoRestore_forwarded() throws Exception {
         TrampolineTestable.sCallingUserId = mUserId;
-        mTrampoline.initializeService();
 
         mTrampoline.setAutoRestore(true);
 
@@ -645,14 +605,7 @@
     }
 
     @Test
-    public void isBackupEnabled_calledBeforeInitialize_ignored() throws Exception {
-        assertFalse(mTrampoline.isBackupEnabled());
-        verifyNoMoreInteractions(mBackupManagerServiceMock);
-    }
-
-    @Test
     public void isBackupEnabledForUser_forwarded() throws Exception {
-        mTrampoline.initializeService();
 
         mTrampoline.isBackupEnabledForUser(mUserId);
 
@@ -662,7 +615,6 @@
     @Test
     public void isBackupEnabled_forwardedToCallingUserId() throws Exception {
         TrampolineTestable.sCallingUserId = mUserId;
-        mTrampoline.initializeService();
 
         mTrampoline.isBackupEnabled();
 
@@ -670,40 +622,19 @@
     }
 
     @Test
-    public void setBackupPassword_calledBeforeInitialize_ignored() throws Exception {
-        mTrampoline.setBackupPassword(CURRENT_PASSWORD, NEW_PASSWORD);
-        verifyNoMoreInteractions(mBackupManagerServiceMock);
-    }
-
-    @Test
     public void setBackupPassword_forwarded() throws Exception {
-        mTrampoline.initializeService();
         mTrampoline.setBackupPassword(CURRENT_PASSWORD, NEW_PASSWORD);
         verify(mBackupManagerServiceMock).setBackupPassword(CURRENT_PASSWORD, NEW_PASSWORD);
     }
 
     @Test
-    public void hasBackupPassword_calledBeforeInitialize_ignored() throws Exception {
-        assertFalse(mTrampoline.hasBackupPassword());
-        verifyNoMoreInteractions(mBackupManagerServiceMock);
-    }
-
-    @Test
     public void hasBackupPassword_forwarded() throws Exception {
-        mTrampoline.initializeService();
         mTrampoline.hasBackupPassword();
         verify(mBackupManagerServiceMock).hasBackupPassword();
     }
 
     @Test
-    public void backupNow_calledBeforeInitialize_ignored() throws Exception {
-        mTrampoline.backupNow();
-        verifyNoMoreInteractions(mBackupManagerServiceMock);
-    }
-
-    @Test
     public void backupNowForUser_forwarded() throws Exception {
-        mTrampoline.initializeService();
 
         mTrampoline.backupNowForUser(mUserId);
 
@@ -713,7 +644,6 @@
     @Test
     public void backupNow_forwardedToCallingUserId() throws Exception {
         TrampolineTestable.sCallingUserId = mUserId;
-        mTrampoline.initializeService();
 
         mTrampoline.backupNow();
 
@@ -721,16 +651,7 @@
     }
 
     @Test
-    public void adbBackup_calledBeforeInitialize_ignored() throws Exception {
-        mTrampoline.adbBackup(mUserId, mParcelFileDescriptorMock, true, true,
-                true, true, true, true, true, true,
-                PACKAGE_NAMES);
-        verifyNoMoreInteractions(mBackupManagerServiceMock);
-    }
-
-    @Test
     public void adbBackup_forwarded() throws Exception {
-        mTrampoline.initializeService();
         mTrampoline.adbBackup(mUserId, mParcelFileDescriptorMock, true, true,
                 true, true, true, true, true, true,
                 PACKAGE_NAMES);
@@ -739,14 +660,7 @@
     }
 
     @Test
-    public void fullTransportBackup_calledBeforeInitialize_ignored() throws Exception {
-        mTrampoline.fullTransportBackupForUser(mUserId, PACKAGE_NAMES);
-        verifyNoMoreInteractions(mBackupManagerServiceMock);
-    }
-
-    @Test
     public void fullTransportBackupForUser_forwarded() throws Exception {
-        mTrampoline.initializeService();
 
         mTrampoline.fullTransportBackupForUser(mUserId, PACKAGE_NAMES);
 
@@ -754,29 +668,13 @@
     }
 
     @Test
-    public void adbRestore_calledBeforeInitialize_ignored() throws Exception {
-        mTrampoline.adbRestore(mUserId, mParcelFileDescriptorMock);
-        verifyNoMoreInteractions(mBackupManagerServiceMock);
-    }
-
-    @Test
     public void adbRestore_forwarded() throws Exception {
-        mTrampoline.initializeService();
         mTrampoline.adbRestore(mUserId, mParcelFileDescriptorMock);
         verify(mBackupManagerServiceMock).adbRestore(mUserId, mParcelFileDescriptorMock);
     }
 
     @Test
-    public void acknowledgeFullBackupOrRestore_calledBeforeInitialize_ignored()
-            throws Exception {
-        mTrampoline.acknowledgeFullBackupOrRestore(123, true, CURRENT_PASSWORD, ENCRYPTION_PASSWORD,
-                mFullBackupRestoreObserverMock);
-        verifyNoMoreInteractions(mBackupManagerServiceMock);
-    }
-
-    @Test
     public void acknowledgeFullBackupOrRestoreForUser_forwarded() throws Exception {
-        mTrampoline.initializeService();
 
         mTrampoline.acknowledgeFullBackupOrRestoreForUser(
                 mUserId,
@@ -799,7 +697,6 @@
     @Test
     public void acknowledgeFullBackupOrRestore_forwarded() throws Exception {
         TrampolineTestable.sCallingUserId = mUserId;
-        mTrampoline.initializeService();
 
         mTrampoline.acknowledgeFullBackupOrRestore(123, true, CURRENT_PASSWORD, ENCRYPTION_PASSWORD,
                 mFullBackupRestoreObserverMock);
@@ -815,15 +712,8 @@
     }
 
     @Test
-    public void getCurrentTransport_calledBeforeInitialize_ignored() throws Exception {
-        assertNull(mTrampoline.getCurrentTransport());
-        verifyNoMoreInteractions(mBackupManagerServiceMock);
-    }
-
-    @Test
     public void getCurrentTransportForUser_forwarded() throws Exception {
         when(mBackupManagerServiceMock.getCurrentTransport(mUserId)).thenReturn(TRANSPORT_NAME);
-        mTrampoline.initializeService();
 
         assertEquals(TRANSPORT_NAME, mTrampoline.getCurrentTransportForUser(mUserId));
         verify(mBackupManagerServiceMock).getCurrentTransport(mUserId);
@@ -833,22 +723,14 @@
     public void getCurrentTransport_forwarded() throws Exception {
         TrampolineTestable.sCallingUserId = mUserId;
         when(mBackupManagerServiceMock.getCurrentTransport(mUserId)).thenReturn(TRANSPORT_NAME);
-        mTrampoline.initializeService();
 
         assertEquals(TRANSPORT_NAME, mTrampoline.getCurrentTransport());
         verify(mBackupManagerServiceMock).getCurrentTransport(mUserId);
     }
 
     @Test
-    public void listAllTransports_calledBeforeInitialize_ignored() throws Exception {
-        assertNull(mTrampoline.listAllTransports());
-        verifyNoMoreInteractions(mBackupManagerServiceMock);
-    }
-
-    @Test
     public void listAllTransportsForUser_forwarded() throws Exception {
         when(mBackupManagerServiceMock.listAllTransports(mUserId)).thenReturn(TRANSPORTS);
-        mTrampoline.initializeService();
 
         assertEquals(TRANSPORTS, mTrampoline.listAllTransportsForUser(mUserId));
         verify(mBackupManagerServiceMock).listAllTransports(mUserId);
@@ -859,63 +741,22 @@
     public void listAllTransports_forwarded() throws Exception {
         TrampolineTestable.sCallingUserId = mUserId;
         when(mBackupManagerServiceMock.listAllTransports(mUserId)).thenReturn(TRANSPORTS);
-        mTrampoline.initializeService();
 
         assertEquals(TRANSPORTS, mTrampoline.listAllTransports());
         verify(mBackupManagerServiceMock).listAllTransports(mUserId);
     }
 
     @Test
-    public void listAllTransportComponentsForUser_calledBeforeInitialize_ignored()
-            throws Exception {
-        assertNull(mTrampoline.listAllTransportComponentsForUser(mUserId));
-        verifyNoMoreInteractions(mBackupManagerServiceMock);
-    }
-
-    @Test
     public void listAllTransportComponentsForUser_forwarded() throws Exception {
         when(mBackupManagerServiceMock.listAllTransportComponents(mUserId)).thenReturn(
                 TRANSPORT_COMPONENTS);
-        mTrampoline.initializeService();
 
         assertEquals(TRANSPORT_COMPONENTS, mTrampoline.listAllTransportComponentsForUser(mUserId));
         verify(mBackupManagerServiceMock).listAllTransportComponents(mUserId);
     }
 
     @Test
-    public void getTransportWhitelist_calledBeforeInitialize_ignored() throws Exception {
-        assertNull(mTrampoline.getTransportWhitelist());
-        verifyNoMoreInteractions(mBackupManagerServiceMock);
-    }
-
-    @Test
-    public void getTransportWhitelist_forwarded() {
-        when(mBackupManagerServiceMock.getTransportWhitelist()).thenReturn(TRANSPORTS);
-        mTrampoline.initializeService();
-
-        assertEquals(TRANSPORTS, mTrampoline.getTransportWhitelist());
-        verify(mBackupManagerServiceMock).getTransportWhitelist();
-    }
-
-    @Test
-    public void updateTransportAttributesForUser_calledBeforeInitialize_ignored() {
-        mTrampoline.updateTransportAttributesForUser(
-                mUserId,
-                TRANSPORT_COMPONENT_NAME,
-                TRANSPORT_NAME,
-                null,
-                "Transport Destination",
-                null,
-                "Data Management");
-
-        verifyNoMoreInteractions(mBackupManagerServiceMock);
-    }
-
-    @Test
     public void updateTransportAttributesForUser_forwarded() {
-        when(mBackupManagerServiceMock.getTransportWhitelist()).thenReturn(TRANSPORTS);
-        mTrampoline.initializeService();
-
         mTrampoline.updateTransportAttributesForUser(
                 mUserId,
                 TRANSPORT_COMPONENT_NAME,
@@ -937,14 +778,7 @@
     }
 
     @Test
-    public void selectBackupTransport_calledBeforeInitialize_ignored() throws RemoteException {
-        mTrampoline.selectBackupTransport(TRANSPORT_NAME);
-        verifyNoMoreInteractions(mBackupManagerServiceMock);
-    }
-
-    @Test
     public void selectBackupTransportForUser_forwarded() throws Exception {
-        mTrampoline.initializeService();
 
         mTrampoline.selectBackupTransportForUser(mUserId, TRANSPORT_NAME);
 
@@ -954,7 +788,6 @@
     @Test
     public void selectBackupTransport_forwarded() throws Exception {
         TrampolineTestable.sCallingUserId = mUserId;
-        mTrampoline.initializeService();
 
         mTrampoline.selectBackupTransport(TRANSPORT_NAME);
 
@@ -962,75 +795,56 @@
     }
 
     @Test
-    public void selectBackupTransportAsyncForUser_calledBeforeInitialize_ignored()
+    public void selectBackupTransportAsyncForUser_beforeUserUnlocked_notifiesBackupNotAllowed()
             throws Exception {
-        LinkedBlockingQueue<Integer> q = new LinkedBlockingQueue();
-
-        mTrampoline.selectBackupTransportAsyncForUser(
-                mUserId,
-                TRANSPORT_COMPONENT_NAME,
-                new ISelectBackupTransportCallback() {
+        when(mBackupManagerServiceMock.getUserServices()).thenReturn(new SparseArray<>());
+        CompletableFuture<Integer> future = new CompletableFuture<>();
+        ISelectBackupTransportCallback listener =
+                new ISelectBackupTransportCallback.Stub() {
                     @Override
-                    public void onSuccess(String transportName) throws RemoteException {
-
+                    public void onSuccess(String transportName) {
+                        future.completeExceptionally(new AssertionError());
                     }
-
                     @Override
-                    public void onFailure(int reason) throws RemoteException {
-                        q.offer(reason);
+                    public void onFailure(int reason) {
+                        future.complete(reason);
                     }
+                };
 
-                    @Override
-                    public IBinder asBinder() {
-                        return null;
-                    }
-                });
+        mTrampoline.selectBackupTransportAsyncForUser(mUserId, TRANSPORT_COMPONENT_NAME, listener);
 
-        verifyNoMoreInteractions(mBackupManagerServiceMock);
-        Integer errorCode = q.poll(5, TimeUnit.SECONDS);
-        assertNotNull(errorCode);
-        assertEquals(BackupManager.ERROR_BACKUP_NOT_ALLOWED, (int) errorCode);
+        assertEquals(BackupManager.ERROR_BACKUP_NOT_ALLOWED, (int) future.get(5, TimeUnit.SECONDS));
     }
 
     @Test
-    public void selectBackupTransportAsyncForUser_calledBeforeInitialize_ignored_nullListener()
+    public void selectBackupTransportAsyncForUser_beforeUserUnlockedWithNullListener_doesNotThrow()
             throws Exception {
         mTrampoline.selectBackupTransportAsyncForUser(mUserId, TRANSPORT_COMPONENT_NAME, null);
 
-        verifyNoMoreInteractions(mBackupManagerServiceMock);
         // No crash.
     }
 
     @Test
-    public void selectBackupTransportAsyncForUser_calledBeforeInitialize_ignored_listenerThrows()
+    public void
+            selectBackupTransportAsyncForUser_beforeUserUnlockedWithThrowingListener_doesNotThrow()
             throws Exception {
-        mTrampoline.selectBackupTransportAsyncForUser(
-                mUserId,
-                TRANSPORT_COMPONENT_NAME,
-                new ISelectBackupTransportCallback() {
+        ISelectBackupTransportCallback.Stub listener =
+                new ISelectBackupTransportCallback.Stub() {
                     @Override
-                    public void onSuccess(String transportName) throws RemoteException {
-
-                    }
-
+                    public void onSuccess(String transportName) {}
                     @Override
                     public void onFailure(int reason) throws RemoteException {
-                        throw new RemoteException("Crash");
+                        throw new RemoteException();
                     }
+                };
 
-                    @Override
-                    public IBinder asBinder() {
-                        return null;
-                    }
-                });
+        mTrampoline.selectBackupTransportAsyncForUser(mUserId, TRANSPORT_COMPONENT_NAME, listener);
 
-        verifyNoMoreInteractions(mBackupManagerServiceMock);
         // No crash.
     }
 
     @Test
     public void selectBackupTransportAsyncForUser_forwarded() throws Exception {
-        mTrampoline.initializeService();
 
         mTrampoline.selectBackupTransportAsyncForUser(mUserId, TRANSPORT_COMPONENT_NAME, null);
 
@@ -1039,17 +853,10 @@
     }
 
     @Test
-    public void getConfigurationIntent_calledBeforeInitialize_ignored() throws Exception {
-        mTrampoline.getConfigurationIntent(TRANSPORT_NAME);
-        verifyNoMoreInteractions(mBackupManagerServiceMock);
-    }
-
-    @Test
     public void getConfigurationIntentForUser_forwarded() throws Exception {
         Intent configurationIntentStub = new Intent();
         when(mBackupManagerServiceMock.getConfigurationIntent(mUserId, TRANSPORT_NAME)).thenReturn(
                 configurationIntentStub);
-        mTrampoline.initializeService();
 
         assertEquals(
                 configurationIntentStub,
@@ -1063,23 +870,15 @@
         Intent configurationIntentStub = new Intent();
         when(mBackupManagerServiceMock.getConfigurationIntent(mUserId, TRANSPORT_NAME)).thenReturn(
                 configurationIntentStub);
-        mTrampoline.initializeService();
 
         assertEquals(configurationIntentStub, mTrampoline.getConfigurationIntent(TRANSPORT_NAME));
         verify(mBackupManagerServiceMock).getConfigurationIntent(mUserId, TRANSPORT_NAME);
     }
 
     @Test
-    public void getDestinationString_calledBeforeInitialize_ignored() throws Exception {
-        assertNull(mTrampoline.getDestinationString(TRANSPORT_NAME));
-        verifyNoMoreInteractions(mBackupManagerServiceMock);
-    }
-
-    @Test
     public void getDestinationStringForUser_forwarded() throws Exception {
         when(mBackupManagerServiceMock.getDestinationString(mUserId, TRANSPORT_NAME)).thenReturn(
                 DESTINATION_STRING);
-        mTrampoline.initializeService();
 
         assertEquals(
                 DESTINATION_STRING,
@@ -1093,23 +892,15 @@
         when(mBackupManagerServiceMock.getDestinationString(mUserId, TRANSPORT_NAME)).thenReturn(
                 DESTINATION_STRING);
 
-        mTrampoline.initializeService();
         assertEquals(DESTINATION_STRING, mTrampoline.getDestinationString(TRANSPORT_NAME));
         verify(mBackupManagerServiceMock).getDestinationString(mUserId, TRANSPORT_NAME);
     }
 
     @Test
-    public void getDataManagementIntent_calledBeforeInitialize_ignored() throws Exception {
-        assertNull(mTrampoline.getDataManagementIntent(TRANSPORT_NAME));
-        verifyNoMoreInteractions(mBackupManagerServiceMock);
-    }
-
-    @Test
     public void getDataManagementIntentForUser_forwarded() throws Exception {
         Intent dataManagementIntent = new Intent();
         when(mBackupManagerServiceMock.getDataManagementIntent(mUserId, TRANSPORT_NAME)).thenReturn(
                 dataManagementIntent);
-        mTrampoline.initializeService();
 
         assertEquals(
                 dataManagementIntent,
@@ -1123,23 +914,15 @@
         Intent dataManagementIntent = new Intent();
         when(mBackupManagerServiceMock.getDataManagementIntent(mUserId, TRANSPORT_NAME)).thenReturn(
                 dataManagementIntent);
-        mTrampoline.initializeService();
 
         assertEquals(dataManagementIntent, mTrampoline.getDataManagementIntent(TRANSPORT_NAME));
         verify(mBackupManagerServiceMock).getDataManagementIntent(mUserId, TRANSPORT_NAME);
     }
 
     @Test
-    public void getDataManagementLabelForUser_calledBeforeInitialize_ignored() throws Exception {
-        assertNull(mTrampoline.getDataManagementLabelForUser(mUserId, TRANSPORT_NAME));
-        verifyNoMoreInteractions(mBackupManagerServiceMock);
-    }
-
-    @Test
     public void getDataManagementLabelForUser_forwarded() throws Exception {
         when(mBackupManagerServiceMock.getDataManagementLabel(mUserId, TRANSPORT_NAME)).thenReturn(
                 DATA_MANAGEMENT_LABEL);
-        mTrampoline.initializeService();
 
         assertEquals(
                 DATA_MANAGEMENT_LABEL,
@@ -1148,14 +931,7 @@
     }
 
     @Test
-    public void beginRestoreSession_calledBeforeInitialize_ignored() throws Exception {
-        mTrampoline.beginRestoreSessionForUser(mUserId, PACKAGE_NAME, TRANSPORT_NAME);
-        verifyNoMoreInteractions(mBackupManagerServiceMock);
-    }
-
-    @Test
     public void beginRestoreSessionForUser_forwarded() throws Exception {
-        mTrampoline.initializeService();
 
         mTrampoline.beginRestoreSessionForUser(mUserId, PACKAGE_NAME, TRANSPORT_NAME);
 
@@ -1164,15 +940,8 @@
     }
 
     @Test
-    public void opComplete_calledBeforeInitialize_ignored() throws Exception {
-        mTrampoline.opComplete(1, 2);
-        verifyNoMoreInteractions(mBackupManagerServiceMock);
-    }
-
-    @Test
     public void opComplete_forwarded() throws Exception {
         TrampolineTestable.sCallingUserId = mUserId;
-        mTrampoline.initializeService();
 
         mTrampoline.opComplete(1, 2);
 
@@ -1180,49 +949,27 @@
     }
 
     @Test
-    public void getAvailableRestoreTokenForUser_calledBeforeInitialize_ignored() {
-        assertEquals(0, mTrampoline.getAvailableRestoreTokenForUser(mUserId, PACKAGE_NAME));
-        verifyNoMoreInteractions(mBackupManagerServiceMock);
-    }
-
-    @Test
     public void getAvailableRestoreTokenForUser_forwarded() {
         when(mBackupManagerServiceMock.getAvailableRestoreToken(mUserId, PACKAGE_NAME))
                 .thenReturn(123L);
-        mTrampoline.initializeService();
 
         assertEquals(123, mTrampoline.getAvailableRestoreTokenForUser(mUserId, PACKAGE_NAME));
         verify(mBackupManagerServiceMock).getAvailableRestoreToken(mUserId, PACKAGE_NAME);
     }
 
     @Test
-    public void isAppEligibleForBackupForUser_calledBeforeInitialize_ignored() {
-        assertFalse(mTrampoline.isAppEligibleForBackupForUser(mUserId, PACKAGE_NAME));
-        verifyNoMoreInteractions(mBackupManagerServiceMock);
-    }
-
-    @Test
     public void isAppEligibleForBackupForUser_forwarded() {
         when(mBackupManagerServiceMock.isAppEligibleForBackup(mUserId, PACKAGE_NAME))
                 .thenReturn(true);
-        mTrampoline.initializeService();
 
         assertTrue(mTrampoline.isAppEligibleForBackupForUser(mUserId, PACKAGE_NAME));
         verify(mBackupManagerServiceMock).isAppEligibleForBackup(mUserId, PACKAGE_NAME);
     }
 
     @Test
-    public void requestBackup_calledBeforeInitialize_ignored() throws RemoteException {
-        assertEquals(BackupManager.ERROR_BACKUP_NOT_ALLOWED, mTrampoline.requestBackup(
-                PACKAGE_NAMES, mBackupObserverMock, mBackupManagerMonitorMock, 123));
-        verifyNoMoreInteractions(mBackupManagerServiceMock);
-    }
-
-    @Test
     public void requestBackupForUser_forwarded() throws Exception {
         when(mBackupManagerServiceMock.requestBackup(mUserId, PACKAGE_NAMES,
                 mBackupObserverMock, mBackupManagerMonitorMock, 123)).thenReturn(456);
-        mTrampoline.initializeService();
 
         assertEquals(456, mTrampoline.requestBackupForUser(mUserId, PACKAGE_NAMES,
                 mBackupObserverMock, mBackupManagerMonitorMock, 123));
@@ -1235,7 +982,6 @@
         TrampolineTestable.sCallingUserId = mUserId;
         when(mBackupManagerServiceMock.requestBackup(mUserId, PACKAGE_NAMES,
                 mBackupObserverMock, mBackupManagerMonitorMock, 123)).thenReturn(456);
-        mTrampoline.initializeService();
 
         assertEquals(456, mTrampoline.requestBackup(PACKAGE_NAMES,
                 mBackupObserverMock, mBackupManagerMonitorMock, 123));
@@ -1244,14 +990,7 @@
     }
 
     @Test
-    public void cancelBackups_calledBeforeInitialize_ignored() throws Exception {
-        mTrampoline.cancelBackups();
-        verifyNoMoreInteractions(mBackupManagerServiceMock);
-    }
-
-    @Test
     public void cancelBackupsForUser_forwarded() throws Exception {
-        mTrampoline.initializeService();
 
         mTrampoline.cancelBackupsForUser(mUserId);
 
@@ -1261,7 +1000,6 @@
     @Test
     public void cancelBackups_forwardedToCallingUserId() throws Exception {
         TrampolineTestable.sCallingUserId = mUserId;
-        mTrampoline.initializeService();
 
         mTrampoline.cancelBackups();
 
@@ -1269,30 +1007,16 @@
     }
 
     @Test
-    public void beginFullBackup_calledBeforeInitialize_ignored() throws Exception {
-        mTrampoline.beginFullBackup(mUserId, new FullBackupJob());
-        verifyNoMoreInteractions(mBackupManagerServiceMock);
-    }
-
-    @Test
     public void beginFullBackup_forwarded() throws Exception {
         FullBackupJob fullBackupJob = new FullBackupJob();
         when(mBackupManagerServiceMock.beginFullBackup(mUserId, fullBackupJob)).thenReturn(true);
 
-        mTrampoline.initializeService();
         assertTrue(mTrampoline.beginFullBackup(mUserId, fullBackupJob));
         verify(mBackupManagerServiceMock).beginFullBackup(mUserId, fullBackupJob);
     }
 
     @Test
-    public void endFullBackup_calledBeforeInitialize_ignored() {
-        mTrampoline.endFullBackup(mUserId);
-        verifyNoMoreInteractions(mBackupManagerServiceMock);
-    }
-
-    @Test
     public void endFullBackup_forwarded() {
-        mTrampoline.initializeService();
         mTrampoline.endFullBackup(mUserId);
         verify(mBackupManagerServiceMock).endFullBackup(mUserId);
     }
@@ -1302,18 +1026,6 @@
         when(mContextMock.checkCallingOrSelfPermission(
                 android.Manifest.permission.DUMP)).thenReturn(
                 PackageManager.PERMISSION_DENIED);
-        mTrampoline.initializeService();
-
-        mTrampoline.dump(mFileDescriptorStub, mPrintWriterMock, new String[0]);
-
-        verifyNoMoreInteractions(mBackupManagerServiceMock);
-    }
-
-    @Test
-    public void dump_calledBeforeInitialize_ignored() {
-        when(mContextMock.checkCallingOrSelfPermission(
-                android.Manifest.permission.DUMP)).thenReturn(
-                PackageManager.PERMISSION_GRANTED);
 
         mTrampoline.dump(mFileDescriptorStub, mPrintWriterMock, new String[0]);
 
@@ -1325,13 +1037,28 @@
         when(mContextMock.checkCallingOrSelfPermission(
                 android.Manifest.permission.DUMP)).thenReturn(
                 PackageManager.PERMISSION_GRANTED);
-        mTrampoline.initializeService();
 
         mTrampoline.dump(mFileDescriptorStub, mPrintWriterMock, null);
 
         verify(mBackupManagerServiceMock).dump(mFileDescriptorStub, mPrintWriterMock, null);
     }
 
+    public void testGetUserForAncestralSerialNumber() {
+        TrampolineTestable.sBackupDisabled = false;
+        Trampoline trampoline = new TrampolineTestable(mContextMock);
+
+        trampoline.getUserForAncestralSerialNumber(0L);
+        verify(mBackupManagerServiceMock).getUserForAncestralSerialNumber(anyInt());
+    }
+
+    public void testGetUserForAncestralSerialNumber_whenDisabled() {
+        TrampolineTestable.sBackupDisabled = true;
+        Trampoline trampoline = new TrampolineTestable(mContextMock);
+
+        trampoline.getUserForAncestralSerialNumber(0L);
+        verify(mBackupManagerServiceMock, never()).getUserForAncestralSerialNumber(anyInt());
+    }
+
     private static class TrampolineTestable extends Trampoline {
         static boolean sBackupDisabled = false;
         static int sCallingUserId = -1;
@@ -1341,10 +1068,10 @@
         static SparseArray<File> sActivatedFiles = new SparseArray<>();
         static SparseArray<File> sRememberActivatedFiles = new SparseArray<>();
         static UserManager sUserManagerMock = null;
-        private int mCreateServiceCallsCount = 0;
 
         TrampolineTestable(Context context) {
             super(context);
+            mService = sBackupManagerServiceMock;
         }
 
         @Override
@@ -1353,7 +1080,7 @@
         }
 
         @Override
-        public boolean isBackupDisabled() {
+        protected boolean isBackupDisabled() {
             return sBackupDisabled;
         }
 
@@ -1382,18 +1109,8 @@
         }
 
         @Override
-        protected BackupManagerService createBackupManagerService() {
-            mCreateServiceCallsCount++;
-            return sBackupManagerServiceMock;
-        }
-
-        @Override
         protected void postToHandler(Runnable runnable) {
             runnable.run();
         }
-
-        int getCreateServiceCallsCount() {
-            return mCreateServiceCallsCount;
-        }
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTests.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTests.java
index f9e4c34..8e0d7be 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTests.java
@@ -311,8 +311,6 @@
     public void testFileLocation_Owner() {
         LockSettingsStorage storage = new LockSettingsStorage(getContext());
 
-        assertEquals("/data/system/gesture.key", storage.getLegacyLockPatternFilename(0));
-        assertEquals("/data/system/password.key", storage.getLegacyLockPasswordFilename(0));
         assertEquals("/data/system/gatekeeper.pattern.key", storage.getLockPatternFilename(0));
         assertEquals("/data/system/gatekeeper.password.key", storage.getLockPasswordFilename(0));
     }
@@ -436,10 +434,8 @@
                 PAYLOAD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD).toBytes();
         CredentialHash deserialized = CredentialHash.fromBytes(serialized);
 
-        assertEquals(CredentialHash.VERSION_GATEKEEPER, deserialized.version);
         assertEquals(LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, deserialized.type);
         assertArrayEquals(PAYLOAD, deserialized.hash);
-        assertFalse(deserialized.isBaseZeroPattern);
     }
 
     public void testCredentialHash_unserialize_versionGatekeeper() {
@@ -453,10 +449,8 @@
         };
         CredentialHash deserialized = CredentialHash.fromBytes(serialized);
 
-        assertEquals(CredentialHash.VERSION_GATEKEEPER, deserialized.version);
         assertEquals(LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, deserialized.type);
         assertArrayEquals(PAYLOAD, deserialized.hash);
-        assertFalse(deserialized.isBaseZeroPattern);
 
         // Make sure the constants we use on the wire do not change.
         assertEquals(-1, LockPatternUtils.CREDENTIAL_TYPE_NONE);
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 87afdfb..05905d9 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ScanTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ScanTests.java
@@ -76,7 +76,7 @@
     @Before
     public void setupInjector() {
         when(mMockInjector.getAbiHelper()).thenReturn(mMockPackageAbiHelper);
-        when(mMockInjector.getUserManager()).thenReturn(mMockUserManager);
+        when(mMockInjector.getUserManagerInternal()).thenReturn(mMockUserManager);
     }
 
     @Before
diff --git a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
index 1bda412..88de250 100644
--- a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
@@ -23,7 +23,10 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+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.anyString;
 import static org.mockito.ArgumentMatchers.argThat;
@@ -59,6 +62,7 @@
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.provider.Settings;
+import android.view.Display;
 
 import androidx.test.InstrumentationRegistry;
 
@@ -157,6 +161,10 @@
         mResourcesSpy = spy(mContextSpy.getResources());
         when(mContextSpy.getResources()).thenReturn(mResourcesSpy);
 
+        when(mDisplayManagerInternalMock.requestPowerState(any(), anyBoolean())).thenReturn(true);
+    }
+
+    private PowerManagerService createService() {
         mService = new PowerManagerService(mContextSpy, new Injector() {
             @Override
             Notifier createNotifier(Looper looper, Context context, IBatteryStats batteryStats,
@@ -166,7 +174,7 @@
 
             @Override
             SuspendBlocker createSuspendBlocker(PowerManagerService service, String name) {
-                return mock(SuspendBlocker.class);
+                return super.createSuspendBlocker(service, name);
             }
 
             @Override
@@ -191,6 +199,7 @@
                 return mAmbientDisplayConfigurationMock;
             }
         });
+        return mService;
     }
 
     @After
@@ -262,6 +271,7 @@
 
     @Test
     public void testUpdatePowerScreenPolicy_UpdateDisplayPowerRequest() {
+        createService();
         mService.updatePowerRequestFromBatterySaverPolicy(mDisplayPowerRequest);
         assertThat(mDisplayPowerRequest.lowPowerMode).isEqualTo(BATTERY_SAVER_ENABLED);
         assertThat(mDisplayPowerRequest.screenLowPowerBrightnessFactor)
@@ -270,6 +280,7 @@
 
     @Test
     public void testGetLastShutdownReasonInternal() {
+        createService();
         SystemProperties.set(TEST_LAST_REBOOT_PROPERTY, "shutdown,thermal");
         int reason = mService.getLastShutdownReasonInternal(TEST_LAST_REBOOT_PROPERTY);
         SystemProperties.set(TEST_LAST_REBOOT_PROPERTY, "");
@@ -278,6 +289,7 @@
 
     @Test
     public void testGetDesiredScreenPolicy_WithVR() throws Exception {
+        createService();
         // Brighten up the screen
         mService.setWakefulnessLocked(WAKEFULNESS_AWAKE, PowerManager.WAKE_REASON_UNKNOWN, 0);
         assertThat(mService.getDesiredScreenPolicyLocked()).isEqualTo(
@@ -307,11 +319,13 @@
 
     @Test
     public void testWakefulnessAwake_InitialValue() throws Exception {
+        createService();
         assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_AWAKE);
     }
 
     @Test
     public void testWakefulnessSleep_NoDozeSleepFlag() throws Exception {
+        createService();
         // Start with AWAKE state
         startSystem();
         assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_AWAKE);
@@ -324,6 +338,7 @@
 
     @Test
     public void testWakefulnessAwake_AcquireCausesWakeup() throws Exception {
+        createService();
         startSystem();
         forceSleep();
 
@@ -355,6 +370,7 @@
 
     @Test
     public void testWakefulnessAwake_IPowerManagerWakeUp() throws Exception {
+        createService();
         startSystem();
         forceSleep();
         mService.getBinderServiceInstance().wakeUp(SystemClock.uptimeMillis(),
@@ -369,6 +385,8 @@
     @Test
     public void testWakefulnessAwake_ShouldWakeUpWhenPluggedIn() throws Exception {
         boolean powerState;
+
+        createService();
         startSystem();
         forceSleep();
 
@@ -444,6 +462,7 @@
 
     @Test
     public void testWakefulnessDoze_goToSleep() throws Exception {
+        createService();
         // Start with AWAKE state
         startSystem();
         assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_AWAKE);
@@ -457,6 +476,7 @@
     @Test
     public void testWasDeviceIdleFor_true() {
         int interval = 1000;
+        createService();
         mService.onUserActivity();
         SystemClock.sleep(interval + 1 /* just a little more */);
         assertThat(mService.wasDeviceIdleForInternal(interval)).isTrue();
@@ -465,12 +485,14 @@
     @Test
     public void testWasDeviceIdleFor_false() {
         int interval = 1000;
+        createService();
         mService.onUserActivity();
         assertThat(mService.wasDeviceIdleForInternal(interval)).isFalse();
     }
 
     @Test
     public void testForceSuspend_putsDeviceToSleep() {
+        createService();
         mService.systemReady(null);
         mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
 
@@ -497,6 +519,8 @@
         final int flags = PowerManager.PARTIAL_WAKE_LOCK;
         final String pkg = mContextSpy.getOpPackageName();
 
+        createService();
+
         // Set up the Notification mock to keep track of the wakelocks that are currently
         // active or disabled. We'll use this to verify that wakelocks are disabled when
         // they should be.
@@ -541,7 +565,54 @@
 
     @Test
     public void testForceSuspend_forceSuspendFailurePropogated() {
+        createService();
         when(mNativeWrapperMock.nativeForceSuspend()).thenReturn(false);
         assertThat(mService.getBinderServiceInstance().forceSuspend()).isFalse();
     }
+
+    @Test
+    public void testSetDozeOverrideFromDreamManager_triggersSuspendBlocker() throws Exception {
+        final String suspendBlockerName = "PowerManagerService.Display";
+        final String tag = "acq_causes_wakeup";
+        final String packageName = "pkg.name";
+        final IBinder token = new Binder();
+
+        final boolean[] isAcquired = new boolean[1];
+        doAnswer(inv -> {
+            if (suspendBlockerName.equals(inv.getArguments()[0])) {
+                isAcquired[0] = false;
+            }
+            return null;
+        }).when(mNativeWrapperMock).nativeReleaseSuspendBlocker(any());
+
+        doAnswer(inv -> {
+            if (suspendBlockerName.equals(inv.getArguments()[0])) {
+                isAcquired[0] = true;
+            }
+            return null;
+        }).when(mNativeWrapperMock).nativeAcquireSuspendBlocker(any());
+
+        // Need to create the service after we stub the mocks for this test because some of the
+        // mocks are used during the constructor.
+        createService();
+
+        // Start with AWAKE state
+        startSystem();
+        assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_AWAKE);
+        assertTrue(isAcquired[0]);
+
+        // Take a nap and verify we no longer hold the blocker
+        int flags = PowerManager.DOZE_WAKE_LOCK;
+        mService.getBinderServiceInstance().acquireWakeLock(token, flags, tag, packageName,
+                null /* workSource */, null /* historyTag */);
+        mService.getBinderServiceInstance().goToSleep(SystemClock.uptimeMillis(),
+                PowerManager.GO_TO_SLEEP_REASON_APPLICATION, 0);
+        assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_DOZING);
+        assertFalse(isAcquired[0]);
+
+        // Override the display state by DreamManager and verify is reacquires the blocker.
+        mService.getLocalServiceInstance()
+                .setDozeOverrideFromDreamManager(Display.STATE_ON, PowerManager.BRIGHTNESS_DEFAULT);
+        assertTrue(isAcquired[0]);
+    }
 }
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 f4a6231..4ffcf8f 100644
--- a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
@@ -39,6 +39,7 @@
 import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeTrue;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Matchers.anyInt;
 import static org.mockito.Mockito.doReturn;
@@ -297,9 +298,6 @@
         mInjector.setDisplayOn(true);
         setChargingState(controller, false);
         controller.checkIdleStates(USER_ID);
-        assertEquals(STANDBY_BUCKET_EXEMPTED,
-                controller.getAppStandbyBucket(PACKAGE_EXEMPTED_1, USER_ID,
-                        mInjector.mElapsedRealtime, false));
         assertNotEquals(STANDBY_BUCKET_EXEMPTED,
                 controller.getAppStandbyBucket(PACKAGE_1, USER_ID,
                         mInjector.mElapsedRealtime, false));
@@ -378,6 +376,14 @@
     }
 
     @Test
+    public void testBoundWidgetPackageExempt() throws Exception {
+        assumeTrue(mInjector.getContext().getSystemService(AppWidgetManager.class) != null);
+        assertEquals(STANDBY_BUCKET_EXEMPTED,
+                mController.getAppStandbyBucket(PACKAGE_EXEMPTED_1, USER_ID,
+                        mInjector.mElapsedRealtime, false));
+    }
+
+    @Test
     public void testCharging() throws Exception {
         long startTime;
         TestParoleListener paroleListener = new TestParoleListener();
diff --git a/services/tests/servicestests/test-apps/JobTestApp/Android.bp b/services/tests/servicestests/test-apps/JobTestApp/Android.bp
index ae1eca7..b29e187 100644
--- a/services/tests/servicestests/test-apps/JobTestApp/Android.bp
+++ b/services/tests/servicestests/test-apps/JobTestApp/Android.bp
@@ -17,8 +17,6 @@
 
     sdk_version: "current",
 
-    test_suites: ["device-tests"],
-
     srcs: ["**/*.java"],
 
     dex_preopt: {
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
index ecf3acd..ab2da2b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
@@ -98,7 +98,7 @@
             new DexmakerShareClassLoaderRule();
 
     final Context mContext = getInstrumentation().getTargetContext();
-    final TestInjector mTestInjector = new TestInjector();
+    final TestInjector mTestInjector = new TestInjector(mContext);
 
     ActivityTaskManagerService mService;
     RootActivityContainer mRootActivityContainer;
@@ -467,6 +467,7 @@
 
             spyOn(getLifecycleManager());
             spyOn(getLockTaskController());
+            spyOn(getTaskChangeNotificationController());
             doReturn(mock(IPackageManager.class)).when(this).getPackageManager();
             // allow background activity starts by default
             doReturn(true).when(this).isBackgroundActivityStartsEnabled();
@@ -567,9 +568,8 @@
     private static class TestInjector extends ActivityManagerService.Injector {
         private ServiceThread mHandlerThread;
 
-        @Override
-        public Context getContext() {
-            return getInstrumentation().getTargetContext();
+        TestInjector(Context context) {
+            super(context);
         }
 
         @Override
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
index f602418..d1dc382 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
@@ -207,7 +207,7 @@
         final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter(
                 runner, 100, 50, true /* changeNeedsSnapshot */);
         // RemoteAnimationController will tracking RemoteAnimationAdapter's caller with calling pid.
-        adapter.setCallingPid(123);
+        adapter.setCallingPidUid(123, 456);
 
         // Simulate activity finish flows to prepare app transition & set visibility,
         // make sure transition is set as expected.
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 c5e7c47..388658d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -756,7 +756,8 @@
         final ISystemGestureExclusionListener.Stub verifier =
                 new ISystemGestureExclusionListener.Stub() {
             @Override
-            public void onSystemGestureExclusionChanged(int displayId, Region actual) {
+            public void onSystemGestureExclusionChanged(int displayId, Region actual,
+                    Region unrestricted) {
                 Region expected = Region.obtain();
                 expected.set(10, 20, 30, 40);
                 assertEquals(expected, actual);
@@ -790,7 +791,14 @@
 
         final Region expected = Region.obtain();
         expected.set(20, 30, 40, 50);
-        assertEquals(expected, dc.calculateSystemGestureExclusion());
+        assertEquals(expected, calculateSystemGestureExclusion(dc));
+    }
+
+    private Region calculateSystemGestureExclusion(DisplayContent dc) {
+        Region out = Region.obtain();
+        Region unrestricted = Region.obtain();
+        dc.calculateSystemGestureExclusion(out, unrestricted);
+        return out;
     }
 
     @Test
@@ -814,7 +822,7 @@
         win2.setHasSurface(true);
 
         final Region expected = Region.obtain();
-        assertEquals(expected, dc.calculateSystemGestureExclusion());
+        assertEquals(expected, calculateSystemGestureExclusion(dc));
     }
 
     @Test
@@ -839,7 +847,7 @@
 
             final Region expected = Region.obtain();
             expected.set(dc.getBounds());
-            assertEquals(expected, dc.calculateSystemGestureExclusion());
+            assertEquals(expected, calculateSystemGestureExclusion(dc));
 
             win.setHasSurface(false);
         }
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
index a1999c90..b7a85d7 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
@@ -43,6 +43,8 @@
 import static org.junit.Assert.fail;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
 
 import static java.lang.Integer.MAX_VALUE;
 
@@ -900,6 +902,46 @@
                         true /* showRecents */));
     }
 
+    @Test
+    public void addTask_callsTaskNotificationController() {
+        final TaskRecord task = createTaskBuilder(".Task").build();
+
+        mRecentTasks.add(task);
+        mRecentTasks.remove(task);
+
+        TaskChangeNotificationController controller =
+                mTestService.getTaskChangeNotificationController();
+        verify(controller, times(2)).notifyTaskListUpdated();
+    }
+
+    @Test
+    public void removeTask_callsTaskNotificationController() {
+        final TaskRecord task = createTaskBuilder(".Task").build();
+
+        mRecentTasks.add(task);
+        mRecentTasks.remove(task);
+
+        // 2 calls - Once for add and once for remove
+        TaskChangeNotificationController controller =
+                mTestService.getTaskChangeNotificationController();
+        verify(controller, times(2)).notifyTaskListUpdated();
+    }
+
+    @Test
+    public void removeALlVisibleTask_callsTaskNotificationController_twice() {
+        final TaskRecord task1 = createTaskBuilder(".Task").build();
+        final TaskRecord task2 = createTaskBuilder(".Task2").build();
+
+        mRecentTasks.add(task1);
+        mRecentTasks.add(task2);
+        mRecentTasks.removeAllVisibleTasks(TEST_USER_0_ID);
+
+        // 4 calls - Twice for add and twice for remove
+        TaskChangeNotificationController controller =
+                mTestService.getTaskChangeNotificationController();
+        verify(controller, times(4)).notifyTaskListUpdated();
+    }
+
     /**
      * Ensures that the raw recent tasks list is in the provided order. Note that the expected tasks
      * should be ordered from least to most recent.
diff --git a/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
index cb74c3e..74791e2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
@@ -79,7 +79,7 @@
 
         when(mMockRunner.asBinder()).thenReturn(new Binder());
         mAdapter = new RemoteAnimationAdapter(mMockRunner, 100, 50, true /* changeNeedsSnapshot */);
-        mAdapter.setCallingPid(123);
+        mAdapter.setCallingPidUid(123, 456);
         mWm.mH.runWithScissors(() -> mHandler = new TestHandler(null, mClock), 0);
         mController = new RemoteAnimationController(mWm, mAdapter, mHandler);
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
index a7c84a1..8c56ffa 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
@@ -23,12 +23,18 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
 
 import android.content.pm.ApplicationInfo;
 import android.platform.test.annotations.Presubmit;
 
+import org.junit.Before;
 import org.junit.Test;
+import org.mockito.InOrder;
+import org.mockito.Mockito;
 
 /**
  * Tests for the {@link WindowProcessController} class.
@@ -39,43 +45,89 @@
 @Presubmit
 public class WindowProcessControllerTests extends ActivityTestsBase {
 
+    WindowProcessController mWpc;
+    WindowProcessListener mMockListener;
+
+    @Before
+    public void setUp() {
+        mMockListener = mock(WindowProcessListener.class);
+        mWpc = new WindowProcessController(
+                mService, mock(ApplicationInfo.class), null, 0, -1, null, mMockListener);
+    }
+
     @Test
     public void testDisplayConfigurationListener() {
-        final WindowProcessController wpc = new WindowProcessController(
-                        mService, mock(ApplicationInfo.class), null, 0, -1, null, null);
+
         //By default, the process should not listen to any display.
-        assertEquals(INVALID_DISPLAY, wpc.getDisplayId());
+        assertEquals(INVALID_DISPLAY, mWpc.getDisplayId());
 
         // Register to display 1 as a listener.
         TestActivityDisplay testActivityDisplay1 = createTestActivityDisplayInContainer();
-        wpc.registerDisplayConfigurationListenerLocked(testActivityDisplay1);
-        assertTrue(testActivityDisplay1.containsListener(wpc));
-        assertEquals(testActivityDisplay1.mDisplayId, wpc.getDisplayId());
+        mWpc.registerDisplayConfigurationListenerLocked(testActivityDisplay1);
+        assertTrue(testActivityDisplay1.containsListener(mWpc));
+        assertEquals(testActivityDisplay1.mDisplayId, mWpc.getDisplayId());
 
         // Move to display 2.
         TestActivityDisplay testActivityDisplay2 = createTestActivityDisplayInContainer();
-        wpc.registerDisplayConfigurationListenerLocked(testActivityDisplay2);
-        assertFalse(testActivityDisplay1.containsListener(wpc));
-        assertTrue(testActivityDisplay2.containsListener(wpc));
-        assertEquals(testActivityDisplay2.mDisplayId, wpc.getDisplayId());
+        mWpc.registerDisplayConfigurationListenerLocked(testActivityDisplay2);
+        assertFalse(testActivityDisplay1.containsListener(mWpc));
+        assertTrue(testActivityDisplay2.containsListener(mWpc));
+        assertEquals(testActivityDisplay2.mDisplayId, mWpc.getDisplayId());
 
         // Null ActivityDisplay will not change anything.
-        wpc.registerDisplayConfigurationListenerLocked(null);
-        assertTrue(testActivityDisplay2.containsListener(wpc));
-        assertEquals(testActivityDisplay2.mDisplayId, wpc.getDisplayId());
+        mWpc.registerDisplayConfigurationListenerLocked(null);
+        assertTrue(testActivityDisplay2.containsListener(mWpc));
+        assertEquals(testActivityDisplay2.mDisplayId, mWpc.getDisplayId());
 
         // Unregister listener will remove the wpc from registered displays.
-        wpc.unregisterDisplayConfigurationListenerLocked();
-        assertFalse(testActivityDisplay1.containsListener(wpc));
-        assertFalse(testActivityDisplay2.containsListener(wpc));
-        assertEquals(INVALID_DISPLAY, wpc.getDisplayId());
+        mWpc.unregisterDisplayConfigurationListenerLocked();
+        assertFalse(testActivityDisplay1.containsListener(mWpc));
+        assertFalse(testActivityDisplay2.containsListener(mWpc));
+        assertEquals(INVALID_DISPLAY, mWpc.getDisplayId());
 
         // Unregistration still work even if the display was removed.
-        wpc.registerDisplayConfigurationListenerLocked(testActivityDisplay1);
-        assertEquals(testActivityDisplay1.mDisplayId, wpc.getDisplayId());
+        mWpc.registerDisplayConfigurationListenerLocked(testActivityDisplay1);
+        assertEquals(testActivityDisplay1.mDisplayId, mWpc.getDisplayId());
         mRootActivityContainer.removeChild(testActivityDisplay1);
-        wpc.unregisterDisplayConfigurationListenerLocked();
-        assertEquals(INVALID_DISPLAY, wpc.getDisplayId());
+        mWpc.unregisterDisplayConfigurationListenerLocked();
+        assertEquals(INVALID_DISPLAY, mWpc.getDisplayId());
+    }
+
+    @Test
+    public void testSetRunningRecentsAnimation() {
+        mWpc.setRunningRecentsAnimation(true);
+        mWpc.setRunningRecentsAnimation(false);
+        mService.mH.runWithScissors(() -> {}, 0);
+
+        InOrder orderVerifier = Mockito.inOrder(mMockListener);
+        orderVerifier.verify(mMockListener).setRunningRemoteAnimation(eq(true));
+        orderVerifier.verify(mMockListener).setRunningRemoteAnimation(eq(false));
+    }
+
+    @Test
+    public void testSetRunningRemoteAnimation() {
+        mWpc.setRunningRemoteAnimation(true);
+        mWpc.setRunningRemoteAnimation(false);
+        mService.mH.runWithScissors(() -> {}, 0);
+
+        InOrder orderVerifier = Mockito.inOrder(mMockListener);
+        orderVerifier.verify(mMockListener).setRunningRemoteAnimation(eq(true));
+        orderVerifier.verify(mMockListener).setRunningRemoteAnimation(eq(false));
+    }
+
+    @Test
+    public void testSetRunningBothAnimations() {
+        mWpc.setRunningRemoteAnimation(true);
+        mWpc.setRunningRecentsAnimation(true);
+
+        mWpc.setRunningRecentsAnimation(false);
+        mWpc.setRunningRemoteAnimation(false);
+        mService.mH.runWithScissors(() -> {}, 0);
+
+        InOrder orderVerifier = Mockito.inOrder(mMockListener);
+        orderVerifier.verify(mMockListener, times(3)).setRunningRemoteAnimation(eq(true));
+        orderVerifier.verify(mMockListener, times(1)).setRunningRemoteAnimation(eq(false));
+        orderVerifier.verifyNoMoreInteractions();
     }
 
     private TestActivityDisplay createTestActivityDisplayInContainer() {
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 2298aa1..2bdeddf 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -830,6 +830,9 @@
                             mUserState.get(user).dumpDatabaseInfo(ipw);
                         }
                         return;
+                    } else if ("appstandby".equals(arg)) {
+                        mAppStandby.dumpState(args, pw);
+                        return;
                     } else if (arg != null && !arg.startsWith("-")) {
                         // Anything else that doesn't start with '-' is a pkg to filter
                         pkg = arg;
diff --git a/startop/view_compiler/Android.bp b/startop/view_compiler/Android.bp
index 92ea872..4f6524e 100644
--- a/startop/view_compiler/Android.bp
+++ b/startop/view_compiler/Android.bp
@@ -77,7 +77,6 @@
     name: "view-compiler-tests",
     defaults: ["viewcompiler_defaults"],
     srcs: [
-        "dex_builder_test.cc",
         "layout_validation_test.cc",
         "util_test.cc",
     ],
diff --git a/startop/view_compiler/dex_builder_test.cc b/startop/view_compiler/dex_builder_test.cc
deleted file mode 100644
index 90c256f..0000000
--- a/startop/view_compiler/dex_builder_test.cc
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "dex_builder.h"
-
-#include "dex/art_dex_file_loader.h"
-#include "dex/dex_file.h"
-#include "gtest/gtest.h"
-
-using namespace startop::dex;
-
-// Takes a DexBuilder, encodes it into an in-memory DEX file, verifies the resulting DEX file and
-// returns whether the verification was successful.
-bool EncodeAndVerify(DexBuilder* dex_file) {
-  slicer::MemView image{dex_file->CreateImage()};
-
-  art::ArtDexFileLoader loader;
-  std::string error_msg;
-  std::unique_ptr<const art::DexFile> loaded_dex_file{loader.Open(image.ptr<const uint8_t>(),
-                                                                  image.size(),
-                                                                  /*location=*/"",
-                                                                  /*location_checksum=*/0,
-                                                                  /*oat_dex_file=*/nullptr,
-                                                                  /*verify=*/true,
-                                                                  /*verify_checksum=*/false,
-                                                                  &error_msg)};
-  return loaded_dex_file != nullptr;
-}
-
-// Write out and verify a DEX file that corresponds to:
-//
-// package dextest;
-// public class DexTest {
-//     public static void foo() {}
-// }
-TEST(DexBuilderTest, VerifyDexWithClassMethod) {
-  DexBuilder dex_file;
-
-  auto cbuilder{dex_file.MakeClass("dextest.DexTest")};
-
-  auto method{cbuilder.CreateMethod("foo", Prototype{TypeDescriptor::Void()})};
-  method.BuildReturn();
-  method.Encode();
-
-  EXPECT_TRUE(EncodeAndVerify(&dex_file));
-}
-
-// Makes sure a bad DEX class fails to verify.
-TEST(DexBuilderTest, VerifyBadDexWithClassMethod) {
-  DexBuilder dex_file;
-
-  auto cbuilder{dex_file.MakeClass("dextest.DexTest")};
-
-  // This method has the error, because methods cannot take Void() as a parameter.
-  auto method{
-      cbuilder.CreateMethod("foo", Prototype{TypeDescriptor::Void(), TypeDescriptor::Void()})};
-  method.BuildReturn();
-  method.Encode();
-
-  EXPECT_FALSE(EncodeAndVerify(&dex_file));
-}
-
-// Write out and verify a DEX file that corresponds to:
-//
-// package dextest;
-// public class DexTest {
-//     public static int foo() { return 5; }
-// }
-TEST(DexBuilderTest, VerifyDexReturn5) {
-  DexBuilder dex_file;
-
-  auto cbuilder{dex_file.MakeClass("dextest.DexTest")};
-
-  auto method{cbuilder.CreateMethod("foo", Prototype{TypeDescriptor::Int()})};
-  auto r = method.MakeRegister();
-  method.BuildConst4(r, 5);
-  method.BuildReturn(r);
-  method.Encode();
-
-  EXPECT_TRUE(EncodeAndVerify(&dex_file));
-}
-
-// Write out and verify a DEX file that corresponds to:
-//
-// package dextest;
-// public class DexTest {
-//     public static int foo(int x) { return x; }
-// }
-TEST(DexBuilderTest, VerifyDexReturnIntParam) {
-  DexBuilder dex_file;
-
-  auto cbuilder{dex_file.MakeClass("dextest.DexTest")};
-
-  auto method{
-      cbuilder.CreateMethod("foo", Prototype{TypeDescriptor::Int(), TypeDescriptor::Int()})};
-  method.BuildReturn(Value::Parameter(0));
-  method.Encode();
-
-  EXPECT_TRUE(EncodeAndVerify(&dex_file));
-}
-
-// Write out and verify a DEX file that corresponds to:
-//
-// package dextest;
-// public class DexTest {
-//     public static int foo(String s) { return s.length(); }
-// }
-TEST(DexBuilderTest, VerifyDexCallStringLength) {
-  DexBuilder dex_file;
-
-  auto cbuilder{dex_file.MakeClass("dextest.DexTest")};
-
-  MethodBuilder method{cbuilder.CreateMethod(
-      "foo", Prototype{TypeDescriptor::Int(), TypeDescriptor::FromClassname("java.lang.String")})};
-
-  Value result = method.MakeRegister();
-
-  MethodDeclData string_length =
-      dex_file.GetOrDeclareMethod(TypeDescriptor::FromClassname("java.lang.String"),
-                                  "length",
-                                  Prototype{TypeDescriptor::Int()});
-
-  method.AddInstruction(Instruction::InvokeVirtual(string_length.id, result, Value::Parameter(0)));
-  method.BuildReturn(result);
-
-  method.Encode();
-
-  EXPECT_TRUE(EncodeAndVerify(&dex_file));
-}
-
-// Write out and verify a DEX file that corresponds to:
-//
-// package dextest;
-// public class DexTest {
-//     public static int foo(String s) { return s.length(); }
-// }
-TEST(DexBuilderTest, VerifyDexCallManyRegisters) {
-  DexBuilder dex_file;
-
-  auto cbuilder{dex_file.MakeClass("dextest.DexTest")};
-
-  MethodBuilder method{cbuilder.CreateMethod(
-      "foo", Prototype{TypeDescriptor::Int()})};
-
-  Value result = method.MakeRegister();
-
-  // Make a bunch of registers
-  for (size_t i = 0; i < 25; ++i) {
-    method.MakeRegister();
-  }
-
-  // Now load a string literal into a register
-  Value string_val = method.MakeRegister();
-  method.BuildConstString(string_val, "foo");
-
-  MethodDeclData string_length =
-      dex_file.GetOrDeclareMethod(TypeDescriptor::FromClassname("java.lang.String"),
-                                  "length",
-                                  Prototype{TypeDescriptor::Int()});
-
-  method.AddInstruction(Instruction::InvokeVirtual(string_length.id, result, string_val));
-  method.BuildReturn(result);
-
-  method.Encode();
-
-  EXPECT_TRUE(EncodeAndVerify(&dex_file));
-}
diff --git a/telephony/java/android/provider/Telephony.java b/telephony/java/android/provider/Telephony.java
index 17d725e..c4a9ee9 100644
--- a/telephony/java/android/provider/Telephony.java
+++ b/telephony/java/android/provider/Telephony.java
@@ -24,7 +24,6 @@
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
-import android.app.job.JobService;
 import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.ContentValues;
@@ -4102,9 +4101,11 @@
          * ServiceState provider.
          * <p>
          * Use this {@link Uri} with a {@link ContentObserver} to be notified of changes to the
-         * {@link ServiceState} while your app is running.  You can also use a {@link JobService} to
+         * {@link ServiceState} while your app is running.
+         * You can also use a {@link android.app.job.JobService} to
          * ensure your app is notified of changes to the {@link Uri} even when it is not running.
-         * Note, however, that using a {@link JobService} does not guarantee timely delivery of
+         * Note, however, that using a {@link android.app.job.JobService}
+         * does not guarantee timely delivery of
          * updates to the {@link Uri}.
          *
          * @param subscriptionId the subscriptionId to receive updates on
@@ -4121,9 +4122,11 @@
          * ServiceState provider.
          * <p>
          * Use this {@link Uri} with a {@link ContentObserver} to be notified of changes to the
-         * {@link ServiceState} while your app is running.  You can also use a {@link JobService} to
+         * {@link ServiceState} while your app is running.  You can also use a
+         * {@link android.app.job.JobService} to
          * ensure your app is notified of changes to the {@link Uri} even when it is not running.
-         * Note, however, that using a {@link JobService} does not guarantee timely delivery of
+         * Note, however, that using a {@link android.app.job.JobService}
+         * does not guarantee timely delivery of
          * updates to the {@link Uri}.
          *
          * @param subscriptionId the subscriptionId to receive updates on
@@ -4378,10 +4381,11 @@
          * <p>
          * Use this {@link Uri} with a {@link ContentObserver} to be notified of changes to the
          * carrier identity {@link TelephonyManager#getSimCarrierId()}
-         * while your app is running. You can also use a {@link JobService} to ensure your app
+         * while your app is running. You can also use a {@link android.app.job.JobService}
+         * to ensure your app
          * is notified of changes to the {@link Uri} even when it is not running.
-         * Note, however, that using a {@link JobService} does not guarantee timely delivery of
-         * updates to the {@link Uri}.
+         * Note, however, that using a {@link android.app.job.JobService} does not guarantee
+         * timely delivery of updates to the {@link Uri}.
          *
          * @param subscriptionId the subscriptionId to receive updates on
          * @return the Uri used to observe carrier identity changes
@@ -4399,10 +4403,11 @@
          * <p>
          * Use this {@link Uri} with a {@link ContentObserver} to be notified of changes to the
          * specific carrier identity {@link TelephonyManager#getSimSpecificCarrierId()}
-         * while your app is running. You can also use a {@link JobService} to ensure your app
+         * while your app is running. You can also use a {@link android.app.job.JobService}
+         * to ensure your app
          * is notified of changes to the {@link Uri} even when it is not running.
-         * Note, however, that using a {@link JobService} does not guarantee timely delivery of
-         * updates to the {@link Uri}.
+         * Note, however, that using a {@link android.app.job.JobService} does not guarantee timely
+         * delivery of updates to the {@link Uri}.
          *
          * @param subscriptionId the subscriptionId to receive updates on
          * @return the Uri used to observe specific carrier identity changes
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 292a294..66cc6eb 100755
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -468,6 +468,14 @@
             "notify_handover_video_from_wifi_to_lte_bool";
 
     /**
+     * Flag specifying whether the carrier supports merging a RTT call with a voice call,
+     * downgrading the call in the process.
+     * @hide
+     */
+    public static final String KEY_ALLOW_MERGING_RTT_CALLS_BOOL =
+             "allow_merging_rtt_calls_bool";
+
+    /**
      * Flag specifying whether the carrier wants to notify the user when a VT call has been handed
      * over from LTE to WIFI.
      * <p>
@@ -2718,12 +2726,20 @@
 
     /**
      * Controls hysteresis time in milli seconds for which OpportunisticNetworkService
-     * will wait before switching data to a network.
+     * will wait before switching data to an opportunistic network.
      */
     public static final String KEY_OPPORTUNISTIC_NETWORK_DATA_SWITCH_HYSTERESIS_TIME_LONG =
             "opportunistic_network_data_switch_hysteresis_time_long";
 
     /**
+     * Controls hysteresis time in milli seconds for which OpportunisticNetworkService
+     * will wait before switching data from opportunistic network to primary network.
+     * @hide
+     */
+    public static final String KEY_OPPORTUNISTIC_NETWORK_DATA_SWITCH_EXIT_HYSTERESIS_TIME_LONG =
+            "opportunistic_network_data_switch_exit_hysteresis_time_long";
+
+    /**
      * Indicates zero or more emergency number prefix(es), because some carrier requires
      * if users dial an emergency number address with a specific prefix, the combination of the
      * prefix and the address is also a valid emergency number to dial. For example, an emergency
@@ -2923,10 +2939,10 @@
 
     /**
      * Wi-Fi configs used in Carrier Wi-Fi application.
-     * TODO(b/132059890): Expose it in a future release as systemapi.
      *
      * @hide
      */
+    @SystemApi
     public static final class Wifi {
         /** Prefix of all Wifi.KEY_* constants. */
         public static final String KEY_PREFIX = "wifi.";
@@ -3113,6 +3129,7 @@
         sDefaults.putBoolean(KEY_CARRIER_VOLTE_AVAILABLE_BOOL, false);
         sDefaults.putBoolean(KEY_CARRIER_VT_AVAILABLE_BOOL, false);
         sDefaults.putBoolean(KEY_NOTIFY_HANDOVER_VIDEO_FROM_WIFI_TO_LTE_BOOL, false);
+        sDefaults.putBoolean(KEY_ALLOW_MERGING_RTT_CALLS_BOOL, false);
         sDefaults.putBoolean(KEY_NOTIFY_HANDOVER_VIDEO_FROM_LTE_TO_WIFI_BOOL, false);
         sDefaults.putBoolean(KEY_SUPPORT_DOWNGRADE_VT_TO_AUDIO_BOOL, true);
         sDefaults.putString(KEY_DEFAULT_VM_NUMBER_STRING, "");
@@ -3484,6 +3501,8 @@
         sDefaults.putLong(KEY_OPPORTUNISTIC_NETWORK_ENTRY_OR_EXIT_HYSTERESIS_TIME_LONG, 10000);
         /* Default value is 10 seconds. */
         sDefaults.putLong(KEY_OPPORTUNISTIC_NETWORK_DATA_SWITCH_HYSTERESIS_TIME_LONG, 10000);
+        /* Default value is 3 seconds. */
+        sDefaults.putLong(KEY_OPPORTUNISTIC_NETWORK_DATA_SWITCH_EXIT_HYSTERESIS_TIME_LONG, 3000);
         sDefaults.putAll(Gps.getDefaults());
         sDefaults.putAll(Wifi.getDefaults());
         sDefaults.putIntArray(KEY_CDMA_ENHANCED_ROAMING_INDICATOR_FOR_HOME_NETWORK_INT_ARRAY,
diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java
index b75e515..f03a9dc 100644
--- a/telephony/java/android/telephony/PhoneNumberUtils.java
+++ b/telephony/java/android/telephony/PhoneNumberUtils.java
@@ -22,9 +22,11 @@
 import com.android.i18n.phonenumbers.Phonenumber.PhoneNumber;
 
 import android.annotation.IntDef;
+import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.Intent;
+import android.content.res.Resources;
 import android.database.Cursor;
 import android.location.CountryDetector;
 import android.net.Uri;
@@ -164,6 +166,33 @@
         return c == 'w'||c == 'W';
     }
 
+    private static int sMinMatch = 0;
+
+    private static int getMinMatch() {
+        if (sMinMatch == 0) {
+            sMinMatch = Resources.getSystem().getInteger(
+                    com.android.internal.R.integer.config_phonenumber_compare_min_match);
+        }
+        return sMinMatch;
+    }
+
+    /**
+     * A Test API to get current sMinMatch.
+     * @hide
+     */
+    @TestApi
+    public static int getMinMatchForTest() {
+        return getMinMatch();
+    }
+
+    /**
+     * A Test API to set sMinMatch.
+     * @hide
+     */
+    @TestApi
+    public static void setMinMatchForTest(int minMatch) {
+        sMinMatch = minMatch;
+    }
 
     /** Returns true if ch is not dialable or alpha char */
     private static boolean isSeparator(char ch) {
@@ -475,7 +504,7 @@
      * enough for caller ID purposes.
      *
      * - Compares from right to left
-     * - requires MIN_MATCH (7) characters to match
+     * - requires minimum characters to match
      * - handles common trunk prefixes and international prefixes
      *   (basically, everything except the Russian trunk prefix)
      *
@@ -491,6 +520,7 @@
         int matched;
         int numNonDialableCharsInA = 0;
         int numNonDialableCharsInB = 0;
+        int minMatch = getMinMatch();
 
         if (a == null || b == null) return a == b;
 
@@ -530,12 +560,12 @@
             }
         }
 
-        if (matched < MIN_MATCH) {
+        if (matched < minMatch) {
             int effectiveALen = a.length() - numNonDialableCharsInA;
             int effectiveBLen = b.length() - numNonDialableCharsInB;
 
 
-            // if the number of dialable chars in a and b match, but the matched chars < MIN_MATCH,
+            // if the number of dialable chars in a and b match, but the matched chars < minMatch,
             // treat them as equal (i.e. 404-04 and 40404)
             if (effectiveALen == effectiveBLen && effectiveALen == matched) {
                 return true;
@@ -545,7 +575,7 @@
         }
 
         // At least one string has matched completely;
-        if (matched >= MIN_MATCH && (ia < 0 || ib < 0)) {
+        if (matched >= minMatch && (ia < 0 || ib < 0)) {
             return true;
         }
 
@@ -736,7 +766,7 @@
     }
 
     /**
-     * Returns the rightmost MIN_MATCH (5) characters in the network portion
+     * Returns the rightmost minimum matched characters in the network portion
      * in *reversed* order
      *
      * This can be used to do a database lookup against the column
@@ -747,7 +777,7 @@
     public static String
     toCallerIDMinMatch(String phoneNumber) {
         String np = extractNetworkPortionAlt(phoneNumber);
-        return internalGetStrippedReversed(np, MIN_MATCH);
+        return internalGetStrippedReversed(np, getMinMatch());
     }
 
     /**
@@ -1709,26 +1739,6 @@
         return normalizedDigits.toString();
     }
 
-    // Three and four digit phone numbers for either special services,
-    // or 3-6 digit addresses from the network (eg carrier-originated SMS messages) should
-    // not match.
-    //
-    // This constant used to be 5, but SMS short codes has increased in length and
-    // can be easily 6 digits now days. Most countries have SMS short code length between
-    // 3 to 6 digits. The exceptions are
-    //
-    // Australia: Short codes are six or eight digits in length, starting with the prefix "19"
-    //            followed by an additional four or six digits and two.
-    // Czechia: Codes are seven digits in length for MO and five (not billed) or
-    //            eight (billed) for MT direction
-    //
-    // see http://en.wikipedia.org/wiki/Short_code#Regional_differences for reference
-    //
-    // However, in order to loose match 650-555-1212 and 555-1212, we need to set the min match
-    // to 7.
-    @UnsupportedAppUsage
-    static final int MIN_MATCH = 7;
-
     /**
      * Checks a given number against the list of
      * emergency numbers provided by the RIL and SIM card.
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 2822fcc..8c53c51 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -34,7 +34,6 @@
 import android.annotation.UnsupportedAppUsage;
 import android.app.BroadcastOptions;
 import android.app.PendingIntent;
-import android.app.job.JobService;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageInfo;
@@ -147,10 +146,11 @@
      * <p>
      * Use this {@link Uri} with a {@link ContentObserver} to be notified of changes to the
      * subscription wfc enabled {@link ImsMmTelManager#isVoWiFiSettingEnabled()}
-     * while your app is running. You can also use a {@link JobService} to ensure your app
+     * while your app is running. You can also use a {@link android.app.job.JobService}
+     * to ensure your app
      * is notified of changes to the {@link Uri} even when it is not running.
-     * Note, however, that using a {@link JobService} does not guarantee timely delivery of
-     * updates to the {@link Uri}.
+     * Note, however, that using a {@link android.app.job.JobService} does not guarantee timely
+     * delivery of updates to the {@link Uri}.
      * To be notified of changes to a specific subId, append subId to the URI
      * {@link Uri#withAppendedPath(Uri, String)}.
      * @hide
@@ -166,10 +166,10 @@
      * Use this {@link Uri} with a {@link ContentObserver} to be notified of changes to the
      * subscription advanced calling enabled
      * {@link ImsMmTelManager#isAdvancedCallingSettingEnabled()} while your app is running.
-     * You can also use a {@link JobService} to ensure your app is notified of changes to the
-     * {@link Uri} even when it is not running.
-     * Note, however, that using a {@link JobService} does not guarantee timely delivery of
-     * updates to the {@link Uri}.
+     * You can also use a {@link android.app.job.JobService} to ensure your app is notified of
+     * changes to the {@link Uri} even when it is not running.
+     * Note, however, that using a {@link android.app.job.JobService} does not guarantee timely
+     * delivery of updates to the {@link Uri}.
      * To be notified of changes to a specific subId, append subId to the URI
      * {@link Uri#withAppendedPath(Uri, String)}.
      * @hide
@@ -184,10 +184,10 @@
      * <p>
      * Use this {@link Uri} with a {@link ContentObserver} to be notified of changes to the
      * subscription wfc mode {@link ImsMmTelManager#getVoWiFiModeSetting()}
-     * while your app is running. You can also use a {@link JobService} to ensure your app
-     * is notified of changes to the {@link Uri} even when it is not running.
-     * Note, however, that using a {@link JobService} does not guarantee timely delivery of
-     * updates to the {@link Uri}.
+     * while your app is running. You can also use a {@link android.app.job.JobService} to ensure
+     * your app is notified of changes to the {@link Uri} even when it is not running.
+     * Note, however, that using a {@link android.app.job.JobService} does not guarantee timely
+     * delivery of updates to the {@link Uri}.
      * To be notified of changes to a specific subId, append subId to the URI
      * {@link Uri#withAppendedPath(Uri, String)}.
      * @hide
@@ -201,10 +201,10 @@
      * <p>
      * Use this {@link Uri} with a {@link ContentObserver} to be notified of changes to the
      * subscription wfc roaming mode {@link ImsMmTelManager#getVoWiFiRoamingModeSetting()}
-     * while your app is running. You can also use a {@link JobService} to ensure your app
-     * is notified of changes to the {@link Uri} even when it is not running.
-     * Note, however, that using a {@link JobService} does not guarantee timely delivery of
-     * updates to the {@link Uri}.
+     * while your app is running. You can also use a {@link android.app.job.JobService}
+     * to ensure your app is notified of changes to the {@link Uri} even when it is not running.
+     * Note, however, that using a {@link android.app.job.JobService} does not guarantee timely
+     * delivery of updates to the {@link Uri}.
      * To be notified of changes to a specific subId, append subId to the URI
      * {@link Uri#withAppendedPath(Uri, String)}.
      * @hide
@@ -220,10 +220,10 @@
      * <p>
      * Use this {@link Uri} with a {@link ContentObserver} to be notified of changes to the
      * subscription vt enabled {@link ImsMmTelManager#isVtSettingEnabled()}
-     * while your app is running. You can also use a {@link JobService} to ensure your app
-     * is notified of changes to the {@link Uri} even when it is not running.
-     * Note, however, that using a {@link JobService} does not guarantee timely delivery of
-     * updates to the {@link Uri}.
+     * while your app is running. You can also use a {@link android.app.job.JobService} to ensure
+     * your app is notified of changes to the {@link Uri} even when it is not running.
+     * Note, however, that using a {@link android.app.job.JobService} does not guarantee timely
+     * delivery of updates to the {@link Uri}.
      * To be notified of changes to a specific subId, append subId to the URI
      * {@link Uri#withAppendedPath(Uri, String)}.
      * @hide
@@ -238,10 +238,10 @@
      * <p>
      * Use this {@link Uri} with a {@link ContentObserver} to be notified of changes to the
      * subscription wfc roaming enabled {@link ImsMmTelManager#isVoWiFiRoamingSettingEnabled()}
-     * while your app is running. You can also use a {@link JobService} to ensure your app
-     * is notified of changes to the {@link Uri} even when it is not running.
-     * Note, however, that using a {@link JobService} does not guarantee timely delivery of
-     * updates to the {@link Uri}.
+     * while your app is running. You can also use a {@link android.app.job.JobService} to ensure
+     * your app is notified of changes to the {@link Uri} even when it is not running.
+     * Note, however, that using a {@link android.app.job.JobService} does not guarantee timely
+     * delivery of updates to the {@link Uri}.
      * To be notified of changes to a specific subId, append subId to the URI
      * {@link Uri#withAppendedPath(Uri, String)}.
      * @hide
diff --git a/telephony/java/android/telephony/emergency/EmergencyNumber.java b/telephony/java/android/telephony/emergency/EmergencyNumber.java
index 511adf6..19d0724 100644
--- a/telephony/java/android/telephony/emergency/EmergencyNumber.java
+++ b/telephony/java/android/telephony/emergency/EmergencyNumber.java
@@ -22,6 +22,7 @@
 import android.hardware.radio.V1_4.EmergencyServiceCategory;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.telephony.CarrierConfigManager;
 import android.telephony.PhoneNumberUtils;
 import android.telephony.Rlog;
 
@@ -301,6 +302,9 @@
      * The character in the number string is only the dial pad
      * character('0'-'9', '*', '+', or '#'). For example: 911.
      *
+     * If the number starts with carrier prefix, the carrier prefix is configured in
+     * {@link CarrierConfigManager#KEY_EMERGENCY_NUMBER_PREFIX_STRING_ARRAY}.
+     *
      * @return the dialing number.
      */
     public @NonNull String getNumber() {
diff --git a/telephony/java/android/telephony/ims/feature/ImsFeature.java b/telephony/java/android/telephony/ims/feature/ImsFeature.java
index 3bec8b0..8f89899 100644
--- a/telephony/java/android/telephony/ims/feature/ImsFeature.java
+++ b/telephony/java/android/telephony/ims/feature/ImsFeature.java
@@ -34,7 +34,9 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.Iterator;
+import java.util.Map;
 import java.util.Set;
 import java.util.WeakHashMap;
 
@@ -106,6 +108,16 @@
     public static final int FEATURE_MAX = 3;
 
     /**
+     * Used for logging purposes.
+     * @hide
+     */
+    public static final Map<Integer, String> FEATURE_LOG_MAP = new HashMap<Integer, String>() {{
+            put(FEATURE_EMERGENCY_MMTEL, "EMERGENCY_MMTEL");
+            put(FEATURE_MMTEL, "MMTEL");
+            put(FEATURE_RCS, "RCS");
+        }};
+
+    /**
      * Integer values defining IMS features that are supported in ImsFeature.
      * @hide
      */
@@ -150,6 +162,16 @@
     public static final int STATE_READY = 2;
 
     /**
+     * Used for logging purposes.
+     * @hide
+     */
+    public static final Map<Integer, String> STATE_LOG_MAP = new HashMap<Integer, String>() {{
+            put(STATE_UNAVAILABLE, "UNAVAILABLE");
+            put(STATE_INITIALIZING, "INITIALIZING");
+            put(STATE_READY, "READY");
+        }};
+
+    /**
      * Integer values defining the result codes that should be returned from
      * {@link #changeEnabledCapabilities} when the framework tries to set a feature's capability.
      * @hide
diff --git a/telephony/java/android/telephony/ims/stub/ImsFeatureConfiguration.java b/telephony/java/android/telephony/ims/stub/ImsFeatureConfiguration.java
index 6ab9465..3b298bb 100644
--- a/telephony/java/android/telephony/ims/stub/ImsFeatureConfiguration.java
+++ b/telephony/java/android/telephony/ims/stub/ImsFeatureConfiguration.java
@@ -21,7 +21,6 @@
 import android.os.Parcelable;
 import android.telephony.ims.feature.ImsFeature;
 import android.util.ArraySet;
-import android.util.Pair;
 
 import java.util.Set;
 
@@ -80,7 +79,7 @@
 
         @Override
         public String toString() {
-            return "{s=" + slotId + ", f=" + featureType + "}";
+            return "{s=" + slotId + ", f=" + ImsFeature.FEATURE_LOG_MAP.get(featureType) + "}";
         }
     }
 
diff --git a/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java b/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
index af993be..e9a177d 100644
--- a/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
+++ b/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
@@ -115,7 +115,7 @@
             final Context otherContext;
             try {
                 otherContext = context.createPackageContextAsUser(context.getPackageName(),
-                        /* flags =*/ 0, new UserHandle(currentUser));
+                        /* flags =*/ 0, UserHandle.of(currentUser));
                 return otherContext.getContentResolver();
             } catch (NameNotFoundException e) {
                 Rlog.e(LOG_TAG, "Can't find self package", e);
diff --git a/telephony/java/com/android/internal/telephony/CarrierAppUtils.java b/telephony/java/com/android/internal/telephony/CarrierAppUtils.java
index 6498e49..0d4fd0f 100644
--- a/telephony/java/com/android/internal/telephony/CarrierAppUtils.java
+++ b/telephony/java/com/android/internal/telephony/CarrierAppUtils.java
@@ -21,6 +21,7 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
+import android.content.res.Resources;
 import android.os.RemoteException;
 import android.permission.IPermissionManager;
 import android.provider.Settings;
@@ -29,7 +30,9 @@
 import android.util.ArraySet;
 import android.util.Slog;
 
+import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.ArrayUtils;
 import com.android.server.SystemConfig;
 
 import java.util.ArrayList;
@@ -143,9 +146,12 @@
         try {
             for (ApplicationInfo ai : candidates) {
                 String packageName = ai.packageName;
-                boolean hasPrivileges = telephonyManager != null &&
-                        telephonyManager.checkCarrierPrivilegesForPackageAnyPhone(packageName) ==
-                                TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS;
+                String[] restrictedCarrierApps = Resources.getSystem().getStringArray(
+                        R.array.config_restrictedPreinstalledCarrierApps);
+                boolean hasPrivileges = telephonyManager != null
+                        && telephonyManager.checkCarrierPrivilegesForPackageAnyPhone(packageName)
+                                == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS
+                        && !ArrayUtils.contains(restrictedCarrierApps, packageName);
 
                 // add hiddenUntilInstalled flag for carrier apps and associated apps
                 packageManager.setSystemAppHiddenUntilInstalled(packageName, true);
diff --git a/telephony/java/com/android/internal/telephony/SmsApplication.java b/telephony/java/com/android/internal/telephony/SmsApplication.java
index 6df5457..62d3536 100644
--- a/telephony/java/com/android/internal/telephony/SmsApplication.java
+++ b/telephony/java/com/android/internal/telephony/SmsApplication.java
@@ -300,7 +300,7 @@
                 Uri.fromParts(SCHEME_SMSTO, "", null));
         List<ResolveInfo> respondServices = packageManager.queryIntentServicesAsUser(intent,
                 PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
-                UserHandle.getUserHandleForUid(userId));
+                UserHandle.of(userId));
         for (ResolveInfo resolveInfo : respondServices) {
             final ServiceInfo serviceInfo = resolveInfo.serviceInfo;
             if (serviceInfo == null) {
@@ -806,7 +806,7 @@
             if (userId != UserHandle.USER_SYSTEM) {
                 try {
                     userContext = mContext.createPackageContextAsUser(mContext.getPackageName(), 0,
-                            new UserHandle(userId));
+                        UserHandle.of(userId));
                 } catch (NameNotFoundException nnfe) {
                     if (DEBUG_MULTIUSER) {
                         Log.w(LOG_TAG, "Unable to create package context for user " + userId);
diff --git a/tests/Codegen/runTest.sh b/tests/Codegen/runTest.sh
index bc1aae0..614cbb7 100755
--- a/tests/Codegen/runTest.sh
+++ b/tests/Codegen/runTest.sh
@@ -12,6 +12,7 @@
 
     header_and_eval m -j16 codegen_cli && \
         header_and_eval codegen $ANDROID_BUILD_TOP/frameworks/base/tests/Codegen/src/com/android/codegentest/SampleDataClass.java && \
+        header_and_eval codegen $ANDROID_BUILD_TOP/frameworks/base/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java && \
         cd $ANDROID_BUILD_TOP &&
         header_and_eval mmma -j16 frameworks/base/tests/Codegen && \
         header_and_eval adb install -r -t $ANDROID_PRODUCT_OUT/testcases/CodegenTests/arm64/CodegenTests.apk && \
diff --git a/tests/Codegen/src/com/android/codegentest/DateParcelling.java b/tests/Codegen/src/com/android/codegentest/MyDateParcelling.java
similarity index 94%
rename from tests/Codegen/src/com/android/codegentest/DateParcelling.java
rename to tests/Codegen/src/com/android/codegentest/MyDateParcelling.java
index b0b00d0..4faeb8e 100644
--- a/tests/Codegen/src/com/android/codegentest/DateParcelling.java
+++ b/tests/Codegen/src/com/android/codegentest/MyDateParcelling.java
@@ -31,11 +31,11 @@
  *
  * Ignore {@link #sInstanceCount} - used for testing.
  */
-public class DateParcelling implements Parcelling<Date> {
+public class MyDateParcelling implements Parcelling<Date> {
 
     static AtomicInteger sInstanceCount = new AtomicInteger(0);
 
-    public DateParcelling() {
+    public MyDateParcelling() {
         sInstanceCount.getAndIncrement();
     }
 
diff --git a/tests/Codegen/src/com/android/codegentest/SampleDataClass.java b/tests/Codegen/src/com/android/codegentest/SampleDataClass.java
index f69a092..30bb3ef 100644
--- a/tests/Codegen/src/com/android/codegentest/SampleDataClass.java
+++ b/tests/Codegen/src/com/android/codegentest/SampleDataClass.java
@@ -53,11 +53,13 @@
 //        genAidl = true,       // implied by `implements Parcelable`
 //        genGetters = true,    // on by default
 //        genConstDefs = true,  // implied by presence of constants with common prefix
+        genBuilder = true,      // on by default if optional fields present, but suppressed by
+                                // genConstructor
+        genConstructor = true,  // on by default but normally suppressed by genBuilder
         genEqualsHashCode = true,
-        genBuilder = true,
         genToString = true,
         genForEachField = true,
-        genConstructor = true   // on by default but normally suppressed by genBuilder
+        genSetters = true
 )
 public final class SampleDataClass implements Parcelable {
 
@@ -136,48 +138,53 @@
     private int mNum4;
 
     /**
-     * {@link Nullable} fields are considered optional and will not throw an exception if omitted
-     * (or set to null) when creating an instance either via a {@link Builder} or constructor.
+     * {@link Nullable} or {@link NonNull} annotation is required on all non-primitive fields.
      */
     private @Nullable String mName;
     /**
-     * Fields with default value expressions ("mFoo = ...") are also optional, and are automatically
+     * Fields with default value expressions ("mFoo = ...") are optional, and are automatically
      * initialized to the provided default expression, unless explicitly set.
-     */
-    private String mName2 = "Bob";
-    /**
-     * Fields without {@link Nullable} annotation or default value are considered required.
      *
-     * {@link NonNull} annotation is recommended on such non-primitive fields for documentation.
+     * When using a {@link Builder} optional fields are passed via a {@link Builder#setName2 setter}
+     * while mandatory fields are passed via {@link Builder#Builder constructor}.
+     */
+    private @NonNull String mName2 = "Bob";
+    /**
+     * Alternatively, when default value computation is expensive,
+     * {@link #defaultName4 defaultFieldName()} can be defined to compute the default value.
      */
     private @NonNull String mName4;
+    private static String defaultName4() {
+        // Expensive computation
+        return "Bob4";
+    }
 
     /**
      * For parcelling, any field type supported by {@link Parcel} is supported out of the box.
      * E.g. {@link Parcelable} subclasses, {@link String}, {@link int}, {@link boolean}, etc.
      */
-    private AccessibilityNodeInfo mOtherParcelable = null;
+    private @Nullable AccessibilityNodeInfo mOtherParcelable = null;
     /**
      * Additionally, support for parcelling other types can be added by implementing a
      * {@link Parcelling}, and referencing it in the {@link DataClass.ParcelWith} field annotation.
      *
-     * @see DateParcelling an example {@link Parcelling} implementation
+     * @see MyDateParcelling an example {@link Parcelling} implementation
      */
-    @DataClass.ParcelWith(DateParcelling.class)
-    private Date mDate = new Date(42 * 42);
+    @DataClass.ParcelWith(MyDateParcelling.class)
+    private @NonNull Date mDate = new Date(42 * 42);
     /**
      * If a {@link Parcelling} is fairly common, consider putting it in {@link Parcelling.BuiltIn}
      * to encourage its reuse.
      */
     @DataClass.ParcelWith(Parcelling.BuiltIn.ForPattern.class)
-    private Pattern mPattern = Pattern.compile("");
+    private @NonNull Pattern mPattern = Pattern.compile("");
 
     /**
      * For lists, when using a {@link Builder}, other than a regular
      * {@link Builder#setLinkAddresses2(List) setter}, and additional
      * {@link Builder#addLinkAddresses2(LinkAddress) add} method is generated for convenience.
      */
-    private List<LinkAddress> mLinkAddresses2 = new ArrayList<>();
+    private @NonNull List<LinkAddress> mLinkAddresses2 = new ArrayList<>();
     /**
      * For aesthetics, you may want to consider providing a singular version of the plural field
      * name, which would be used for the {@link #mLinkAddresses2 above mentioned} "add" method.
@@ -185,7 +192,7 @@
      * @see Builder#addLinkAddress(LinkAddress)
      */
     @DataClass.PluralOf("linkAddress")
-    private ArrayList<LinkAddress> mLinkAddresses = new ArrayList<>();
+    private @NonNull ArrayList<LinkAddress> mLinkAddresses = new ArrayList<>();
     /**
      * For array fields, when using a {@link Builder}, vararg argument format is used for
      * convenience.
@@ -193,11 +200,6 @@
      * @see Builder#setLinkAddresses4(LinkAddress...)
      */
     private @Nullable LinkAddress[] mLinkAddresses4 = null;
-    /**
-     * For boolean fields, when using a {@link Builder}, in addition to a regular setter, methods
-     * like {@link Builder#markActive()} and {@link Builder#markNotActive()} are generated.
-     */
-    private boolean mActive = true;
 
     /**
      * {@link IntDef}/{@link StringDef}-annotated fields propagate the annotation to
@@ -206,7 +208,7 @@
      * @see #getStateName
      * @see Builder#setStateName
      */
-    private @StateName String mStateName = STATE_NAME_UNDEFINED;
+    private @StateName @NonNull String mStateName = STATE_NAME_UNDEFINED;
     /**
      * Fields annotated with {@link IntDef} annotations also get a proper {@link #toString()} value.
      */
@@ -220,11 +222,11 @@
     /**
      * Making a field public will suppress getter generation in favor of accessing it directly.
      */
-    public CharSequence charSeq = "";
+    public @NonNull CharSequence charSeq = "";
     /**
      * Final fields suppress generating a setter (when setters are requested).
      */
-    private final LinkAddress[] mLinkAddresses5;
+    private final @Nullable LinkAddress[] mLinkAddresses5;
     /**
      * Transient fields are completely ignored and can be used for caching.
      */
@@ -261,7 +263,7 @@
      *
      * @see AnnotationValidations#validate(Class, Size, int, String, int, String, int)
      */
-    private @android.annotation.IntRange(from = 0, to = 4) int mLimited = 3;
+    private @android.annotation.IntRange(from = 0, to = 6) int mDayOfWeek = 3;
     /**
      * Unnamed validation annotation parameter gets supplied to the validating method named as
      * "value".
@@ -272,6 +274,7 @@
      * @see AnnotationValidations#validate(Class, Size, int, String, int)
      */
     @Size(2)
+    @NonNull
     @Each @FloatRange(from = 0f)
     private float[] mCoords = new float[] {0f, 0f};
 
@@ -340,7 +343,6 @@
 
 
     // Code below generated by codegen v1.0.0.
-    //   on Jul 29, 2019, 2:50:21 PM PDT
     //
     // DO NOT MODIFY!
     //
@@ -408,13 +410,9 @@
     @DataClass.Generated.Member
     public @interface StateName {}
 
-    @DataClass.Generated(
-            time = 1564437021513L,
-            codegenVersion = "1.0.0",
-            sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/SampleDataClass.java",
-            inputSignatures = "public static final  java.lang.String STATE_NAME_UNDEFINED\npublic static final  java.lang.String STATE_NAME_ON\npublic static final  java.lang.String STATE_NAME_OFF\npublic static final  int STATE_UNDEFINED\npublic static final  int STATE_ON\npublic static final  int STATE_OFF\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_MANUAL_REQUEST\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_COMPATIBILITY_MODE_REQUEST\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_AUGMENTED_REQUEST\nprivate  int mNum\nprivate  int mNum2\nprivate  int mNum4\nprivate @android.annotation.Nullable java.lang.String mName\nprivate  java.lang.String mName2\nprivate @android.annotation.NonNull java.lang.String mName4\nprivate  android.view.accessibility.AccessibilityNodeInfo mOtherParcelable\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.codegentest.DateParcelling.class) java.util.Date mDate\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForPattern.class) java.util.regex.Pattern mPattern\nprivate  java.util.List<android.net.LinkAddress> mLinkAddresses2\nprivate @com.android.internal.util.DataClass.PluralOf(\"linkAddress\") java.util.ArrayList<android.net.LinkAddress> mLinkAddresses\nprivate @android.annotation.Nullable android.net.LinkAddress[] mLinkAddresses4\nprivate  boolean mActive\nprivate @com.android.codegentest.SampleDataClass.StateName java.lang.String mStateName\nprivate @com.android.codegentest.SampleDataClass.RequestFlags int mFlags\nprivate @com.android.codegentest.SampleDataClass.State int mState\npublic  java.lang.CharSequence charSeq\nprivate final  android.net.LinkAddress[] mLinkAddresses5\nprivate transient  android.net.LinkAddress[] mLinkAddresses6\ntransient  int[] mTmpStorage\nprivate @android.annotation.StringRes int mStringRes\nprivate @android.annotation.IntRange(from=0L, to=4L) int mLimited\nprivate @android.annotation.Size(2L) @com.android.internal.util.DataClass.Each @android.annotation.FloatRange(from=0.0) float[] mCoords\nprivate  int[] lazyInitTmpStorage()\npublic  android.net.LinkAddress[] getLinkAddresses4()\nprivate  boolean patternEquals(java.util.regex.Pattern)\nprivate  int patternHashCode()\nprivate  void onConstructed()\npublic  void dump(java.io.PrintWriter)")
-
-/**
+    /**
+     * Creates a new SampleDataClass.
+     *
      * @param num
      *   Any property javadoc should go onto the field, and will be copied where appropriate,
      *   including getters, constructor parameters, builder setters, etc.
@@ -429,15 +427,16 @@
      *   {@code @hide} javadoc annotation is also propagated, which can be used to adjust the
      *   desired public API surface.
      * @param name
-     *   {@link Nullable} fields are considered optional and will not throw an exception if omitted
-     *   (or set to null) when creating an instance either via a {@link Builder} or constructor.
+     *   {@link Nullable} or {@link NonNull} annotation is required on all non-primitive fields.
      * @param name2
-     *   Fields with default value expressions ("mFoo = ...") are also optional, and are automatically
+     *   Fields with default value expressions ("mFoo = ...") are optional, and are automatically
      *   initialized to the provided default expression, unless explicitly set.
-     * @param name4
-     *   Fields without {@link Nullable} annotation or default value are considered required.
      *
-     *   {@link NonNull} annotation is recommended on such non-primitive fields for documentation.
+     *   When using a {@link Builder} optional fields are passed via a {@link Builder#setName2 setter}
+     *   while mandatory fields are passed via {@link Builder#Builder constructor}.
+     * @param name4
+     *   Alternatively, when default value computation is expensive,
+     *   {@link #defaultName4 defaultFieldName()} can be defined to compute the default value.
      * @param otherParcelable
      *   For parcelling, any field type supported by {@link Parcel} is supported out of the box.
      *   E.g. {@link Parcelable} subclasses, {@link String}, {@link int}, {@link boolean}, etc.
@@ -457,9 +456,6 @@
      * @param linkAddresses4
      *   For array fields, when using a {@link Builder}, vararg argument format is used for
      *   convenience.
-     * @param active
-     *   For boolean fields, when using a {@link Builder}, in addition to a regular setter, methods
-     *   like {@link Builder#markActive()} and {@link Builder#markNotActive()} are generated.
      * @param stateName
      *   {@link IntDef}/{@link StringDef}-annotated fields propagate the annotation to
      *   getter/constructor/setter/builder parameters, making for a nicer api.
@@ -480,7 +476,7 @@
      *   You can also extend support to your custom annotations by creating another corresponding
      *   overloads like
      *   {@link AnnotationValidations#validate(Class, UserIdInt, int)}.
-     * @param limited
+     * @param dayOfWeek
      *   Validation annotations may also have parameters.
      *
      *   Parameter values will be supplied to validation method as name-value pairs.
@@ -497,50 +493,49 @@
             int num2,
             int num4,
             @Nullable String name,
-            String name2,
+            @NonNull String name2,
             @NonNull String name4,
-            AccessibilityNodeInfo otherParcelable,
-            Date date,
-            Pattern pattern,
-            List<LinkAddress> linkAddresses2,
-            ArrayList<LinkAddress> linkAddresses,
+            @Nullable AccessibilityNodeInfo otherParcelable,
+            @NonNull Date date,
+            @NonNull Pattern pattern,
+            @NonNull List<LinkAddress> linkAddresses2,
+            @NonNull ArrayList<LinkAddress> linkAddresses,
             @Nullable LinkAddress[] linkAddresses4,
-            boolean active,
-            @StateName String stateName,
+            @StateName @NonNull String stateName,
             @RequestFlags int flags,
             @State int state,
-            CharSequence charSeq,
-            LinkAddress[] linkAddresses5,
+            @NonNull CharSequence charSeq,
+            @Nullable LinkAddress[] linkAddresses5,
             @StringRes int stringRes,
-            @android.annotation.IntRange(from = 0, to = 4) int limited,
-            @Size(2) @FloatRange(from = 0f) float[] coords) {
+            @android.annotation.IntRange(from = 0, to = 6) int dayOfWeek,
+            @Size(2) @NonNull @Each @FloatRange(from = 0f) float[] coords) {
         this.mNum = num;
         this.mNum2 = num2;
         this.mNum4 = num4;
         this.mName = name;
         this.mName2 = name2;
-        this.mName4 = Preconditions.checkNotNull(name4);
-        this.mOtherParcelable = otherParcelable;
-        this.mDate = date;
-        this.mPattern = pattern;
-        this.mLinkAddresses2 = linkAddresses2;
-        this.mLinkAddresses = linkAddresses;
-        this.mLinkAddresses4 = linkAddresses4;
-        this.mActive = active;
-        this.mStateName = stateName;
-        this.mFlags = flags;
-        this.mState = state;
-        this.charSeq = charSeq;
-        this.mLinkAddresses5 = linkAddresses5;
-        this.mStringRes = stringRes;
-        this.mLimited = limited;
-        this.mCoords = coords;
+        AnnotationValidations.validate(
+                NonNull.class, null, mName2);
+        this.mName4 = name4;
         AnnotationValidations.validate(
                 NonNull.class, null, mName4);
+        this.mOtherParcelable = otherParcelable;
+        this.mDate = date;
+        AnnotationValidations.validate(
+                NonNull.class, null, mDate);
+        this.mPattern = pattern;
+        AnnotationValidations.validate(
+                NonNull.class, null, mPattern);
+        this.mLinkAddresses2 = linkAddresses2;
+        AnnotationValidations.validate(
+                NonNull.class, null, mLinkAddresses2);
+        this.mLinkAddresses = linkAddresses;
+        AnnotationValidations.validate(
+                NonNull.class, null, mLinkAddresses);
+        this.mLinkAddresses4 = linkAddresses4;
+        this.mStateName = stateName;
 
-        //noinspection PointlessBooleanExpression
-        if (true
-                && !(Objects.equals(mStateName, STATE_NAME_UNDEFINED))
+        if (!(Objects.equals(mStateName, STATE_NAME_UNDEFINED))
                 && !(Objects.equals(mStateName, STATE_NAME_ON))
                 && !(Objects.equals(mStateName, STATE_NAME_OFF))) {
             throw new java.lang.IllegalArgumentException(
@@ -550,17 +545,18 @@
                             + "STATE_NAME_OFF(" + STATE_NAME_OFF + ")");
         }
 
+        AnnotationValidations.validate(
+                NonNull.class, null, mStateName);
+        this.mFlags = flags;
 
-        //noinspection PointlessBitwiseExpression
         Preconditions.checkFlagsArgument(
-                mFlags, 0
-                        | FLAG_MANUAL_REQUEST
+                mFlags,
+                FLAG_MANUAL_REQUEST
                         | FLAG_COMPATIBILITY_MODE_REQUEST
                         | FLAG_AUGMENTED_REQUEST);
+        this.mState = state;
 
-        //noinspection PointlessBooleanExpression
-        if (true
-                && !(mState == STATE_UNDEFINED)
+        if (!(mState == STATE_UNDEFINED)
                 && !(mState == STATE_ON)
                 && !(mState == STATE_OFF)) {
             throw new java.lang.IllegalArgumentException(
@@ -570,15 +566,24 @@
                             + "STATE_OFF(" + STATE_OFF + ")");
         }
 
+        this.charSeq = charSeq;
+        AnnotationValidations.validate(
+                NonNull.class, null, charSeq);
+        this.mLinkAddresses5 = linkAddresses5;
+        this.mStringRes = stringRes;
         AnnotationValidations.validate(
                 StringRes.class, null, mStringRes);
+        this.mDayOfWeek = dayOfWeek;
         AnnotationValidations.validate(
-                android.annotation.IntRange.class, null, mLimited,
+                android.annotation.IntRange.class, null, mDayOfWeek,
                 "from", 0,
-                "to", 4);
+                "to", 6);
+        this.mCoords = coords;
         AnnotationValidations.validate(
                 Size.class, null, mCoords.length,
                 "value", 2);
+        AnnotationValidations.validate(
+                NonNull.class, null, mCoords);
         int coordsSize = mCoords.length;
         for (int i = 0; i < coordsSize; i++) {
             AnnotationValidations.validate(
@@ -628,8 +633,7 @@
     }
 
     /**
-     * {@link Nullable} fields are considered optional and will not throw an exception if omitted
-     * (or set to null) when creating an instance either via a {@link Builder} or constructor.
+     * {@link Nullable} or {@link NonNull} annotation is required on all non-primitive fields.
      */
     @DataClass.Generated.Member
     public @Nullable String getName() {
@@ -637,18 +641,20 @@
     }
 
     /**
-     * Fields with default value expressions ("mFoo = ...") are also optional, and are automatically
+     * Fields with default value expressions ("mFoo = ...") are optional, and are automatically
      * initialized to the provided default expression, unless explicitly set.
+     *
+     * When using a {@link Builder} optional fields are passed via a {@link Builder#setName2 setter}
+     * while mandatory fields are passed via {@link Builder#Builder constructor}.
      */
     @DataClass.Generated.Member
-    public String getName2() {
+    public @NonNull String getName2() {
         return mName2;
     }
 
     /**
-     * Fields without {@link Nullable} annotation or default value are considered required.
-     *
-     * {@link NonNull} annotation is recommended on such non-primitive fields for documentation.
+     * Alternatively, when default value computation is expensive,
+     * {@link #defaultName4 defaultFieldName()} can be defined to compute the default value.
      */
     @DataClass.Generated.Member
     public @NonNull String getName4() {
@@ -660,7 +666,7 @@
      * E.g. {@link Parcelable} subclasses, {@link String}, {@link int}, {@link boolean}, etc.
      */
     @DataClass.Generated.Member
-    public AccessibilityNodeInfo getOtherParcelable() {
+    public @Nullable AccessibilityNodeInfo getOtherParcelable() {
         return mOtherParcelable;
     }
 
@@ -668,10 +674,10 @@
      * Additionally, support for parcelling other types can be added by implementing a
      * {@link Parcelling}, and referencing it in the {@link DataClass.ParcelWith} field annotation.
      *
-     * @see DateParcelling an example {@link Parcelling} implementation
+     * @see MyDateParcelling an example {@link Parcelling} implementation
      */
     @DataClass.Generated.Member
-    public Date getDate() {
+    public @NonNull Date getDate() {
         return mDate;
     }
 
@@ -680,7 +686,7 @@
      * to encourage its reuse.
      */
     @DataClass.Generated.Member
-    public Pattern getPattern() {
+    public @NonNull Pattern getPattern() {
         return mPattern;
     }
 
@@ -690,7 +696,7 @@
      * {@link Builder#addLinkAddresses2(LinkAddress) add} method is generated for convenience.
      */
     @DataClass.Generated.Member
-    public List<LinkAddress> getLinkAddresses2() {
+    public @NonNull List<LinkAddress> getLinkAddresses2() {
         return mLinkAddresses2;
     }
 
@@ -701,20 +707,11 @@
      * @see Builder#addLinkAddress(LinkAddress)
      */
     @DataClass.Generated.Member
-    public ArrayList<LinkAddress> getLinkAddresses() {
+    public @NonNull ArrayList<LinkAddress> getLinkAddresses() {
         return mLinkAddresses;
     }
 
     /**
-     * For boolean fields, when using a {@link Builder}, in addition to a regular setter, methods
-     * like {@link Builder#markActive()} and {@link Builder#markNotActive()} are generated.
-     */
-    @DataClass.Generated.Member
-    public boolean isActive() {
-        return mActive;
-    }
-
-    /**
      * {@link IntDef}/{@link StringDef}-annotated fields propagate the annotation to
      * getter/constructor/setter/builder parameters, making for a nicer api.
      *
@@ -722,7 +719,7 @@
      * @see Builder#setStateName
      */
     @DataClass.Generated.Member
-    public @StateName String getStateName() {
+    public @StateName @NonNull String getStateName() {
         return mStateName;
     }
 
@@ -746,7 +743,7 @@
      * Final fields suppress generating a setter (when setters are requested).
      */
     @DataClass.Generated.Member
-    public LinkAddress[] getLinkAddresses5() {
+    public @Nullable LinkAddress[] getLinkAddresses5() {
         return mLinkAddresses5;
     }
 
@@ -775,8 +772,8 @@
      * @see AnnotationValidations#validate(Class, Size, int, String, int, String, int)
      */
     @DataClass.Generated.Member
-    public @android.annotation.IntRange(from = 0, to = 4) int getLimited() {
-        return mLimited;
+    public @android.annotation.IntRange(from = 0, to = 6) int getDayOfWeek() {
+        return mDayOfWeek;
     }
 
     /**
@@ -789,7 +786,7 @@
      * @see AnnotationValidations#validate(Class, Size, int, String, int)
      */
     @DataClass.Generated.Member
-    public @Size(2) @FloatRange(from = 0f) float[] getCoords() {
+    public @Size(2) @NonNull @Each @FloatRange(from = 0f) float[] getCoords() {
         return mCoords;
     }
 
@@ -810,6 +807,282 @@
         return tmpStorage;
     }
 
+    /**
+     * Any property javadoc should go onto the field, and will be copied where appropriate,
+     * including getters, constructor parameters, builder setters, etc.
+     *
+     * <p>
+     * This allows to avoid the burden of maintaining copies of the same documentation
+     * pieces in multiple places for each field.
+     */
+    @DataClass.Generated.Member
+    public SampleDataClass setNum(int value) {
+        mNum = value;
+        return this;
+    }
+
+    /**
+     * Various javadoc features should work as expected when copied, e.g {@code code},
+     * {@link #mName links}, <a href="https://google.com">html links</a>, etc.
+     *
+     * @see #mNum2 ..and so should blocks at the bottom, e.g. {@code @see} blocks.
+     */
+    @DataClass.Generated.Member
+    public SampleDataClass setNum2(int value) {
+        mNum2 = value;
+        return this;
+    }
+
+    /**
+     * {@code @hide} javadoc annotation is also propagated, which can be used to adjust the
+     * desired public API surface.
+     *
+     * @see #getNum4() is hidden
+     * @see Builder#setNum4(int) also hidden
+     * @hide
+     */
+    @DataClass.Generated.Member
+    public SampleDataClass setNum4(int value) {
+        mNum4 = value;
+        return this;
+    }
+
+    /**
+     * {@link Nullable} or {@link NonNull} annotation is required on all non-primitive fields.
+     */
+    @DataClass.Generated.Member
+    public SampleDataClass setName(@Nullable String value) {
+        mName = value;
+        return this;
+    }
+
+    /**
+     * Fields with default value expressions ("mFoo = ...") are optional, and are automatically
+     * initialized to the provided default expression, unless explicitly set.
+     *
+     * When using a {@link Builder} optional fields are passed via a {@link Builder#setName2 setter}
+     * while mandatory fields are passed via {@link Builder#Builder constructor}.
+     */
+    @DataClass.Generated.Member
+    public SampleDataClass setName2(@NonNull String value) {
+        mName2 = value;
+        AnnotationValidations.validate(
+                NonNull.class, null, mName2);
+        return this;
+    }
+
+    /**
+     * Alternatively, when default value computation is expensive,
+     * {@link #defaultName4 defaultFieldName()} can be defined to compute the default value.
+     */
+    @DataClass.Generated.Member
+    public SampleDataClass setName4(@NonNull String value) {
+        mName4 = value;
+        AnnotationValidations.validate(
+                NonNull.class, null, mName4);
+        return this;
+    }
+
+    /**
+     * For parcelling, any field type supported by {@link Parcel} is supported out of the box.
+     * E.g. {@link Parcelable} subclasses, {@link String}, {@link int}, {@link boolean}, etc.
+     */
+    @DataClass.Generated.Member
+    public SampleDataClass setOtherParcelable(@Nullable AccessibilityNodeInfo value) {
+        mOtherParcelable = value;
+        return this;
+    }
+
+    /**
+     * Additionally, support for parcelling other types can be added by implementing a
+     * {@link Parcelling}, and referencing it in the {@link DataClass.ParcelWith} field annotation.
+     *
+     * @see MyDateParcelling an example {@link Parcelling} implementation
+     */
+    @DataClass.Generated.Member
+    public SampleDataClass setDate(@NonNull Date value) {
+        mDate = value;
+        AnnotationValidations.validate(
+                NonNull.class, null, mDate);
+        return this;
+    }
+
+    /**
+     * If a {@link Parcelling} is fairly common, consider putting it in {@link Parcelling.BuiltIn}
+     * to encourage its reuse.
+     */
+    @DataClass.Generated.Member
+    public SampleDataClass setPattern(@NonNull Pattern value) {
+        mPattern = value;
+        AnnotationValidations.validate(
+                NonNull.class, null, mPattern);
+        return this;
+    }
+
+    /**
+     * For lists, when using a {@link Builder}, other than a regular
+     * {@link Builder#setLinkAddresses2(List) setter}, and additional
+     * {@link Builder#addLinkAddresses2(LinkAddress) add} method is generated for convenience.
+     */
+    @DataClass.Generated.Member
+    public SampleDataClass setLinkAddresses2(@NonNull List<LinkAddress> value) {
+        mLinkAddresses2 = value;
+        AnnotationValidations.validate(
+                NonNull.class, null, mLinkAddresses2);
+        return this;
+    }
+
+    /**
+     * For aesthetics, you may want to consider providing a singular version of the plural field
+     * name, which would be used for the {@link #mLinkAddresses2 above mentioned} "add" method.
+     *
+     * @see Builder#addLinkAddress(LinkAddress)
+     */
+    @DataClass.Generated.Member
+    public SampleDataClass setLinkAddresses(@NonNull ArrayList<LinkAddress> value) {
+        mLinkAddresses = value;
+        AnnotationValidations.validate(
+                NonNull.class, null, mLinkAddresses);
+        return this;
+    }
+
+    /**
+     * For array fields, when using a {@link Builder}, vararg argument format is used for
+     * convenience.
+     *
+     * @see Builder#setLinkAddresses4(LinkAddress...)
+     */
+    @DataClass.Generated.Member
+    public SampleDataClass setLinkAddresses4(@Nullable LinkAddress... value) {
+        mLinkAddresses4 = value;
+        return this;
+    }
+
+    /**
+     * {@link IntDef}/{@link StringDef}-annotated fields propagate the annotation to
+     * getter/constructor/setter/builder parameters, making for a nicer api.
+     *
+     * @see #getStateName
+     * @see Builder#setStateName
+     */
+    @DataClass.Generated.Member
+    public SampleDataClass setStateName(@StateName @NonNull String value) {
+        mStateName = value;
+
+        if (!(Objects.equals(mStateName, STATE_NAME_UNDEFINED))
+                && !(Objects.equals(mStateName, STATE_NAME_ON))
+                && !(Objects.equals(mStateName, STATE_NAME_OFF))) {
+            throw new java.lang.IllegalArgumentException(
+                    "stateName was " + mStateName + " but must be one of: "
+                            + "STATE_NAME_UNDEFINED(" + STATE_NAME_UNDEFINED + "), "
+                            + "STATE_NAME_ON(" + STATE_NAME_ON + "), "
+                            + "STATE_NAME_OFF(" + STATE_NAME_OFF + ")");
+        }
+
+        AnnotationValidations.validate(
+                NonNull.class, null, mStateName);
+        return this;
+    }
+
+    /**
+     * Fields annotated with {@link IntDef} annotations also get a proper {@link #toString()} value.
+     */
+    @DataClass.Generated.Member
+    public SampleDataClass setFlags(@RequestFlags int value) {
+        mFlags = value;
+
+        Preconditions.checkFlagsArgument(
+                mFlags,
+                FLAG_MANUAL_REQUEST
+                        | FLAG_COMPATIBILITY_MODE_REQUEST
+                        | FLAG_AUGMENTED_REQUEST);
+        return this;
+    }
+
+    /**
+     * Above is true for both {@link IntDef#flag flags} and enum-like {@link IntDef}s
+     */
+    @DataClass.Generated.Member
+    public SampleDataClass setState(@State int value) {
+        mState = value;
+
+        if (!(mState == STATE_UNDEFINED)
+                && !(mState == STATE_ON)
+                && !(mState == STATE_OFF)) {
+            throw new java.lang.IllegalArgumentException(
+                    "state was " + mState + " but must be one of: "
+                            + "STATE_UNDEFINED(" + STATE_UNDEFINED + "), "
+                            + "STATE_ON(" + STATE_ON + "), "
+                            + "STATE_OFF(" + STATE_OFF + ")");
+        }
+
+        return this;
+    }
+
+    /**
+     * Fields with certain annotations are automatically validated in constructor
+     *
+     * You can see overloads in {@link AnnotationValidations} for a list of currently
+     * supported ones.
+     *
+     * You can also extend support to your custom annotations by creating another corresponding
+     * overloads like
+     * {@link AnnotationValidations#validate(Class, UserIdInt, int)}.
+     *
+     * @see #SampleDataClass
+     */
+    @DataClass.Generated.Member
+    public SampleDataClass setStringRes(@StringRes int value) {
+        mStringRes = value;
+        AnnotationValidations.validate(
+                StringRes.class, null, mStringRes);
+        return this;
+    }
+
+    /**
+     * Validation annotations may also have parameters.
+     *
+     * Parameter values will be supplied to validation method as name-value pairs.
+     *
+     * @see AnnotationValidations#validate(Class, Size, int, String, int, String, int)
+     */
+    @DataClass.Generated.Member
+    public SampleDataClass setDayOfWeek(@android.annotation.IntRange(from = 0, to = 6) int value) {
+        mDayOfWeek = value;
+        AnnotationValidations.validate(
+                android.annotation.IntRange.class, null, mDayOfWeek,
+                "from", 0,
+                "to", 6);
+        return this;
+    }
+
+    /**
+     * Unnamed validation annotation parameter gets supplied to the validating method named as
+     * "value".
+     *
+     * Validation annotations following {@link Each} annotation, will be applied for each
+     * array/collection element instead.
+     *
+     * @see AnnotationValidations#validate(Class, Size, int, String, int)
+     */
+    @DataClass.Generated.Member
+    public SampleDataClass setCoords(@Size(2) @NonNull @Each @FloatRange(from = 0f) float... value) {
+        mCoords = value;
+        AnnotationValidations.validate(
+                Size.class, null, mCoords.length,
+                "value", 2);
+        AnnotationValidations.validate(
+                NonNull.class, null, mCoords);
+        int coordsSize = mCoords.length;
+        for (int i = 0; i < coordsSize; i++) {
+            AnnotationValidations.validate(
+                    FloatRange.class, null, mCoords[i],
+                    "from", 0f);
+        }
+
+        return this;
+    }
+
     @Override
     @DataClass.Generated.Member
     public String toString() {
@@ -829,14 +1102,13 @@
                 "linkAddresses2 = " + mLinkAddresses2 + ", " +
                 "linkAddresses = " + mLinkAddresses + ", " +
                 "linkAddresses4 = " + java.util.Arrays.toString(mLinkAddresses4) + ", " +
-                "active = " + mActive + ", " +
                 "stateName = " + mStateName + ", " +
                 "flags = " + requestFlagsToString(mFlags) + ", " +
                 "state = " + stateToString(mState) + ", " +
                 "charSeq = " + charSeq + ", " +
                 "linkAddresses5 = " + java.util.Arrays.toString(mLinkAddresses5) + ", " +
                 "stringRes = " + mStringRes + ", " +
-                "limited = " + mLimited + ", " +
+                "dayOfWeek = " + mDayOfWeek + ", " +
                 "coords = " + java.util.Arrays.toString(mCoords) +
         " }";
     }
@@ -866,14 +1138,13 @@
                 && Objects.equals(mLinkAddresses2, that.mLinkAddresses2)
                 && Objects.equals(mLinkAddresses, that.mLinkAddresses)
                 && java.util.Arrays.equals(mLinkAddresses4, that.mLinkAddresses4)
-                && mActive == that.mActive
                 && Objects.equals(mStateName, that.mStateName)
                 && mFlags == that.mFlags
                 && mState == that.mState
                 && Objects.equals(charSeq, that.charSeq)
                 && java.util.Arrays.equals(mLinkAddresses5, that.mLinkAddresses5)
                 && mStringRes == that.mStringRes
-                && mLimited == that.mLimited
+                && mDayOfWeek == that.mDayOfWeek
                 && java.util.Arrays.equals(mCoords, that.mCoords);
     }
 
@@ -896,14 +1167,13 @@
         _hash = 31 * _hash + Objects.hashCode(mLinkAddresses2);
         _hash = 31 * _hash + Objects.hashCode(mLinkAddresses);
         _hash = 31 * _hash + java.util.Arrays.hashCode(mLinkAddresses4);
-        _hash = 31 * _hash + Boolean.hashCode(mActive);
         _hash = 31 * _hash + Objects.hashCode(mStateName);
         _hash = 31 * _hash + mFlags;
         _hash = 31 * _hash + mState;
         _hash = 31 * _hash + Objects.hashCode(charSeq);
         _hash = 31 * _hash + java.util.Arrays.hashCode(mLinkAddresses5);
         _hash = 31 * _hash + mStringRes;
-        _hash = 31 * _hash + mLimited;
+        _hash = 31 * _hash + mDayOfWeek;
         _hash = 31 * _hash + java.util.Arrays.hashCode(mCoords);
         return _hash;
     }
@@ -924,14 +1194,13 @@
         actionObject.acceptObject(this, "linkAddresses2", mLinkAddresses2);
         actionObject.acceptObject(this, "linkAddresses", mLinkAddresses);
         actionObject.acceptObject(this, "linkAddresses4", mLinkAddresses4);
-        actionObject.acceptObject(this, "active", mActive);
         actionObject.acceptObject(this, "stateName", mStateName);
         actionInt.acceptInt(this, "flags", mFlags);
         actionInt.acceptInt(this, "state", mState);
         actionObject.acceptObject(this, "charSeq", charSeq);
         actionObject.acceptObject(this, "linkAddresses5", mLinkAddresses5);
         actionInt.acceptInt(this, "stringRes", mStringRes);
-        actionInt.acceptInt(this, "limited", mLimited);
+        actionInt.acceptInt(this, "dayOfWeek", mDayOfWeek);
         actionObject.acceptObject(this, "coords", mCoords);
     }
 
@@ -951,25 +1220,24 @@
         action.acceptObject(this, "linkAddresses2", mLinkAddresses2);
         action.acceptObject(this, "linkAddresses", mLinkAddresses);
         action.acceptObject(this, "linkAddresses4", mLinkAddresses4);
-        action.acceptObject(this, "active", mActive);
         action.acceptObject(this, "stateName", mStateName);
         action.acceptObject(this, "flags", mFlags);
         action.acceptObject(this, "state", mState);
         action.acceptObject(this, "charSeq", charSeq);
         action.acceptObject(this, "linkAddresses5", mLinkAddresses5);
         action.acceptObject(this, "stringRes", mStringRes);
-        action.acceptObject(this, "limited", mLimited);
+        action.acceptObject(this, "dayOfWeek", mDayOfWeek);
         action.acceptObject(this, "coords", mCoords);
     }
 
     @DataClass.Generated.Member
     static Parcelling<Date> sParcellingForDate =
             Parcelling.Cache.get(
-                    DateParcelling.class);
+                    MyDateParcelling.class);
     static {
         if (sParcellingForDate == null) {
             sParcellingForDate = Parcelling.Cache.put(
-                    new DateParcelling());
+                    new MyDateParcelling());
         }
     }
 
@@ -991,40 +1259,31 @@
         // void parcelFieldName(Parcel dest, int flags) { ... }
 
         long flg = 0;
-        if (mActive) flg |= 0x1000;
         if (mName != null) flg |= 0x8;
-        if (mName2 != null) flg |= 0x10;
         if (mOtherParcelable != null) flg |= 0x40;
-        if (mDate != null) flg |= 0x80;
-        if (mPattern != null) flg |= 0x100;
-        if (mLinkAddresses2 != null) flg |= 0x200;
-        if (mLinkAddresses != null) flg |= 0x400;
         if (mLinkAddresses4 != null) flg |= 0x800;
-        if (mStateName != null) flg |= 0x2000;
-        if (charSeq != null) flg |= 0x10000;
-        if (mLinkAddresses5 != null) flg |= 0x20000;
-        if (mCoords != null) flg |= 0x100000;
+        if (mLinkAddresses5 != null) flg |= 0x10000;
         dest.writeLong(flg);
         dest.writeInt(mNum);
         dest.writeInt(mNum2);
         dest.writeInt(mNum4);
         if (mName != null) dest.writeString(mName);
-        if (mName2 != null) dest.writeString(mName2);
+        dest.writeString(mName2);
         dest.writeString(mName4);
         if (mOtherParcelable != null) dest.writeTypedObject(mOtherParcelable, flags);
         sParcellingForDate.parcel(mDate, dest, flags);
         sParcellingForPattern.parcel(mPattern, dest, flags);
-        if (mLinkAddresses2 != null) dest.writeParcelableList(mLinkAddresses2, flags);
-        if (mLinkAddresses != null) dest.writeParcelableList(mLinkAddresses, flags);
+        dest.writeParcelableList(mLinkAddresses2, flags);
+        dest.writeParcelableList(mLinkAddresses, flags);
         if (mLinkAddresses4 != null) dest.writeTypedArray(mLinkAddresses4, flags);
-        if (mStateName != null) dest.writeString(mStateName);
+        dest.writeString(mStateName);
         dest.writeInt(mFlags);
         dest.writeInt(mState);
-        if (charSeq != null) dest.writeCharSequence(charSeq);
+        dest.writeCharSequence(charSeq);
         if (mLinkAddresses5 != null) dest.writeTypedArray(mLinkAddresses5, flags);
         dest.writeInt(mStringRes);
-        dest.writeInt(mLimited);
-        if (mCoords != null) dest.writeFloatArray(mCoords);
+        dest.writeInt(mDayOfWeek);
+        dest.writeFloatArray(mCoords);
     }
 
     @Override
@@ -1046,35 +1305,28 @@
             // static FieldType unparcelFieldName(Parcel in) { ... }
 
             long flg = in.readLong();
-            boolean active = (flg & 0x1000) != 0;
             int num = in.readInt();
             int num2 = in.readInt();
             int num4 = in.readInt();
             String name = (flg & 0x8) == 0 ? null : in.readString();
-            String name2 = (flg & 0x10) == 0 ? null : in.readString();
+            String name2 = in.readString();
             String name4 = in.readString();
             AccessibilityNodeInfo otherParcelable = (flg & 0x40) == 0 ? null : (AccessibilityNodeInfo) in.readTypedObject(AccessibilityNodeInfo.CREATOR);
             Date date = sParcellingForDate.unparcel(in);
             Pattern pattern = sParcellingForPattern.unparcel(in);
-            List<LinkAddress> linkAddresses2 = null;
-            if ((flg & 0x200) != 0) {
-                linkAddresses2 = new ArrayList<>();
-                in.readParcelableList(linkAddresses2, LinkAddress.class.getClassLoader());
-            }
-            ArrayList<LinkAddress> linkAddresses = null;
-            if ((flg & 0x400) != 0) {
-                linkAddresses = new ArrayList<>();
-                in.readParcelableList(linkAddresses, LinkAddress.class.getClassLoader());
-            }
+            List<LinkAddress> linkAddresses2 = new ArrayList<>();
+            in.readParcelableList(linkAddresses2, LinkAddress.class.getClassLoader());
+            ArrayList<LinkAddress> linkAddresses = new ArrayList<>();
+            in.readParcelableList(linkAddresses, LinkAddress.class.getClassLoader());
             LinkAddress[] linkAddresses4 = (flg & 0x800) == 0 ? null : (LinkAddress[]) in.createTypedArray(LinkAddress.CREATOR);
-            String stateName = (flg & 0x2000) == 0 ? null : in.readString();
+            String stateName = in.readString();
             int flags = in.readInt();
             int state = in.readInt();
-            CharSequence _charSeq = (flg & 0x10000) == 0 ? null : (CharSequence) in.readCharSequence();
-            LinkAddress[] linkAddresses5 = (flg & 0x20000) == 0 ? null : (LinkAddress[]) in.createTypedArray(LinkAddress.CREATOR);
+            CharSequence _charSeq = (CharSequence) in.readCharSequence();
+            LinkAddress[] linkAddresses5 = (flg & 0x10000) == 0 ? null : (LinkAddress[]) in.createTypedArray(LinkAddress.CREATOR);
             int stringRes = in.readInt();
-            int limited = in.readInt();
-            float[] coords = (flg & 0x100000) == 0 ? null : in.createFloatArray();
+            int dayOfWeek = in.readInt();
+            float[] coords = in.createFloatArray();
             return new SampleDataClass(
                     num,
                     num2,
@@ -1088,14 +1340,13 @@
                     linkAddresses2,
                     linkAddresses,
                     linkAddresses4,
-                    active,
                     stateName,
                     flags,
                     state,
                     _charSeq,
                     linkAddresses5,
                     stringRes,
-                    limited,
+                    dayOfWeek,
                     coords);
         }
     };
@@ -1105,34 +1356,74 @@
      */
     @SuppressWarnings("WeakerAccess")
     @DataClass.Generated.Member
-    public static class Builder
-            extends android.provider.OneTimeUseBuilder<SampleDataClass> {
+    public static class Builder {
 
-        protected int mNum;
-        protected int mNum2;
-        protected int mNum4;
-        protected @Nullable String mName;
-        protected String mName2;
-        protected @NonNull String mName4;
-        protected AccessibilityNodeInfo mOtherParcelable;
-        protected Date mDate;
-        protected Pattern mPattern;
-        protected List<LinkAddress> mLinkAddresses2;
-        protected ArrayList<LinkAddress> mLinkAddresses;
-        protected @Nullable LinkAddress[] mLinkAddresses4;
-        protected boolean mActive;
-        protected @StateName String mStateName;
-        protected @RequestFlags int mFlags;
-        protected @State int mState;
-        protected CharSequence charSeq;
-        protected LinkAddress[] mLinkAddresses5;
-        protected @StringRes int mStringRes;
-        protected @android.annotation.IntRange(from = 0, to = 4) int mLimited;
-        protected @Size(2) @FloatRange(from = 0f) float[] mCoords;
+        private int mNum;
+        private int mNum2;
+        private int mNum4;
+        private @Nullable String mName;
+        private @NonNull String mName2;
+        private @NonNull String mName4;
+        private @Nullable AccessibilityNodeInfo mOtherParcelable;
+        private @NonNull Date mDate;
+        private @NonNull Pattern mPattern;
+        private @NonNull List<LinkAddress> mLinkAddresses2;
+        private @NonNull ArrayList<LinkAddress> mLinkAddresses;
+        private @Nullable LinkAddress[] mLinkAddresses4;
+        private @StateName @NonNull String mStateName;
+        private @RequestFlags int mFlags;
+        private @State int mState;
+        private @NonNull CharSequence charSeq;
+        private @Nullable LinkAddress[] mLinkAddresses5;
+        private @StringRes int mStringRes;
+        private @android.annotation.IntRange(from = 0, to = 6) int mDayOfWeek;
+        private @Size(2) @NonNull @Each @FloatRange(from = 0f) float[] mCoords;
 
-        protected long mBuilderFieldsSet = 0L;
+        private long mBuilderFieldsSet = 0L;
 
-        public Builder() {};
+        /**
+         * Creates a new Builder.
+         *
+         * @param num
+         *   Any property javadoc should go onto the field, and will be copied where appropriate,
+         *   including getters, constructor parameters, builder setters, etc.
+         *
+         *   <p>
+         *   This allows to avoid the burden of maintaining copies of the same documentation
+         *   pieces in multiple places for each field.
+         * @param num2
+         *   Various javadoc features should work as expected when copied, e.g {@code code},
+         *   {@link #mName links}, <a href="https://google.com">html links</a>, etc.
+         * @param num4
+         *   {@code @hide} javadoc annotation is also propagated, which can be used to adjust the
+         *   desired public API surface.
+         * @param name
+         *   {@link Nullable} or {@link NonNull} annotation is required on all non-primitive fields.
+         * @param flags
+         *   Fields annotated with {@link IntDef} annotations also get a proper {@link #toString()} value.
+         * @param linkAddresses5
+         *   Final fields suppress generating a setter (when setters are requested).
+         */
+        public Builder(
+                int num,
+                int num2,
+                int num4,
+                @Nullable String name,
+                @RequestFlags int flags,
+                @Nullable LinkAddress[] linkAddresses5) {
+            mNum = num;
+            mNum2 = num2;
+            mNum4 = num4;
+            mName = name;
+            mFlags = flags;
+
+            Preconditions.checkFlagsArgument(
+                    mFlags,
+                    FLAG_MANUAL_REQUEST
+                            | FLAG_COMPATIBILITY_MODE_REQUEST
+                            | FLAG_AUGMENTED_REQUEST);
+            mLinkAddresses5 = linkAddresses5;
+        }
 
         /**
          * Any property javadoc should go onto the field, and will be copied where appropriate,
@@ -1143,7 +1434,7 @@
          * pieces in multiple places for each field.
          */
         @DataClass.Generated.Member
-        public Builder setNum(int value) {
+        public @NonNull Builder setNum(int value) {
             checkNotUsed();
             mBuilderFieldsSet |= 0x1;
             mNum = value;
@@ -1157,7 +1448,7 @@
          * @see #mNum2 ..and so should blocks at the bottom, e.g. {@code @see} blocks.
          */
         @DataClass.Generated.Member
-        public Builder setNum2(int value) {
+        public @NonNull Builder setNum2(int value) {
             checkNotUsed();
             mBuilderFieldsSet |= 0x2;
             mNum2 = value;
@@ -1173,7 +1464,7 @@
          * @hide
          */
         @DataClass.Generated.Member
-        public Builder setNum4(int value) {
+        public @NonNull Builder setNum4(int value) {
             checkNotUsed();
             mBuilderFieldsSet |= 0x4;
             mNum4 = value;
@@ -1181,11 +1472,10 @@
         }
 
         /**
-         * {@link Nullable} fields are considered optional and will not throw an exception if omitted
-         * (or set to null) when creating an instance either via a {@link Builder} or constructor.
+         * {@link Nullable} or {@link NonNull} annotation is required on all non-primitive fields.
          */
         @DataClass.Generated.Member
-        public Builder setName(@Nullable String value) {
+        public @NonNull Builder setName(@Nullable String value) {
             checkNotUsed();
             mBuilderFieldsSet |= 0x8;
             mName = value;
@@ -1193,11 +1483,14 @@
         }
 
         /**
-         * Fields with default value expressions ("mFoo = ...") are also optional, and are automatically
+         * Fields with default value expressions ("mFoo = ...") are optional, and are automatically
          * initialized to the provided default expression, unless explicitly set.
+         *
+         * When using a {@link Builder} optional fields are passed via a {@link Builder#setName2 setter}
+         * while mandatory fields are passed via {@link Builder#Builder constructor}.
          */
         @DataClass.Generated.Member
-        public Builder setName2(String value) {
+        public @NonNull Builder setName2(@NonNull String value) {
             checkNotUsed();
             mBuilderFieldsSet |= 0x10;
             mName2 = value;
@@ -1205,12 +1498,11 @@
         }
 
         /**
-         * Fields without {@link Nullable} annotation or default value are considered required.
-         *
-         * {@link NonNull} annotation is recommended on such non-primitive fields for documentation.
+         * Alternatively, when default value computation is expensive,
+         * {@link #defaultName4 defaultFieldName()} can be defined to compute the default value.
          */
         @DataClass.Generated.Member
-        public Builder setName4(@NonNull String value) {
+        public @NonNull Builder setName4(@NonNull String value) {
             checkNotUsed();
             mBuilderFieldsSet |= 0x20;
             mName4 = value;
@@ -1222,7 +1514,7 @@
          * E.g. {@link Parcelable} subclasses, {@link String}, {@link int}, {@link boolean}, etc.
          */
         @DataClass.Generated.Member
-        public Builder setOtherParcelable(AccessibilityNodeInfo value) {
+        public @NonNull Builder setOtherParcelable(@Nullable AccessibilityNodeInfo value) {
             checkNotUsed();
             mBuilderFieldsSet |= 0x40;
             mOtherParcelable = value;
@@ -1233,10 +1525,10 @@
          * Additionally, support for parcelling other types can be added by implementing a
          * {@link Parcelling}, and referencing it in the {@link DataClass.ParcelWith} field annotation.
          *
-         * @see DateParcelling an example {@link Parcelling} implementation
+         * @see MyDateParcelling an example {@link Parcelling} implementation
          */
         @DataClass.Generated.Member
-        public Builder setDate(Date value) {
+        public @NonNull Builder setDate(@NonNull Date value) {
             checkNotUsed();
             mBuilderFieldsSet |= 0x80;
             mDate = value;
@@ -1248,7 +1540,7 @@
          * to encourage its reuse.
          */
         @DataClass.Generated.Member
-        public Builder setPattern(Pattern value) {
+        public @NonNull Builder setPattern(@NonNull Pattern value) {
             checkNotUsed();
             mBuilderFieldsSet |= 0x100;
             mPattern = value;
@@ -1261,7 +1553,7 @@
          * {@link Builder#addLinkAddresses2(LinkAddress) add} method is generated for convenience.
          */
         @DataClass.Generated.Member
-        public Builder setLinkAddresses2(List<LinkAddress> value) {
+        public @NonNull Builder setLinkAddresses2(@NonNull List<LinkAddress> value) {
             checkNotUsed();
             mBuilderFieldsSet |= 0x200;
             mLinkAddresses2 = value;
@@ -1270,7 +1562,7 @@
 
         /** @see #setLinkAddresses2 */
         @DataClass.Generated.Member
-        public Builder addLinkAddresses2(@NonNull LinkAddress value) {
+        public @NonNull Builder addLinkAddresses2(LinkAddress value) {
             // You can refine this method's name by providing item's singular name, e.g.:
             // @DataClass.PluralOf("item")) mItems = ...
 
@@ -1286,7 +1578,7 @@
          * @see Builder#addLinkAddress(LinkAddress)
          */
         @DataClass.Generated.Member
-        public Builder setLinkAddresses(ArrayList<LinkAddress> value) {
+        public @NonNull Builder setLinkAddresses(@NonNull ArrayList<LinkAddress> value) {
             checkNotUsed();
             mBuilderFieldsSet |= 0x400;
             mLinkAddresses = value;
@@ -1295,7 +1587,7 @@
 
         /** @see #setLinkAddresses */
         @DataClass.Generated.Member
-        public Builder addLinkAddress(@NonNull LinkAddress value) {
+        public @NonNull Builder addLinkAddress(LinkAddress value) {
             if (mLinkAddresses == null) setLinkAddresses(new ArrayList<>());
             mLinkAddresses.add(value);
             return this;
@@ -1308,7 +1600,7 @@
          * @see Builder#setLinkAddresses4(LinkAddress...)
          */
         @DataClass.Generated.Member
-        public Builder setLinkAddresses4(@Nullable LinkAddress... value) {
+        public @NonNull Builder setLinkAddresses4(@Nullable LinkAddress... value) {
             checkNotUsed();
             mBuilderFieldsSet |= 0x800;
             mLinkAddresses4 = value;
@@ -1316,30 +1608,6 @@
         }
 
         /**
-         * For boolean fields, when using a {@link Builder}, in addition to a regular setter, methods
-         * like {@link Builder#markActive()} and {@link Builder#markNotActive()} are generated.
-         */
-        @DataClass.Generated.Member
-        public Builder setActive(boolean value) {
-            checkNotUsed();
-            mBuilderFieldsSet |= 0x1000;
-            mActive = value;
-            return this;
-        }
-
-        /** @see #setActive */
-        @DataClass.Generated.Member
-        public Builder markActive() {
-            return setActive(true);
-        }
-
-        /** @see #setActive */
-        @DataClass.Generated.Member
-        public Builder markNotActive() {
-            return setActive(false);
-        }
-
-        /**
          * {@link IntDef}/{@link StringDef}-annotated fields propagate the annotation to
          * getter/constructor/setter/builder parameters, making for a nicer api.
          *
@@ -1347,9 +1615,9 @@
          * @see Builder#setStateName
          */
         @DataClass.Generated.Member
-        public Builder setStateName(@StateName String value) {
+        public @NonNull Builder setStateName(@StateName @NonNull String value) {
             checkNotUsed();
-            mBuilderFieldsSet |= 0x2000;
+            mBuilderFieldsSet |= 0x1000;
             mStateName = value;
             return this;
         }
@@ -1358,9 +1626,9 @@
          * Fields annotated with {@link IntDef} annotations also get a proper {@link #toString()} value.
          */
         @DataClass.Generated.Member
-        public Builder setFlags(@RequestFlags int value) {
+        public @NonNull Builder setFlags(@RequestFlags int value) {
             checkNotUsed();
-            mBuilderFieldsSet |= 0x4000;
+            mBuilderFieldsSet |= 0x2000;
             mFlags = value;
             return this;
         }
@@ -1369,9 +1637,9 @@
          * Above is true for both {@link IntDef#flag flags} and enum-like {@link IntDef}s
          */
         @DataClass.Generated.Member
-        public Builder setState(@State int value) {
+        public @NonNull Builder setState(@State int value) {
             checkNotUsed();
-            mBuilderFieldsSet |= 0x8000;
+            mBuilderFieldsSet |= 0x4000;
             mState = value;
             return this;
         }
@@ -1380,9 +1648,9 @@
          * Making a field public will suppress getter generation in favor of accessing it directly.
          */
         @DataClass.Generated.Member
-        public Builder setCharSeq(CharSequence value) {
+        public @NonNull Builder setCharSeq(@NonNull CharSequence value) {
             checkNotUsed();
-            mBuilderFieldsSet |= 0x10000;
+            mBuilderFieldsSet |= 0x8000;
             charSeq = value;
             return this;
         }
@@ -1391,9 +1659,9 @@
          * Final fields suppress generating a setter (when setters are requested).
          */
         @DataClass.Generated.Member
-        public Builder setLinkAddresses5(LinkAddress... value) {
+        public @NonNull Builder setLinkAddresses5(@Nullable LinkAddress... value) {
             checkNotUsed();
-            mBuilderFieldsSet |= 0x20000;
+            mBuilderFieldsSet |= 0x10000;
             mLinkAddresses5 = value;
             return this;
         }
@@ -1411,9 +1679,9 @@
          * @see #SampleDataClass
          */
         @DataClass.Generated.Member
-        public Builder setStringRes(@StringRes int value) {
+        public @NonNull Builder setStringRes(@StringRes int value) {
             checkNotUsed();
-            mBuilderFieldsSet |= 0x40000;
+            mBuilderFieldsSet |= 0x20000;
             mStringRes = value;
             return this;
         }
@@ -1426,10 +1694,10 @@
          * @see AnnotationValidations#validate(Class, Size, int, String, int, String, int)
          */
         @DataClass.Generated.Member
-        public Builder setLimited(@android.annotation.IntRange(from = 0, to = 4) int value) {
+        public @NonNull Builder setDayOfWeek(@android.annotation.IntRange(from = 0, to = 6) int value) {
             checkNotUsed();
-            mBuilderFieldsSet |= 0x80000;
-            mLimited = value;
+            mBuilderFieldsSet |= 0x40000;
+            mDayOfWeek = value;
             return this;
         }
 
@@ -1443,30 +1711,23 @@
          * @see AnnotationValidations#validate(Class, Size, int, String, int)
          */
         @DataClass.Generated.Member
-        public Builder setCoords(@Size(2) @FloatRange(from = 0f) float... value) {
+        public @NonNull Builder setCoords(@Size(2) @NonNull @Each @FloatRange(from = 0f) float... value) {
             checkNotUsed();
-            mBuilderFieldsSet |= 0x100000;
+            mBuilderFieldsSet |= 0x80000;
             mCoords = value;
             return this;
         }
 
         /** Builds the instance. This builder should not be touched after calling this! */
         public SampleDataClass build() {
-            markUsed();
-            if ((mBuilderFieldsSet & 0x1) == 0) {
-                throw new IllegalStateException("Required field not set: num");
-            }
-            if ((mBuilderFieldsSet & 0x2) == 0) {
-                throw new IllegalStateException("Required field not set: num2");
-            }
-            if ((mBuilderFieldsSet & 0x4) == 0) {
-                throw new IllegalStateException("Required field not set: num4");
-            }
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x100000; // Mark builder used
+
             if ((mBuilderFieldsSet & 0x10) == 0) {
                 mName2 = "Bob";
             }
             if ((mBuilderFieldsSet & 0x20) == 0) {
-                throw new IllegalStateException("Required field not set: name4");
+                mName4 = defaultName4();
             }
             if ((mBuilderFieldsSet & 0x40) == 0) {
                 mOtherParcelable = null;
@@ -1487,30 +1748,21 @@
                 mLinkAddresses4 = null;
             }
             if ((mBuilderFieldsSet & 0x1000) == 0) {
-                mActive = true;
-            }
-            if ((mBuilderFieldsSet & 0x2000) == 0) {
                 mStateName = STATE_NAME_UNDEFINED;
             }
             if ((mBuilderFieldsSet & 0x4000) == 0) {
-                throw new IllegalStateException("Required field not set: flags");
-            }
-            if ((mBuilderFieldsSet & 0x8000) == 0) {
                 mState = STATE_UNDEFINED;
             }
-            if ((mBuilderFieldsSet & 0x10000) == 0) {
+            if ((mBuilderFieldsSet & 0x8000) == 0) {
                 charSeq = "";
             }
             if ((mBuilderFieldsSet & 0x20000) == 0) {
-                throw new IllegalStateException("Required field not set: linkAddresses5");
-            }
-            if ((mBuilderFieldsSet & 0x40000) == 0) {
                 mStringRes = 0;
             }
-            if ((mBuilderFieldsSet & 0x80000) == 0) {
-                mLimited = 3;
+            if ((mBuilderFieldsSet & 0x40000) == 0) {
+                mDayOfWeek = 3;
             }
-            if ((mBuilderFieldsSet & 0x100000) == 0) {
+            if ((mBuilderFieldsSet & 0x80000) == 0) {
                 mCoords = new float[] { 0f, 0f };
             }
             SampleDataClass o = new SampleDataClass(
@@ -1526,17 +1778,31 @@
                     mLinkAddresses2,
                     mLinkAddresses,
                     mLinkAddresses4,
-                    mActive,
                     mStateName,
                     mFlags,
                     mState,
                     charSeq,
                     mLinkAddresses5,
                     mStringRes,
-                    mLimited,
+                    mDayOfWeek,
                     mCoords);
             return o;
         }
+
+        private void checkNotUsed() {
+            if ((mBuilderFieldsSet & 0x100000) != 0) {
+                throw new IllegalStateException(
+                        "This Builder should not be reused. Use a new Builder instance instead");
+            }
+        }
     }
 
+    @DataClass.Generated(
+            time = 1565126122525L,
+            codegenVersion = "1.0.0",
+            sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/SampleDataClass.java",
+            inputSignatures = "public static final  java.lang.String STATE_NAME_UNDEFINED\npublic static final  java.lang.String STATE_NAME_ON\npublic static final  java.lang.String STATE_NAME_OFF\npublic static final  int STATE_UNDEFINED\npublic static final  int STATE_ON\npublic static final  int STATE_OFF\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_MANUAL_REQUEST\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_COMPATIBILITY_MODE_REQUEST\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_AUGMENTED_REQUEST\nprivate  int mNum\nprivate  int mNum2\nprivate  int mNum4\nprivate @android.annotation.Nullable java.lang.String mName\nprivate @android.annotation.NonNull java.lang.String mName2\nprivate @android.annotation.NonNull java.lang.String mName4\nprivate @android.annotation.Nullable android.view.accessibility.AccessibilityNodeInfo mOtherParcelable\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.codegentest.MyDateParcelling.class) @android.annotation.NonNull java.util.Date mDate\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForPattern.class) @android.annotation.NonNull java.util.regex.Pattern mPattern\nprivate @android.annotation.NonNull java.util.List<android.net.LinkAddress> mLinkAddresses2\nprivate @com.android.internal.util.DataClass.PluralOf(\"linkAddress\") @android.annotation.NonNull java.util.ArrayList<android.net.LinkAddress> mLinkAddresses\nprivate @android.annotation.Nullable android.net.LinkAddress[] mLinkAddresses4\nprivate @com.android.codegentest.SampleDataClass.StateName @android.annotation.NonNull java.lang.String mStateName\nprivate @com.android.codegentest.SampleDataClass.RequestFlags int mFlags\nprivate @com.android.codegentest.SampleDataClass.State int mState\npublic @android.annotation.NonNull java.lang.CharSequence charSeq\nprivate final @android.annotation.Nullable android.net.LinkAddress[] mLinkAddresses5\nprivate transient  android.net.LinkAddress[] mLinkAddresses6\ntransient  int[] mTmpStorage\nprivate @android.annotation.StringRes int mStringRes\nprivate @android.annotation.IntRange(from=0L, to=6L) int mDayOfWeek\nprivate @android.annotation.Size(2L) @android.annotation.NonNull @com.android.internal.util.DataClass.Each @android.annotation.FloatRange(from=0.0) float[] mCoords\nprivate static  java.lang.String defaultName4()\nprivate  int[] lazyInitTmpStorage()\npublic  android.net.LinkAddress[] getLinkAddresses4()\nprivate  boolean patternEquals(java.util.regex.Pattern)\nprivate  int patternHashCode()\nprivate  void onConstructed()\npublic  void dump(java.io.PrintWriter)\nclass SampleDataClass extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genBuilder=true, genConstructor=true, genEqualsHashCode=true, genToString=true, genForEachField=true, genSetters=true)")
+    @Deprecated
+    private void __metadata() {}
+
 }
diff --git a/tests/Codegen/src/com/android/codegentest/SampleDataClassTest.java b/tests/Codegen/src/com/android/codegentest/SampleDataClassTest.java
index 71e85ab..6636207 100644
--- a/tests/Codegen/src/com/android/codegentest/SampleDataClassTest.java
+++ b/tests/Codegen/src/com/android/codegentest/SampleDataClassTest.java
@@ -49,7 +49,7 @@
     private SampleDataClass mSpecimen = newBuilder().build();
 
     private static SampleDataClass.Builder newBuilder() {
-        return newIncompleteBuilder()
+        return newInvalidBuilder()
                 .setNum(42)
                 .setNum2(42)
                 .setNum4(42)
@@ -57,9 +57,8 @@
                 .setLinkAddresses5();
     }
 
-    private static SampleDataClass.Builder newIncompleteBuilder() {
-        return new SampleDataClass.Builder()
-                .markActive()
+    private static SampleDataClass.Builder newInvalidBuilder() {
+        return new SampleDataClass.Builder(1, 2, 3, "a", 0, null)
                 .setName("some parcelable")
                 .setFlags(SampleDataClass.FLAG_MANUAL_REQUEST);
     }
@@ -91,7 +90,7 @@
     public void testCustomParcelling_instanceIsCached() {
         parcelAndUnparcel(mSpecimen, SampleDataClass.CREATOR);
         parcelAndUnparcel(mSpecimen, SampleDataClass.CREATOR);
-        assertEquals(1, DateParcelling.sInstanceCount.get());
+        assertEquals(1, MyDateParcelling.sInstanceCount.get());
     }
 
     @Test
@@ -149,8 +148,8 @@
     }
 
     @Test(expected = IllegalStateException.class)
-    public void testBuilder_throwsWhenRequiredFieldMissing() {
-        newIncompleteBuilder().build();
+    public void testBuilder_performsValidation() {
+        newInvalidBuilder().build();
     }
 
     @Test
@@ -205,6 +204,11 @@
         assertSame(tmpStorage, tmpStorageAgain);
     }
 
+    @Test(expected = IllegalStateException.class)
+    public void testCustomAnnotationValidation_isRun() {
+        newBuilder().setDayOfWeek(42).build();
+    }
+
     private static <T extends Parcelable> T parcelAndUnparcel(
             T original, Parcelable.Creator<T> creator) {
         Parcel p = Parcel.obtain();
diff --git a/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java b/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java
new file mode 100644
index 0000000..11f03a7
--- /dev/null
+++ b/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java
@@ -0,0 +1,186 @@
+/*
+ * 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.codegentest;
+
+import android.annotation.NonNull;
+import android.os.SystemClock;
+
+import com.android.internal.util.DataClass;
+
+import java.util.concurrent.TimeUnit;
+
+@DataClass(genBuilder = true)
+public class SampleWithCustomBuilder {
+
+    long delayAmount = 0;
+    @NonNull
+    TimeUnit delayUnit = TimeUnit.MILLISECONDS;
+
+    long creationTimestamp = SystemClock.uptimeMillis();
+
+    /**
+     * You can declare a class named {@code BaseBuilder} to have the generated builder extend from
+     * it instead.
+     *
+     * Same rules apply where defining a non-abstract method will suppress the generation of a
+     * method with the same signature.
+     *
+     * For abstract generatable methods, implementations are generated as normal, but original
+     * visibility is used, allowing you to hide methods.
+     *
+     * Here for example, we hide {@link #setDelayUnit} and {@link #setDelayAmount} from public API,
+     * replacing it with {@link #setDelay} instead.
+     */
+    // Suppress setter generation for a field that is not supposed to come from user input.
+    @DataClass.Suppress("setCreationTimestamp")
+    static abstract class BaseBuilder {
+
+        /**
+         * Hide methods by declaring them with reduced (package-private) visibility.
+         */
+        abstract Builder setDelayAmount(long value);
+
+        /**
+         * Alternatively, hide methods by using @hide, to hide them from public API only.
+         *
+         * @hide
+         */
+        public abstract Builder setDelayUnit(TimeUnit value);
+
+        /**
+         * Can provide additional method on the builder, e.g. as a replacement for the ones we've
+         * just hidden.
+         */
+        public Builder setDelay(long amount, TimeUnit unit) {
+            setDelayAmount(amount);
+            setDelayUnit(unit);
+            return (Builder) this;
+        }
+    }
+
+
+
+    // Code below generated by codegen v1.0.0.
+    //
+    // DO NOT MODIFY!
+    //
+    // To regenerate run:
+    // $ codegen $ANDROID_BUILD_TOP/frameworks/base/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java
+    //
+    // CHECKSTYLE:OFF Generated code
+
+    @DataClass.Generated.Member
+    /* package-private */ SampleWithCustomBuilder(
+            long delayAmount,
+            @NonNull TimeUnit delayUnit,
+            long creationTimestamp) {
+        this.delayAmount = delayAmount;
+        this.delayUnit = delayUnit;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, delayUnit);
+        this.creationTimestamp = creationTimestamp;
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    @DataClass.Generated.Member
+    public long getDelayAmount() {
+        return delayAmount;
+    }
+
+    @DataClass.Generated.Member
+    public @NonNull TimeUnit getDelayUnit() {
+        return delayUnit;
+    }
+
+    @DataClass.Generated.Member
+    public long getCreationTimestamp() {
+        return creationTimestamp;
+    }
+
+    /**
+     * A builder for {@link SampleWithCustomBuilder}
+     */
+    @SuppressWarnings("WeakerAccess")
+    @DataClass.Generated.Member
+    public static class Builder extends BaseBuilder {
+
+        private long delayAmount;
+        private @NonNull TimeUnit delayUnit;
+        private long creationTimestamp;
+
+        private long mBuilderFieldsSet = 0L;
+
+        public Builder() {
+        }
+
+        @DataClass.Generated.Member
+        @Override
+        @NonNull Builder setDelayAmount(long value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x1;
+            delayAmount = value;
+            return this;
+        }
+
+        @DataClass.Generated.Member
+        @Override
+        public @NonNull Builder setDelayUnit(@NonNull TimeUnit value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x2;
+            delayUnit = value;
+            return this;
+        }
+
+        /** Builds the instance. This builder should not be touched after calling this! */
+        public SampleWithCustomBuilder build() {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x8; // Mark builder used
+
+            if ((mBuilderFieldsSet & 0x1) == 0) {
+                delayAmount = 0;
+            }
+            if ((mBuilderFieldsSet & 0x2) == 0) {
+                delayUnit = TimeUnit.MILLISECONDS;
+            }
+            if ((mBuilderFieldsSet & 0x4) == 0) {
+                creationTimestamp = SystemClock.uptimeMillis();
+            }
+            SampleWithCustomBuilder o = new SampleWithCustomBuilder(
+                    delayAmount,
+                    delayUnit,
+                    creationTimestamp);
+            return o;
+        }
+
+        private void checkNotUsed() {
+            if ((mBuilderFieldsSet & 0x8) != 0) {
+                throw new IllegalStateException(
+                        "This Builder should not be reused. Use a new Builder instance instead");
+            }
+        }
+    }
+
+    @DataClass.Generated(
+            time = 1565126123496L,
+            codegenVersion = "1.0.0",
+            sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java",
+            inputSignatures = "  long delayAmount\n @android.annotation.NonNull java.util.concurrent.TimeUnit delayUnit\n  long creationTimestamp\nclass SampleWithCustomBuilder extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genBuilder=true)\nabstract  com.android.codegentest.SampleWithCustomBuilder.Builder setDelayAmount(long)\npublic abstract  com.android.codegentest.SampleWithCustomBuilder.Builder setDelayUnit(java.util.concurrent.TimeUnit)\npublic  com.android.codegentest.SampleWithCustomBuilder.Builder setDelay(long,java.util.concurrent.TimeUnit)\nclass BaseBuilder extends java.lang.Object implements []")
+    @Deprecated
+    private void __metadata() {}
+
+}
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
index a27df47..2c0432a 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
@@ -154,15 +154,8 @@
             // TODO: Race condition between the timeout and when the broadcast is
             // received could lead to test flakiness.
             Intent broadcast = broadcastReceiver.poll(5, TimeUnit.SECONDS);
-            if (context.getUser().isSystem()) {
-                // Only system user should receive those broadcasts.
-                assertThat(broadcast).isNotNull();
-                assertThat(broadcastReceiver.poll(0, TimeUnit.SECONDS)).isNull();
-            } else {
-                // This is in case the test was running under a secondary user, in which case
-                // the broadcast won't be received here.
-                assertThat(broadcast).isNull();
-            }
+            assertThat(broadcast).isNotNull();
+            assertThat(broadcastReceiver.poll(0, TimeUnit.SECONDS)).isNull();
 
             // Verify the recent rollback has been recorded.
             RollbackInfo committed = getUniqueRollbackInfoForPackage(
diff --git a/tests/net/Android.bp b/tests/net/Android.bp
index 5260b30..502aa97 100644
--- a/tests/net/Android.bp
+++ b/tests/net/Android.bp
@@ -56,6 +56,7 @@
         "androidx.test.rules",
         "FrameworksNetCommonTests",
         "frameworks-base-testutils",
+        "frameworks-net-integration-testutils",
         "framework-protos",
         "mockito-target-minus-junit4",
         "net-tests-utils",
diff --git a/tests/net/integration/Android.bp b/tests/net/integration/Android.bp
new file mode 100644
index 0000000..16a68d7
--- /dev/null
+++ b/tests/net/integration/Android.bp
@@ -0,0 +1,31 @@
+//
+// 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.
+//
+
+// Utilities for testing framework code both in integration and unit tests.
+java_library {
+    name: "frameworks-net-integration-testutils",
+    srcs: ["util/**/*.java", "util/**/*.kt"],
+    static_libs: [
+        "androidx.annotation_annotation",
+        "androidx.test.rules",
+        "junit",
+        "net-tests-utils",
+    ],
+    libs: [
+        "services.core",
+        "services.net",
+    ],
+}
diff --git a/tests/net/integration/util/com/android/server/ConnectivityServiceTestUtils.kt b/tests/net/integration/util/com/android/server/ConnectivityServiceTestUtils.kt
new file mode 100644
index 0000000..fa2b99c
--- /dev/null
+++ b/tests/net/integration/util/com/android/server/ConnectivityServiceTestUtils.kt
@@ -0,0 +1,41 @@
+/*
+ * 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
+
+import android.net.ConnectivityManager.TYPE_BLUETOOTH
+import android.net.ConnectivityManager.TYPE_ETHERNET
+import android.net.ConnectivityManager.TYPE_MOBILE
+import android.net.ConnectivityManager.TYPE_NONE
+import android.net.ConnectivityManager.TYPE_TEST
+import android.net.ConnectivityManager.TYPE_VPN
+import android.net.ConnectivityManager.TYPE_WIFI
+import android.net.NetworkCapabilities.TRANSPORT_BLUETOOTH
+import android.net.NetworkCapabilities.TRANSPORT_CELLULAR
+import android.net.NetworkCapabilities.TRANSPORT_ETHERNET
+import android.net.NetworkCapabilities.TRANSPORT_TEST
+import android.net.NetworkCapabilities.TRANSPORT_VPN
+import android.net.NetworkCapabilities.TRANSPORT_WIFI
+
+fun transportToLegacyType(transport: Int) = when (transport) {
+    TRANSPORT_BLUETOOTH -> TYPE_BLUETOOTH
+    TRANSPORT_CELLULAR -> TYPE_MOBILE
+    TRANSPORT_ETHERNET -> TYPE_ETHERNET
+    TRANSPORT_TEST -> TYPE_TEST
+    TRANSPORT_VPN -> TYPE_VPN
+    TRANSPORT_WIFI -> TYPE_WIFI
+    else -> TYPE_NONE
+}
\ No newline at end of file
diff --git a/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java b/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java
new file mode 100644
index 0000000..1e8d83c
--- /dev/null
+++ b/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java
@@ -0,0 +1,267 @@
+/*
+ * 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;
+
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET;
+import static android.net.NetworkCapabilities.TRANSPORT_VPN;
+import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
+import static android.net.NetworkCapabilities.TRANSPORT_WIFI_AWARE;
+
+import static com.android.server.ConnectivityServiceTestUtilsKt.transportToLegacyType;
+
+import static junit.framework.Assert.assertTrue;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.LinkProperties;
+import android.net.Network;
+import android.net.NetworkAgent;
+import android.net.NetworkCapabilities;
+import android.net.NetworkFactory;
+import android.net.NetworkInfo;
+import android.net.NetworkMisc;
+import android.net.NetworkSpecifier;
+import android.net.SocketKeepalive;
+import android.net.UidRange;
+import android.os.ConditionVariable;
+import android.os.HandlerThread;
+import android.os.Message;
+import android.util.Log;
+
+import com.android.server.connectivity.ConnectivityConstants;
+import com.android.testutils.HandlerUtilsKt;
+import com.android.testutils.TestableNetworkCallback;
+
+import java.util.Set;
+
+public class NetworkAgentWrapper implements TestableNetworkCallback.HasNetwork {
+    private final NetworkInfo mNetworkInfo;
+    private final NetworkCapabilities mNetworkCapabilities;
+    private final HandlerThread mHandlerThread;
+    private final Context mContext;
+    private final String mLogTag;
+
+    private final ConditionVariable mDisconnected = new ConditionVariable();
+    private final ConditionVariable mPreventReconnectReceived = new ConditionVariable();
+    private int mScore;
+    private NetworkAgent mNetworkAgent;
+    private int mStartKeepaliveError = SocketKeepalive.ERROR_UNSUPPORTED;
+    private int mStopKeepaliveError = SocketKeepalive.NO_KEEPALIVE;
+    private Integer mExpectedKeepaliveSlot = null;
+
+    public NetworkAgentWrapper(int transport, LinkProperties linkProperties, Context context)
+            throws Exception {
+        final int type = transportToLegacyType(transport);
+        final String typeName = ConnectivityManager.getNetworkTypeName(type);
+        mNetworkInfo = new NetworkInfo(type, 0, typeName, "Mock");
+        mNetworkCapabilities = new NetworkCapabilities();
+        mNetworkCapabilities.addTransportType(transport);
+        switch (transport) {
+            case TRANSPORT_ETHERNET:
+                mScore = 70;
+                break;
+            case TRANSPORT_WIFI:
+                mScore = 60;
+                break;
+            case TRANSPORT_CELLULAR:
+                mScore = 50;
+                break;
+            case TRANSPORT_WIFI_AWARE:
+                mScore = 20;
+                break;
+            case TRANSPORT_VPN:
+                mNetworkCapabilities.removeCapability(NET_CAPABILITY_NOT_VPN);
+                mScore = ConnectivityConstants.VPN_DEFAULT_SCORE;
+                break;
+            default:
+                throw new UnsupportedOperationException("unimplemented network type");
+        }
+        mContext = context;
+        mLogTag = "Mock-" + typeName;
+        mHandlerThread = new HandlerThread(mLogTag);
+        mHandlerThread.start();
+
+        mNetworkAgent = makeNetworkAgent(linkProperties);
+    }
+
+    protected InstrumentedNetworkAgent makeNetworkAgent(LinkProperties linkProperties)
+            throws Exception {
+        return new InstrumentedNetworkAgent(this, linkProperties);
+    }
+
+    public static class InstrumentedNetworkAgent extends NetworkAgent {
+        private final NetworkAgentWrapper mWrapper;
+
+        public InstrumentedNetworkAgent(NetworkAgentWrapper wrapper, LinkProperties lp) {
+            super(wrapper.mHandlerThread.getLooper(), wrapper.mContext, wrapper.mLogTag,
+                    wrapper.mNetworkInfo, wrapper.mNetworkCapabilities, lp, wrapper.mScore,
+                    new NetworkMisc(), NetworkFactory.SerialNumber.NONE);
+            mWrapper = wrapper;
+        }
+
+        @Override
+        public void unwanted() {
+            mWrapper.mDisconnected.open();
+        }
+
+        @Override
+        public void startSocketKeepalive(Message msg) {
+            int slot = msg.arg1;
+            if (mWrapper.mExpectedKeepaliveSlot != null) {
+                assertEquals((int) mWrapper.mExpectedKeepaliveSlot, slot);
+            }
+            onSocketKeepaliveEvent(slot, mWrapper.mStartKeepaliveError);
+        }
+
+        @Override
+        public void stopSocketKeepalive(Message msg) {
+            onSocketKeepaliveEvent(msg.arg1, mWrapper.mStopKeepaliveError);
+        }
+
+        @Override
+        protected void preventAutomaticReconnect() {
+            mWrapper.mPreventReconnectReceived.open();
+        }
+
+        @Override
+        protected void addKeepalivePacketFilter(Message msg) {
+            Log.i(mWrapper.mLogTag, "Add keepalive packet filter.");
+        }
+
+        @Override
+        protected void removeKeepalivePacketFilter(Message msg) {
+            Log.i(mWrapper.mLogTag, "Remove keepalive packet filter.");
+        }
+    }
+
+    public void adjustScore(int change) {
+        mScore += change;
+        mNetworkAgent.sendNetworkScore(mScore);
+    }
+
+    public int getScore() {
+        return mScore;
+    }
+
+    public void explicitlySelected(boolean explicitlySelected, boolean acceptUnvalidated) {
+        mNetworkAgent.explicitlySelected(explicitlySelected, acceptUnvalidated);
+    }
+
+    public void addCapability(int capability) {
+        mNetworkCapabilities.addCapability(capability);
+        mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
+    }
+
+    public void removeCapability(int capability) {
+        mNetworkCapabilities.removeCapability(capability);
+        mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
+    }
+
+    public void setUids(Set<UidRange> uids) {
+        mNetworkCapabilities.setUids(uids);
+        mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
+    }
+
+    public void setSignalStrength(int signalStrength) {
+        mNetworkCapabilities.setSignalStrength(signalStrength);
+        mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
+    }
+
+    public void setNetworkSpecifier(NetworkSpecifier networkSpecifier) {
+        mNetworkCapabilities.setNetworkSpecifier(networkSpecifier);
+        mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
+    }
+
+    public void setNetworkCapabilities(NetworkCapabilities nc, boolean sendToConnectivityService) {
+        mNetworkCapabilities.set(nc);
+        if (sendToConnectivityService) {
+            mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
+        }
+    }
+
+    public void connect() {
+        assertNotEquals("MockNetworkAgents can only be connected once",
+                getNetworkInfo().getDetailedState(), NetworkInfo.DetailedState.CONNECTED);
+        mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, null, null);
+        mNetworkAgent.sendNetworkInfo(mNetworkInfo);
+    }
+
+    public void suspend() {
+        mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.SUSPENDED, null, null);
+        mNetworkAgent.sendNetworkInfo(mNetworkInfo);
+    }
+
+    public void resume() {
+        mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, null, null);
+        mNetworkAgent.sendNetworkInfo(mNetworkInfo);
+    }
+
+    public void disconnect() {
+        mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.DISCONNECTED, null, null);
+        mNetworkAgent.sendNetworkInfo(mNetworkInfo);
+    }
+
+    @Override
+    public Network getNetwork() {
+        return new Network(mNetworkAgent.netId);
+    }
+
+    public void expectPreventReconnectReceived(long timeoutMs) {
+        assertTrue(mPreventReconnectReceived.block(timeoutMs));
+    }
+
+    public void expectDisconnected(long timeoutMs) {
+        assertTrue(mDisconnected.block(timeoutMs));
+    }
+
+    public void sendLinkProperties(LinkProperties lp) {
+        mNetworkAgent.sendLinkProperties(lp);
+    }
+
+    public void setStartKeepaliveEvent(int reason) {
+        mStartKeepaliveError = reason;
+    }
+
+    public void setStopKeepaliveEvent(int reason) {
+        mStopKeepaliveError = reason;
+    }
+
+    public void setExpectedKeepaliveSlot(Integer slot) {
+        mExpectedKeepaliveSlot = slot;
+    }
+
+    public NetworkAgent getNetworkAgent() {
+        return mNetworkAgent;
+    }
+
+    public NetworkInfo getNetworkInfo() {
+        return mNetworkInfo;
+    }
+
+    public NetworkCapabilities getNetworkCapabilities() {
+        return mNetworkCapabilities;
+    }
+
+    public void waitForIdle(long timeoutMs) {
+        HandlerUtilsKt.waitForIdle(mHandlerThread, timeoutMs);
+    }
+}
diff --git a/tests/net/integration/util/com/android/server/TestNetIdManager.kt b/tests/net/integration/util/com/android/server/TestNetIdManager.kt
new file mode 100644
index 0000000..eb290dc
--- /dev/null
+++ b/tests/net/integration/util/com/android/server/TestNetIdManager.kt
@@ -0,0 +1,38 @@
+/*
+ * 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
+
+import java.util.concurrent.atomic.AtomicInteger
+
+/**
+ * A [NetIdManager] that generates ID starting from [NetIdManager.MAX_NET_ID] and decreasing, rather
+ * than starting from [NetIdManager.MIN_NET_ID] and increasing.
+ *
+ * Useful for testing ConnectivityService, to minimize the risk of test ConnectivityService netIDs
+ * overlapping with netIDs used by the real ConnectivityService on the device.
+ *
+ * IDs may still overlap if many networks have been used on the device (so the "real" netIDs
+ * are close to MAX_NET_ID), but this is typically not the case when running unit tests. Also, there
+ * is no way to fully solve the overlap issue without altering ID allocation in non-test code, as
+ * the real ConnectivityService could start using netIds that have been used by the test in the
+ * past.
+ */
+class TestNetIdManager : NetIdManager() {
+    private val nextId = AtomicInteger(MAX_NET_ID)
+    override fun reserveNetId() = nextId.decrementAndGet()
+    override fun releaseNetId(id: Int) = Unit
+}
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 5cc95d9..f3c735c 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -28,8 +28,6 @@
 import static android.net.ConnectivityManager.TYPE_MOBILE;
 import static android.net.ConnectivityManager.TYPE_MOBILE_FOTA;
 import static android.net.ConnectivityManager.TYPE_MOBILE_MMS;
-import static android.net.ConnectivityManager.TYPE_NONE;
-import static android.net.ConnectivityManager.TYPE_VPN;
 import static android.net.ConnectivityManager.TYPE_WIFI;
 import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_DNS;
 import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_FALLBACK;
@@ -69,6 +67,7 @@
 import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
 import static android.net.RouteInfo.RTN_UNREACHABLE;
 
+import static com.android.server.ConnectivityServiceTestUtilsKt.transportToLegacyType;
 import static com.android.testutils.ConcurrentUtilsKt.await;
 import static com.android.testutils.ConcurrentUtilsKt.durationOf;
 import static com.android.testutils.ExceptionUtils.ignoreExceptions;
@@ -86,6 +85,7 @@
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Matchers.anyInt;
@@ -93,6 +93,7 @@
 import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.inOrder;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
@@ -105,6 +106,7 @@
 import static org.mockito.Mockito.when;
 
 import android.annotation.NonNull;
+import android.app.AlarmManager;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
@@ -125,6 +127,7 @@
 import android.net.ConnectivityManager.TooManyRequestsException;
 import android.net.ConnectivityThread;
 import android.net.IDnsResolver;
+import android.net.IIpConnectivityMetrics;
 import android.net.INetd;
 import android.net.INetworkMonitor;
 import android.net.INetworkMonitorCallbacks;
@@ -139,12 +142,8 @@
 import android.net.LinkProperties;
 import android.net.MatchAllNetworkSpecifier;
 import android.net.Network;
-import android.net.NetworkAgent;
 import android.net.NetworkCapabilities;
 import android.net.NetworkFactory;
-import android.net.NetworkInfo;
-import android.net.NetworkInfo.DetailedState;
-import android.net.NetworkMisc;
 import android.net.NetworkRequest;
 import android.net.NetworkSpecifier;
 import android.net.NetworkStack;
@@ -168,7 +167,6 @@
 import android.os.HandlerThread;
 import android.os.INetworkManagementService;
 import android.os.Looper;
-import android.os.Message;
 import android.os.Parcel;
 import android.os.ParcelFileDescriptor;
 import android.os.Parcelable;
@@ -265,10 +263,12 @@
     // timeout. For this, our assertions should run fast enough to leave less than
     // (mService.mLingerDelayMs - TEST_CALLBACK_TIMEOUT_MS) between the time callbacks are
     // supposedly fired, and the time we call expectCallback.
-    private final static int TEST_CALLBACK_TIMEOUT_MS = 200;
+    private static final int TEST_CALLBACK_TIMEOUT_MS = 200;
     // Chosen to be less than TEST_CALLBACK_TIMEOUT_MS. This ensures that requests have time to
     // complete before callbacks are verified.
-    private final static int TEST_REQUEST_TIMEOUT_MS = 150;
+    private static final int TEST_REQUEST_TIMEOUT_MS = 150;
+
+    private static final int UNREASONABLY_LONG_ALARM_WAIT_MS = 1000;
 
     private static final String CLAT_PREFIX = "v4-";
     private static final String MOBILE_IFNAME = "test_rmnet_data0";
@@ -276,15 +276,19 @@
     private static final String[] EMPTY_STRING_ARRAY = new String[0];
 
     private MockContext mServiceContext;
-    private WrappedConnectivityService mService;
+    private HandlerThread mCsHandlerThread;
+    private ConnectivityService mService;
     private WrappedConnectivityManager mCm;
-    private MockNetworkAgent mWiFiNetworkAgent;
-    private MockNetworkAgent mCellNetworkAgent;
-    private MockNetworkAgent mEthernetNetworkAgent;
+    private TestNetworkAgentWrapper mWiFiNetworkAgent;
+    private TestNetworkAgentWrapper mCellNetworkAgent;
+    private TestNetworkAgentWrapper mEthernetNetworkAgent;
     private MockVpn mMockVpn;
     private Context mContext;
     private INetworkPolicyListener mPolicyListener;
+    private WrappedMultinetworkPolicyTracker mPolicyTracker;
+    private HandlerThread mAlarmManagerThread;
 
+    @Mock IIpConnectivityMetrics mIpConnectivityMetrics;
     @Mock IpConnectivityMetrics.Logger mMetricsService;
     @Mock DefaultNetworkMetrics mDefaultNetworkMetrics;
     @Mock INetworkManagementService mNetworkManagementService;
@@ -296,6 +300,7 @@
     @Mock PackageManager mPackageManager;
     @Mock UserManager mUserManager;
     @Mock NotificationManager mNotificationManager;
+    @Mock AlarmManager mAlarmManager;
 
     private ArgumentCaptor<ResolverParamsParcel> mResolverParamsParcelCaptor =
             ArgumentCaptor.forClass(ResolverParamsParcel.class);
@@ -368,6 +373,7 @@
             if (Context.NOTIFICATION_SERVICE.equals(name)) return mNotificationManager;
             if (Context.NETWORK_STACK_SERVICE.equals(name)) return mNetworkStack;
             if (Context.USER_SERVICE.equals(name)) return mUserManager;
+            if (Context.ALARM_SERVICE.equals(name)) return mAlarmManager;
             return super.getSystemService(name);
         }
 
@@ -397,25 +403,20 @@
         }
     }
 
-    public void waitForIdle(int timeoutMsAsInt) {
-        long timeoutMs = timeoutMsAsInt;
-        HandlerUtilsKt.waitForIdle(mService.mHandlerThread, timeoutMs);
-        waitForIdle(mCellNetworkAgent, timeoutMs);
-        waitForIdle(mWiFiNetworkAgent, timeoutMs);
-        waitForIdle(mEthernetNetworkAgent, timeoutMs);
-        HandlerUtilsKt.waitForIdle(mService.mHandlerThread, timeoutMs);
-        HandlerUtilsKt.waitForIdle(ConnectivityThread.get(), timeoutMs);
+    private void waitForIdle() {
+        HandlerUtilsKt.waitForIdle(mCsHandlerThread, TIMEOUT_MS);
+        waitForIdle(mCellNetworkAgent, TIMEOUT_MS);
+        waitForIdle(mWiFiNetworkAgent, TIMEOUT_MS);
+        waitForIdle(mEthernetNetworkAgent, TIMEOUT_MS);
+        HandlerUtilsKt.waitForIdle(mCsHandlerThread, TIMEOUT_MS);
+        HandlerUtilsKt.waitForIdle(ConnectivityThread.get(), TIMEOUT_MS);
     }
 
-    public void waitForIdle(MockNetworkAgent agent, long timeoutMs) {
+    private void waitForIdle(TestNetworkAgentWrapper agent, long timeoutMs) {
         if (agent == null) {
             return;
         }
-        HandlerUtilsKt.waitForIdle(agent.mHandlerThread, timeoutMs);
-    }
-
-    private void waitForIdle() {
-        waitForIdle(TIMEOUT_MS);
+        agent.waitForIdle(timeoutMs);
     }
 
     @Test
@@ -429,7 +430,7 @@
 
         // Bring up a network that we can use to send messages to ConnectivityService.
         ConditionVariable cv = waitForConnectivityBroadcasts(1);
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(false);
         waitFor(cv);
         Network n = mWiFiNetworkAgent.getNetwork();
@@ -449,7 +450,7 @@
     public void verifyThatNotWaitingForIdleCausesRaceConditions() throws Exception {
         // Bring up a network that we can use to send messages to ConnectivityService.
         ConditionVariable cv = waitForConnectivityBroadcasts(1);
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(false);
         waitFor(cv);
         Network n = mWiFiNetworkAgent.getNetwork();
@@ -469,7 +470,7 @@
         fail("expected race condition at least once in " + attempts + " attempts");
     }
 
-    private class MockNetworkAgent implements TestableNetworkCallback.HasNetwork {
+    private class TestNetworkAgentWrapper extends NetworkAgentWrapper {
         private static final int VALIDATION_RESULT_BASE = NETWORK_VALIDATION_PROBE_DNS
                 | NETWORK_VALIDATION_PROBE_HTTP
                 | NETWORK_VALIDATION_PROBE_HTTPS;
@@ -480,86 +481,35 @@
                 | NETWORK_VALIDATION_RESULT_PARTIAL;
         private static final int VALIDATION_RESULT_INVALID = 0;
 
-        private final INetworkMonitor mNetworkMonitor;
-        private final NetworkInfo mNetworkInfo;
-        private final NetworkCapabilities mNetworkCapabilities;
-        private final HandlerThread mHandlerThread;
-        private final ConditionVariable mDisconnected = new ConditionVariable();
-        private final ConditionVariable mNetworkStatusReceived = new ConditionVariable();
-        private final ConditionVariable mPreventReconnectReceived = new ConditionVariable();
-        private int mScore;
-        private NetworkAgent mNetworkAgent;
-        private int mStartKeepaliveError = SocketKeepalive.ERROR_UNSUPPORTED;
-        private int mStopKeepaliveError = SocketKeepalive.NO_KEEPALIVE;
-        private Integer mExpectedKeepaliveSlot = null;
-        // Contains the redirectUrl from networkStatus(). Before reading, wait for
-        // mNetworkStatusReceived.
-        private String mRedirectUrl;
-
+        private INetworkMonitor mNetworkMonitor;
         private INetworkMonitorCallbacks mNmCallbacks;
         private int mNmValidationResult = VALIDATION_RESULT_BASE;
         private String mNmValidationRedirectUrl = null;
         private boolean mNmProvNotificationRequested = false;
 
-        void setNetworkValid() {
-            mNmValidationResult = VALIDATION_RESULT_VALID;
-            mNmValidationRedirectUrl = null;
-        }
+        private final ConditionVariable mNetworkStatusReceived = new ConditionVariable();
+        // Contains the redirectUrl from networkStatus(). Before reading, wait for
+        // mNetworkStatusReceived.
+        private String mRedirectUrl;
 
-        void setNetworkInvalid() {
-            mNmValidationResult = VALIDATION_RESULT_INVALID;
-            mNmValidationRedirectUrl = null;
-        }
-
-        void setNetworkPortal(String redirectUrl) {
-            setNetworkInvalid();
-            mNmValidationRedirectUrl = redirectUrl;
-        }
-
-        void setNetworkPartial() {
-            mNmValidationResult = VALIDATION_RESULT_PARTIAL;
-            mNmValidationRedirectUrl = null;
-        }
-
-        void setNetworkPartialValid() {
-            mNmValidationResult = VALIDATION_RESULT_PARTIAL | VALIDATION_RESULT_VALID;
-            mNmValidationRedirectUrl = null;
-        }
-
-        MockNetworkAgent(int transport) throws Exception {
+        TestNetworkAgentWrapper(int transport) throws Exception {
             this(transport, new LinkProperties());
         }
 
-        MockNetworkAgent(int transport, LinkProperties linkProperties) throws Exception {
-            final int type = transportToLegacyType(transport);
-            final String typeName = ConnectivityManager.getNetworkTypeName(type);
-            mNetworkInfo = new NetworkInfo(type, 0, typeName, "Mock");
-            mNetworkCapabilities = new NetworkCapabilities();
-            mNetworkCapabilities.addTransportType(transport);
-            switch (transport) {
-                case TRANSPORT_ETHERNET:
-                    mScore = 70;
-                    break;
-                case TRANSPORT_WIFI:
-                    mScore = 60;
-                    break;
-                case TRANSPORT_CELLULAR:
-                    mScore = 50;
-                    break;
-                case TRANSPORT_WIFI_AWARE:
-                    mScore = 20;
-                    break;
-                case TRANSPORT_VPN:
-                    mNetworkCapabilities.removeCapability(NET_CAPABILITY_NOT_VPN);
-                    mScore = ConnectivityConstants.VPN_DEFAULT_SCORE;
-                    break;
-                default:
-                    throw new UnsupportedOperationException("unimplemented network type");
-            }
-            mHandlerThread = new HandlerThread("Mock-" + typeName);
-            mHandlerThread.start();
+        TestNetworkAgentWrapper(int transport, LinkProperties linkProperties)
+                throws Exception {
+            super(transport, linkProperties, mServiceContext);
 
+            // Waits for the NetworkAgent to be registered, which includes the creation of the
+            // NetworkMonitor.
+            waitForIdle(TIMEOUT_MS);
+        }
+
+        @Override
+        protected InstrumentedNetworkAgent makeNetworkAgent(LinkProperties linkProperties)
+                throws Exception {
             mNetworkMonitor = mock(INetworkMonitor.class);
+
             final Answer validateAnswer = inv -> {
                 new Thread(ignoreExceptions(this::onValidationRequested)).start();
                 return null;
@@ -576,56 +526,20 @@
                     any() /* name */,
                     nmCbCaptor.capture());
 
-            mNetworkAgent = new NetworkAgent(mHandlerThread.getLooper(), mServiceContext,
-                    "Mock-" + typeName, mNetworkInfo, mNetworkCapabilities,
-                    linkProperties, mScore, new NetworkMisc(), NetworkFactory.SerialNumber.NONE) {
-                @Override
-                public void unwanted() { mDisconnected.open(); }
-
-                @Override
-                public void startSocketKeepalive(Message msg) {
-                    int slot = msg.arg1;
-                    if (mExpectedKeepaliveSlot != null) {
-                        assertEquals((int) mExpectedKeepaliveSlot, slot);
-                    }
-                    onSocketKeepaliveEvent(slot, mStartKeepaliveError);
-                }
-
-                @Override
-                public void stopSocketKeepalive(Message msg) {
-                    onSocketKeepaliveEvent(msg.arg1, mStopKeepaliveError);
-                }
-
+            final InstrumentedNetworkAgent na = new InstrumentedNetworkAgent(this, linkProperties) {
                 @Override
                 public void networkStatus(int status, String redirectUrl) {
                     mRedirectUrl = redirectUrl;
                     mNetworkStatusReceived.open();
                 }
-
-                @Override
-                protected void preventAutomaticReconnect() {
-                    mPreventReconnectReceived.open();
-                }
-
-                @Override
-                protected void addKeepalivePacketFilter(Message msg) {
-                    Log.i(TAG, "Add keepalive packet filter.");
-                }
-
-                @Override
-                protected void removeKeepalivePacketFilter(Message msg) {
-                    Log.i(TAG, "Remove keepalive packet filter.");
-                }
             };
 
-            assertEquals(mNetworkAgent.netId, nmNetworkCaptor.getValue().netId);
+            assertEquals(na.netId, nmNetworkCaptor.getValue().netId);
             mNmCallbacks = nmCbCaptor.getValue();
 
             mNmCallbacks.onNetworkMonitorCreated(mNetworkMonitor);
 
-            // Waits for the NetworkAgent to be registered, which includes the creation of the
-            // NetworkMonitor.
-            waitForIdle();
+            return na;
         }
 
         private void onValidationRequested() throws Exception {
@@ -645,55 +559,11 @@
             }
         }
 
-        public void adjustScore(int change) {
-            mScore += change;
-            mNetworkAgent.sendNetworkScore(mScore);
-        }
-
-        public int getScore() {
-            return mScore;
-        }
-
-        public void explicitlySelected(boolean explicitlySelected, boolean acceptUnvalidated) {
-            mNetworkAgent.explicitlySelected(explicitlySelected, acceptUnvalidated);
-        }
-
-        public void addCapability(int capability) {
-            mNetworkCapabilities.addCapability(capability);
-            mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
-        }
-
-        public void removeCapability(int capability) {
-            mNetworkCapabilities.removeCapability(capability);
-            mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
-        }
-
-        public void setUids(Set<UidRange> uids) {
-            mNetworkCapabilities.setUids(uids);
-            mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
-        }
-
-        public void setSignalStrength(int signalStrength) {
-            mNetworkCapabilities.setSignalStrength(signalStrength);
-            mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
-        }
-
-        public void setNetworkSpecifier(NetworkSpecifier networkSpecifier) {
-            mNetworkCapabilities.setNetworkSpecifier(networkSpecifier);
-            mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
-        }
-
-        public void setNetworkCapabilities(NetworkCapabilities nc,
-                boolean sendToConnectivityService) {
-            mNetworkCapabilities.set(nc);
-            if (sendToConnectivityService) {
-                mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
-            }
-        }
-
+        /**
+         * Connect without adding any internet capability.
+         */
         public void connectWithoutInternet() {
-            mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, null);
-            mNetworkAgent.sendNetworkInfo(mNetworkInfo);
+            super.connect();
         }
 
         /**
@@ -710,23 +580,21 @@
          * @param hasInternet Indicate if network should pretend to have NET_CAPABILITY_INTERNET.
          */
         public void connect(boolean validated, boolean hasInternet) {
-            assertEquals("MockNetworkAgents can only be connected once",
-                    mNetworkInfo.getDetailedState(), DetailedState.IDLE);
-            assertFalse(mNetworkCapabilities.hasCapability(NET_CAPABILITY_INTERNET));
+            assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_INTERNET));
 
-            NetworkCallback callback = null;
+            ConnectivityManager.NetworkCallback callback = null;
             final ConditionVariable validatedCv = new ConditionVariable();
             if (validated) {
                 setNetworkValid();
                 NetworkRequest request = new NetworkRequest.Builder()
-                        .addTransportType(mNetworkCapabilities.getTransportTypes()[0])
+                        .addTransportType(getNetworkCapabilities().getTransportTypes()[0])
                         .clearCapabilities()
                         .build();
-                callback = new NetworkCallback() {
+                callback = new ConnectivityManager.NetworkCallback() {
                     public void onCapabilitiesChanged(Network network,
                             NetworkCapabilities networkCapabilities) {
                         if (network.equals(getNetwork()) &&
-                            networkCapabilities.hasCapability(NET_CAPABILITY_VALIDATED)) {
+                                networkCapabilities.hasCapability(NET_CAPABILITY_VALIDATED)) {
                             validatedCv.open();
                         }
                     }
@@ -763,47 +631,29 @@
             connect(false);
         }
 
-        public void suspend() {
-            mNetworkInfo.setDetailedState(DetailedState.SUSPENDED, null, null);
-            mNetworkAgent.sendNetworkInfo(mNetworkInfo);
+        void setNetworkValid() {
+            mNmValidationResult = VALIDATION_RESULT_VALID;
+            mNmValidationRedirectUrl = null;
         }
 
-        public void resume() {
-            mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, null);
-            mNetworkAgent.sendNetworkInfo(mNetworkInfo);
+        void setNetworkInvalid() {
+            mNmValidationResult = VALIDATION_RESULT_INVALID;
+            mNmValidationRedirectUrl = null;
         }
 
-        public void disconnect() {
-            mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, null);
-            mNetworkAgent.sendNetworkInfo(mNetworkInfo);
+        void setNetworkPortal(String redirectUrl) {
+            setNetworkInvalid();
+            mNmValidationRedirectUrl = redirectUrl;
         }
 
-        public Network getNetwork() {
-            return new Network(mNetworkAgent.netId);
+        void setNetworkPartial() {
+            mNmValidationResult = VALIDATION_RESULT_PARTIAL;
+            mNmValidationRedirectUrl = null;
         }
 
-        public ConditionVariable getPreventReconnectReceived() {
-            return mPreventReconnectReceived;
-        }
-
-        public ConditionVariable getDisconnectedCV() {
-            return mDisconnected;
-        }
-
-        public void sendLinkProperties(LinkProperties lp) {
-            mNetworkAgent.sendLinkProperties(lp);
-        }
-
-        public void setStartKeepaliveError(int error) {
-            mStartKeepaliveError = error;
-        }
-
-        public void setStopKeepaliveError(int error) {
-            mStopKeepaliveError = error;
-        }
-
-        public void setExpectedKeepaliveSlot(Integer slot) {
-            mExpectedKeepaliveSlot = slot;
+        void setNetworkPartialValid() {
+            mNmValidationResult = VALIDATION_RESULT_PARTIAL | VALIDATION_RESULT_VALID;
+            mNmValidationRedirectUrl = null;
         }
 
         public String waitForRedirectUrl() {
@@ -811,12 +661,12 @@
             return mRedirectUrl;
         }
 
-        public NetworkAgent getNetworkAgent() {
-            return mNetworkAgent;
+        public void expectDisconnected() {
+            expectDisconnected(TIMEOUT_MS);
         }
 
-        public NetworkCapabilities getNetworkCapabilities() {
-            return mNetworkCapabilities;
+        public void expectPreventReconnectReceived() {
+            expectPreventReconnectReceived(TIMEOUT_MS);
         }
     }
 
@@ -995,15 +845,15 @@
         private boolean mConnected = false;
         // Careful ! This is different from mNetworkAgent, because MockNetworkAgent does
         // not inherit from NetworkAgent.
-        private MockNetworkAgent mMockNetworkAgent;
+        private TestNetworkAgentWrapper mMockNetworkAgent;
 
         public MockVpn(int userId) {
             super(startHandlerThreadAndReturnLooper(), mServiceContext, mNetworkManagementService,
                     userId);
         }
 
-        public void setNetworkAgent(MockNetworkAgent agent) {
-            waitForIdle(agent, TIMEOUT_MS);
+        public void setNetworkAgent(TestNetworkAgentWrapper agent) {
+            agent.waitForIdle(TIMEOUT_MS);
             mMockNetworkAgent = agent;
             mNetworkAgent = agent.getNetworkAgent();
             mNetworkCapabilities.set(agent.getNetworkCapabilities());
@@ -1070,187 +920,45 @@
         }
     }
 
-    private class FakeWakeupMessage extends WakeupMessage {
-        private static final int UNREASONABLY_LONG_WAIT = 1000;
-
-        public FakeWakeupMessage(Context context, Handler handler, String cmdName, int cmd) {
-            super(context, handler, cmdName, cmd);
-        }
-
-        public FakeWakeupMessage(Context context, Handler handler, String cmdName, int cmd,
-                int arg1, int arg2, Object obj) {
-            super(context, handler, cmdName, cmd, arg1, arg2, obj);
-        }
-
-        @Override
-        public void schedule(long when) {
-            long delayMs = when - SystemClock.elapsedRealtime();
-            if (delayMs < 0) delayMs = 0;
-            if (delayMs > UNREASONABLY_LONG_WAIT) {
-                fail("Attempting to send msg more than " + UNREASONABLY_LONG_WAIT +
-                        "ms into the future: " + delayMs);
-            }
-            Message msg = mHandler.obtainMessage(mCmd, mArg1, mArg2, mObj);
-            mHandler.sendMessageDelayed(msg, delayMs);
-        }
-
-        @Override
-        public void cancel() {
-            mHandler.removeMessages(mCmd, mObj);
-        }
-
-        @Override
-        public void onAlarm() {
-            throw new AssertionError("Should never happen. Update this fake.");
+    private void mockVpn(int uid) {
+        synchronized (mService.mVpns) {
+            int userId = UserHandle.getUserId(uid);
+            mMockVpn = new MockVpn(userId);
+            // This has no effect unless the VPN is actually connected, because things like
+            // getActiveNetworkForUidInternal call getNetworkAgentInfoForNetId on the VPN
+            // netId, and check if that network is actually connected.
+            mService.mVpns.put(userId, mMockVpn);
         }
     }
 
-    private class WrappedMultinetworkPolicyTracker extends MultinetworkPolicyTracker {
-        public volatile boolean configRestrictsAvoidBadWifi;
-        public volatile int configMeteredMultipathPreference;
+    private void setUidRulesChanged(int uidRules) throws RemoteException {
+        mPolicyListener.onUidRulesChanged(Process.myUid(), uidRules);
+    }
 
-        public WrappedMultinetworkPolicyTracker(Context c, Handler h, Runnable r) {
+    private void setRestrictBackgroundChanged(boolean restrictBackground) throws RemoteException {
+        mPolicyListener.onRestrictBackgroundChanged(restrictBackground);
+    }
+
+    private Nat464Xlat getNat464Xlat(NetworkAgentWrapper mna) {
+        return mService.getNetworkAgentInfoForNetwork(mna.getNetwork()).clatd;
+    }
+
+    private static class WrappedMultinetworkPolicyTracker extends MultinetworkPolicyTracker {
+        volatile boolean mConfigRestrictsAvoidBadWifi;
+        volatile int mConfigMeteredMultipathPreference;
+
+        WrappedMultinetworkPolicyTracker(Context c, Handler h, Runnable r) {
             super(c, h, r);
         }
 
         @Override
         public boolean configRestrictsAvoidBadWifi() {
-            return configRestrictsAvoidBadWifi;
+            return mConfigRestrictsAvoidBadWifi;
         }
 
         @Override
         public int configMeteredMultipathPreference() {
-            return configMeteredMultipathPreference;
-        }
-    }
-
-    private class WrappedConnectivityService extends ConnectivityService {
-        public WrappedMultinetworkPolicyTracker wrappedMultinetworkPolicyTracker;
-        private MockableSystemProperties mSystemProperties;
-
-        public WrappedConnectivityService(Context context, INetworkManagementService netManager,
-                INetworkStatsService statsService, INetworkPolicyManager policyManager,
-                IpConnectivityLog log, INetd netd, IDnsResolver dnsResolver) {
-            super(context, netManager, statsService, policyManager, dnsResolver, log, netd);
-            mNetd = netd;
-            mLingerDelayMs = TEST_LINGER_DELAY_MS;
-        }
-
-        @Override
-        protected MockableSystemProperties getSystemProperties() {
-            // Minimal approach to overriding system properties: let most calls fall through to real
-            // device values, and only override ones values that are important to this test.
-            mSystemProperties = spy(new MockableSystemProperties());
-            when(mSystemProperties.getInt("net.tcp.default_init_rwnd", 0)).thenReturn(0);
-            when(mSystemProperties.getBoolean("ro.radio.noril", false)).thenReturn(false);
-            return mSystemProperties;
-        }
-
-        @Override
-        protected Tethering makeTethering() {
-            return mock(Tethering.class);
-        }
-
-        @Override
-        protected ProxyTracker makeProxyTracker() {
-            return mock(ProxyTracker.class);
-        }
-
-        @Override
-        protected int reserveNetId() {
-            while (true) {
-                final int netId = super.reserveNetId();
-
-                // Don't overlap test NetIDs with real NetIDs as binding sockets to real networks
-                // can have odd side-effects, like network validations succeeding.
-                Context context = InstrumentationRegistry.getContext();
-                final Network[] networks = ConnectivityManager.from(context).getAllNetworks();
-                boolean overlaps = false;
-                for (Network network : networks) {
-                    if (netId == network.netId) {
-                        overlaps = true;
-                        break;
-                    }
-                }
-                if (overlaps) continue;
-
-                return netId;
-            }
-        }
-
-        @Override
-        protected boolean queryUserAccess(int uid, int netId) {
-            return true;
-        }
-
-        public Nat464Xlat getNat464Xlat(MockNetworkAgent mna) {
-            return getNetworkAgentInfoForNetwork(mna.getNetwork()).clatd;
-        }
-
-        @Override
-        public MultinetworkPolicyTracker createMultinetworkPolicyTracker(
-                Context c, Handler h, Runnable r) {
-            final WrappedMultinetworkPolicyTracker tracker = new WrappedMultinetworkPolicyTracker(c, h, r);
-            return tracker;
-        }
-
-        public WrappedMultinetworkPolicyTracker getMultinetworkPolicyTracker() {
-            return (WrappedMultinetworkPolicyTracker) mMultinetworkPolicyTracker;
-        }
-
-        @Override
-        protected NetworkStackClient getNetworkStack() {
-            return mNetworkStack;
-        }
-
-        @Override
-        public WakeupMessage makeWakeupMessage(
-                Context context, Handler handler, String cmdName, int cmd, Object obj) {
-            return new FakeWakeupMessage(context, handler, cmdName, cmd, 0, 0, obj);
-        }
-
-        @Override
-        public boolean hasService(String name) {
-            // Currenty, the only relevant service that ConnectivityService checks for is
-            // ETHERNET_SERVICE.
-            return Context.ETHERNET_SERVICE.equals(name);
-        }
-
-        @Override
-        protected IpConnectivityMetrics.Logger metricsLogger() {
-            return mMetricsService;
-        }
-
-        @Override
-        protected void registerNetdEventCallback() {
-        }
-
-        public void mockVpn(int uid) {
-            synchronized (mVpns) {
-                int userId = UserHandle.getUserId(uid);
-                mMockVpn = new MockVpn(userId);
-                // This has no effect unless the VPN is actually connected, because things like
-                // getActiveNetworkForUidInternal call getNetworkAgentInfoForNetId on the VPN
-                // netId, and check if that network is actually connected.
-                mVpns.put(userId, mMockVpn);
-            }
-        }
-
-        public void waitForIdle(int timeoutMs) {
-            HandlerUtilsKt.waitForIdle(mHandlerThread, timeoutMs);
-        }
-
-        public void waitForIdle() {
-            waitForIdle(TIMEOUT_MS);
-        }
-
-        public void setUidRulesChanged(int uidRules) throws RemoteException {
-            mPolicyListener.onUidRulesChanged(Process.myUid(), uidRules);
-        }
-
-        public void setRestrictBackgroundChanged(boolean restrictBackground)
-                throws RemoteException {
-            mPolicyListener.onRestrictBackgroundChanged(restrictBackground);
+            return mConfigMeteredMultipathPreference;
         }
     }
 
@@ -1296,13 +1004,22 @@
         LocalServices.addService(
                 NetworkPolicyManagerInternal.class, mock(NetworkPolicyManagerInternal.class));
 
-        mService = new WrappedConnectivityService(mServiceContext,
+        mAlarmManagerThread = new HandlerThread("TestAlarmManager");
+        mAlarmManagerThread.start();
+        initAlarmManager(mAlarmManager, mAlarmManagerThread.getThreadHandler());
+
+        mCsHandlerThread = new HandlerThread("TestConnectivityService");
+        final ConnectivityService.Dependencies deps = makeDependencies();
+        mService = new ConnectivityService(mServiceContext,
                 mNetworkManagementService,
                 mStatsService,
                 mNpm,
+                mMockDnsResolver,
                 mock(IpConnectivityLog.class),
                 mMockNetd,
-                mMockDnsResolver);
+                deps);
+        mService.mLingerDelayMs = TEST_LINGER_DELAY_MS;
+        verify(deps).makeMultinetworkPolicyTracker(any(), any(), any());
 
         final ArgumentCaptor<INetworkPolicyListener> policyListenerCaptor =
                 ArgumentCaptor.forClass(INetworkPolicyListener.class);
@@ -1313,7 +1030,7 @@
         // getSystemService() correctly.
         mCm = new WrappedConnectivityManager(InstrumentationRegistry.getContext(), mService);
         mService.systemReady();
-        mService.mockVpn(Process.myUid());
+        mockVpn(Process.myUid());
         mCm.bindProcessToNetwork(null);
 
         // Ensure that the default setting for Captive Portals is used for most tests
@@ -1322,6 +1039,57 @@
         setPrivateDnsSettings(PRIVATE_DNS_MODE_OFF, "ignored.example.com");
     }
 
+    private ConnectivityService.Dependencies makeDependencies() {
+        final MockableSystemProperties systemProperties = spy(new MockableSystemProperties());
+        when(systemProperties.getInt("net.tcp.default_init_rwnd", 0)).thenReturn(0);
+        when(systemProperties.getBoolean("ro.radio.noril", false)).thenReturn(false);
+
+        final ConnectivityService.Dependencies deps = mock(ConnectivityService.Dependencies.class);
+        doReturn(mCsHandlerThread).when(deps).makeHandlerThread();
+        doReturn(new TestNetIdManager()).when(deps).makeNetIdManager();
+        doReturn(mNetworkStack).when(deps).getNetworkStack();
+        doReturn(systemProperties).when(deps).getSystemProperties();
+        doReturn(mock(Tethering.class)).when(deps).makeTethering(any(), any(), any(), any(), any());
+        doReturn(mock(ProxyTracker.class)).when(deps).makeProxyTracker(any(), any());
+        doReturn(mMetricsService).when(deps).getMetricsLogger();
+        doReturn(true).when(deps).queryUserAccess(anyInt(), anyInt());
+        doReturn(mIpConnectivityMetrics).when(deps).getIpConnectivityMetrics();
+        doReturn(true).when(deps).hasService(Context.ETHERNET_SERVICE);
+        doAnswer(inv -> {
+            mPolicyTracker = new WrappedMultinetworkPolicyTracker(
+                    inv.getArgument(0), inv.getArgument(1), inv.getArgument(2));
+            return mPolicyTracker;
+        }).when(deps).makeMultinetworkPolicyTracker(any(), any(), any());
+
+        return deps;
+    }
+
+    private static void initAlarmManager(final AlarmManager am, final Handler alarmHandler) {
+        doAnswer(inv -> {
+            final long when = inv.getArgument(1);
+            final WakeupMessage wakeupMsg = inv.getArgument(3);
+            final Handler handler = inv.getArgument(4);
+
+            long delayMs = when - SystemClock.elapsedRealtime();
+            if (delayMs < 0) delayMs = 0;
+            if (delayMs > UNREASONABLY_LONG_ALARM_WAIT_MS) {
+                fail("Attempting to send msg more than " + UNREASONABLY_LONG_ALARM_WAIT_MS
+                        + "ms into the future: " + delayMs);
+            }
+            alarmHandler.postDelayed(() -> handler.post(wakeupMsg::onAlarm), wakeupMsg /* token */,
+                    delayMs);
+
+            return null;
+        }).when(am).setExact(eq(AlarmManager.ELAPSED_REALTIME_WAKEUP), anyLong(), anyString(),
+                any(WakeupMessage.class), any());
+
+        doAnswer(inv -> {
+            final WakeupMessage wakeupMsg = inv.getArgument(0);
+            alarmHandler.removeCallbacksAndMessages(wakeupMsg /* token */);
+            return null;
+        }).when(am).cancel(any(WakeupMessage.class));
+    }
+
     @After
     public void tearDown() throws Exception {
         setAlwaysOnNetworks(false);
@@ -1338,6 +1106,9 @@
             mEthernetNetworkAgent = null;
         }
         FakeSettingsProvider.clearSettingsProvider();
+
+        mCsHandlerThread.quitSafely();
+        mAlarmManagerThread.quitSafely();
     }
 
     private void mockDefaultPackages() throws Exception {
@@ -1357,21 +1128,6 @@
                 }));
     }
 
-   private static int transportToLegacyType(int transport) {
-        switch (transport) {
-            case TRANSPORT_ETHERNET:
-                return TYPE_ETHERNET;
-            case TRANSPORT_WIFI:
-                return TYPE_WIFI;
-            case TRANSPORT_CELLULAR:
-                return TYPE_MOBILE;
-            case TRANSPORT_VPN:
-                return TYPE_VPN;
-            default:
-                return TYPE_NONE;
-        }
-    }
-
     private void verifyActiveNetwork(int transport) {
         // Test getActiveNetworkInfo()
         assertNotNull(mCm.getActiveNetworkInfo());
@@ -1449,8 +1205,8 @@
     @Test
     public void testLingering() throws Exception {
         verifyNoNetwork();
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         assertNull(mCm.getActiveNetworkInfo());
         assertNull(mCm.getActiveNetwork());
         // Test bringing up validated cellular.
@@ -1474,7 +1230,7 @@
         assertTrue(mCm.getAllNetworks()[0].equals(mCellNetworkAgent.getNetwork()) ||
                 mCm.getAllNetworks()[1].equals(mCellNetworkAgent.getNetwork()));
         // Test cellular linger timeout.
-        waitFor(mCellNetworkAgent.getDisconnectedCV());
+        mCellNetworkAgent.expectDisconnected();
         waitForIdle();
         assertLength(1, mCm.getAllNetworks());
         verifyActiveNetwork(TRANSPORT_WIFI);
@@ -1490,13 +1246,13 @@
     @Test
     public void testValidatedCellularOutscoresUnvalidatedWiFi() throws Exception {
         // Test bringing up unvalidated WiFi
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         ConditionVariable cv = waitForConnectivityBroadcasts(1);
         mWiFiNetworkAgent.connect(false);
         waitFor(cv);
         verifyActiveNetwork(TRANSPORT_WIFI);
         // Test bringing up unvalidated cellular
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         mCellNetworkAgent.connect(false);
         waitForIdle();
         verifyActiveNetwork(TRANSPORT_WIFI);
@@ -1505,7 +1261,7 @@
         waitForIdle();
         verifyActiveNetwork(TRANSPORT_WIFI);
         // Test bringing up validated cellular
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         cv = waitForConnectivityBroadcasts(2);
         mCellNetworkAgent.connect(true);
         waitFor(cv);
@@ -1525,13 +1281,13 @@
     @Test
     public void testUnvalidatedWifiOutscoresUnvalidatedCellular() throws Exception {
         // Test bringing up unvalidated cellular.
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         ConditionVariable cv = waitForConnectivityBroadcasts(1);
         mCellNetworkAgent.connect(false);
         waitFor(cv);
         verifyActiveNetwork(TRANSPORT_CELLULAR);
         // Test bringing up unvalidated WiFi.
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         cv = waitForConnectivityBroadcasts(2);
         mWiFiNetworkAgent.connect(false);
         waitFor(cv);
@@ -1551,7 +1307,7 @@
     @Test
     public void testUnlingeringDoesNotValidate() throws Exception {
         // Test bringing up unvalidated WiFi.
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         ConditionVariable cv = waitForConnectivityBroadcasts(1);
         mWiFiNetworkAgent.connect(false);
         waitFor(cv);
@@ -1559,7 +1315,7 @@
         assertFalse(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).hasCapability(
                 NET_CAPABILITY_VALIDATED));
         // Test bringing up validated cellular.
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         cv = waitForConnectivityBroadcasts(2);
         mCellNetworkAgent.connect(true);
         waitFor(cv);
@@ -1579,13 +1335,13 @@
     @Test
     public void testCellularOutscoresWeakWifi() throws Exception {
         // Test bringing up validated cellular.
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         ConditionVariable cv = waitForConnectivityBroadcasts(1);
         mCellNetworkAgent.connect(true);
         waitFor(cv);
         verifyActiveNetwork(TRANSPORT_CELLULAR);
         // Test bringing up validated WiFi.
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         cv = waitForConnectivityBroadcasts(2);
         mWiFiNetworkAgent.connect(true);
         waitFor(cv);
@@ -1606,45 +1362,41 @@
     public void testReapingNetwork() throws Exception {
         // Test bringing up WiFi without NET_CAPABILITY_INTERNET.
         // Expect it to be torn down immediately because it satisfies no requests.
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
-        ConditionVariable cv = mWiFiNetworkAgent.getDisconnectedCV();
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connectWithoutInternet();
-        waitFor(cv);
+        mWiFiNetworkAgent.expectDisconnected();
         // Test bringing up cellular without NET_CAPABILITY_INTERNET.
         // Expect it to be torn down immediately because it satisfies no requests.
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
-        cv = mCellNetworkAgent.getDisconnectedCV();
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mCellNetworkAgent.connectWithoutInternet();
-        waitFor(cv);
+        mCellNetworkAgent.expectDisconnected();
         // Test bringing up validated WiFi.
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
-        cv = waitForConnectivityBroadcasts(1);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
+        final ConditionVariable cv = waitForConnectivityBroadcasts(1);
         mWiFiNetworkAgent.connect(true);
         waitFor(cv);
         verifyActiveNetwork(TRANSPORT_WIFI);
         // Test bringing up unvalidated cellular.
         // Expect it to be torn down because it could never be the highest scoring network
         // satisfying the default request even if it validated.
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
-        cv = mCellNetworkAgent.getDisconnectedCV();
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         mCellNetworkAgent.connect(false);
-        waitFor(cv);
+        mCellNetworkAgent.expectDisconnected();
         verifyActiveNetwork(TRANSPORT_WIFI);
-        cv = mWiFiNetworkAgent.getDisconnectedCV();
         mWiFiNetworkAgent.disconnect();
-        waitFor(cv);
+        mWiFiNetworkAgent.expectDisconnected();
     }
 
     @Test
     public void testCellularFallback() throws Exception {
         // Test bringing up validated cellular.
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         ConditionVariable cv = waitForConnectivityBroadcasts(1);
         mCellNetworkAgent.connect(true);
         waitFor(cv);
         verifyActiveNetwork(TRANSPORT_CELLULAR);
         // Test bringing up validated WiFi.
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         cv = waitForConnectivityBroadcasts(2);
         mWiFiNetworkAgent.connect(true);
         waitFor(cv);
@@ -1676,13 +1428,13 @@
     @Test
     public void testWiFiFallback() throws Exception {
         // Test bringing up unvalidated WiFi.
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         ConditionVariable cv = waitForConnectivityBroadcasts(1);
         mWiFiNetworkAgent.connect(false);
         waitFor(cv);
         verifyActiveNetwork(TRANSPORT_WIFI);
         // Test bringing up validated cellular.
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         cv = waitForConnectivityBroadcasts(2);
         mCellNetworkAgent.connect(true);
         waitFor(cv);
@@ -1760,7 +1512,7 @@
 
         // Test unvalidated networks
         ConditionVariable cv = waitForConnectivityBroadcasts(1);
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         mCellNetworkAgent.connect(false);
         genericNetworkCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
         cellNetworkCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
@@ -1775,7 +1527,7 @@
         assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
 
         cv = waitForConnectivityBroadcasts(2);
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(false);
         genericNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
         wifiNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
@@ -1799,7 +1551,7 @@
         assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
 
         // Test validated networks
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         mCellNetworkAgent.connect(true);
         genericNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
         cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
@@ -1812,7 +1564,7 @@
         assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
         assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
 
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(true);
         genericNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
         genericNetworkCallback.expectCallback(CallbackRecord.LOSING, mCellNetworkAgent);
@@ -1850,9 +1602,9 @@
         TestNetworkCallback defaultCallback = new TestNetworkCallback();
         mCm.registerDefaultNetworkCallback(defaultCallback);
 
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
-        mEthernetNetworkAgent = new MockNetworkAgent(TRANSPORT_ETHERNET);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
+        mEthernetNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_ETHERNET);
 
         mCellNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
         mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
@@ -1891,7 +1643,7 @@
         assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
 
         for (int i = 0; i < 4; i++) {
-            MockNetworkAgent oldNetwork, newNetwork;
+            TestNetworkAgentWrapper oldNetwork, newNetwork;
             if (i % 2 == 0) {
                 mWiFiNetworkAgent.adjustScore(-15);
                 oldNetwork = mWiFiNetworkAgent;
@@ -1943,7 +1695,7 @@
 
         mCm.registerNetworkCallback(request, callback);
 
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         mCellNetworkAgent.connect(false);   // Score: 10
         callback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
         defaultCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
@@ -1952,7 +1704,7 @@
 
         // Bring up wifi with a score of 20.
         // Cell stays up because it would satisfy the default request if it validated.
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(false);   // Score: 20
         callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
         defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
@@ -1968,7 +1720,7 @@
 
         // Bring up wifi with a score of 70.
         // Cell is lingered because it would not satisfy any request, even if it validated.
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.adjustScore(50);
         mWiFiNetworkAgent.connect(false);   // Score: 70
         callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
@@ -1987,7 +1739,7 @@
 
         // Bring up wifi, then validate it. Previous versions would immediately tear down cell, but
         // it's arguably correct to linger it, since it was the default network before it validated.
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(true);
         callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
         // TODO: Investigate sending validated before losing.
@@ -2008,12 +1760,12 @@
         assertEquals(null, mCm.getActiveNetwork());
 
         // If a network is lingering, and we add and remove a request from it, resume lingering.
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         mCellNetworkAgent.connect(true);
         callback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
         defaultCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
         assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(true);
         defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
         callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
@@ -2044,7 +1796,7 @@
         mCm.requestNetwork(cellRequest, noopCallback);
 
         // Now connect wifi, and expect it to become the default network.
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(true);
         callback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent);
         defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
@@ -2065,7 +1817,7 @@
         TestNetworkCallback trackDefaultCallback = new TestNetworkCallback();
         mCm.registerDefaultNetworkCallback(trackDefaultCallback);
         trackDefaultCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent);
-        mEthernetNetworkAgent = new MockNetworkAgent(TRANSPORT_ETHERNET);
+        mEthernetNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_ETHERNET);
         mEthernetNetworkAgent.connect(true);
         callback.expectAvailableCallbacksUnvalidated(mEthernetNetworkAgent);
         callback.expectCallback(CallbackRecord.LOSING, mWiFiNetworkAgent);
@@ -2100,8 +1852,8 @@
         TestNetworkCallback defaultCallback = new TestNetworkCallback();
         mCm.registerDefaultNetworkCallback(defaultCallback);
 
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
 
         mCellNetworkAgent.connect(true);
         callback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
@@ -2142,12 +1894,12 @@
         mCm.registerNetworkCallback(request, callback);
 
         // Bring up validated cell.
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         mCellNetworkAgent.connect(true);
         callback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
 
         // Bring up unvalidated wifi with explicitlySelected=true.
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.explicitlySelected(true, false);
         mWiFiNetworkAgent.connect(false);
         callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
@@ -2170,7 +1922,7 @@
         // Disconnect wifi, and then reconnect, again with explicitlySelected=true.
         mWiFiNetworkAgent.disconnect();
         callback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.explicitlySelected(true, false);
         mWiFiNetworkAgent.connect(false);
         callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
@@ -2181,7 +1933,7 @@
         callback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
 
         // Reconnect, again with explicitlySelected=true, but this time validate.
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.explicitlySelected(true, false);
         mWiFiNetworkAgent.connect(true);
         callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
@@ -2191,7 +1943,7 @@
 
         // BUG: the network will no longer linger, even though it's validated and outscored.
         // TODO: fix this.
-        mEthernetNetworkAgent = new MockNetworkAgent(TRANSPORT_ETHERNET);
+        mEthernetNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_ETHERNET);
         mEthernetNetworkAgent.connect(true);
         callback.expectAvailableThenValidatedCallbacks(mEthernetNetworkAgent);
         assertEquals(mEthernetNetworkAgent.getNetwork(), mCm.getActiveNetwork());
@@ -2202,7 +1954,7 @@
         // wifi immediately.
         mWiFiNetworkAgent.disconnect();
         callback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.explicitlySelected(true, true);
         mWiFiNetworkAgent.connect(false);
         callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
@@ -2215,7 +1967,7 @@
         // Check that the network is not scored specially and that the device prefers cell data.
         mWiFiNetworkAgent.disconnect();
         callback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.explicitlySelected(false, true);
         mWiFiNetworkAgent.connect(false);
         callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
@@ -2277,7 +2029,7 @@
         assertTrue(testFactory.getMyStartRequested());
 
         // Now bring in a higher scored network.
-        MockNetworkAgent testAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        TestNetworkAgentWrapper testAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         // Rather than create a validated network which complicates things by registering it's
         // own NetworkRequest during startup, just bump up the score to cancel out the
         // unvalidated penalty.
@@ -2371,18 +2123,17 @@
     @Test
     public void testMMSonWiFi() throws Exception {
         // Test bringing up cellular without MMS NetworkRequest gets reaped
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         mCellNetworkAgent.addCapability(NET_CAPABILITY_MMS);
-        ConditionVariable cv = mCellNetworkAgent.getDisconnectedCV();
         mCellNetworkAgent.connectWithoutInternet();
-        waitFor(cv);
+        mCellNetworkAgent.expectDisconnected();
         waitForIdle();
         assertEmpty(mCm.getAllNetworks());
         verifyNoNetwork();
 
         // Test bringing up validated WiFi.
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
-        cv = waitForConnectivityBroadcasts(1);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
+        final ConditionVariable cv = waitForConnectivityBroadcasts(1);
         mWiFiNetworkAgent.connect(true);
         waitFor(cv);
         verifyActiveNetwork(TRANSPORT_WIFI);
@@ -2394,23 +2145,22 @@
         mCm.requestNetwork(builder.build(), networkCallback);
 
         // Test bringing up unvalidated cellular with MMS
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         mCellNetworkAgent.addCapability(NET_CAPABILITY_MMS);
         mCellNetworkAgent.connectWithoutInternet();
         networkCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
         verifyActiveNetwork(TRANSPORT_WIFI);
 
         // Test releasing NetworkRequest disconnects cellular with MMS
-        cv = mCellNetworkAgent.getDisconnectedCV();
         mCm.unregisterNetworkCallback(networkCallback);
-        waitFor(cv);
+        mCellNetworkAgent.expectDisconnected();
         verifyActiveNetwork(TRANSPORT_WIFI);
     }
 
     @Test
     public void testMMSonCell() throws Exception {
         // Test bringing up cellular without MMS
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         ConditionVariable cv = waitForConnectivityBroadcasts(1);
         mCellNetworkAgent.connect(false);
         waitFor(cv);
@@ -2423,16 +2173,16 @@
         mCm.requestNetwork(builder.build(), networkCallback);
 
         // Test bringing up MMS cellular network
-        MockNetworkAgent mmsNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        TestNetworkAgentWrapper
+                mmsNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         mmsNetworkAgent.addCapability(NET_CAPABILITY_MMS);
         mmsNetworkAgent.connectWithoutInternet();
         networkCallback.expectAvailableCallbacksUnvalidated(mmsNetworkAgent);
         verifyActiveNetwork(TRANSPORT_CELLULAR);
 
         // Test releasing MMS NetworkRequest does not disconnect main cellular NetworkAgent
-        cv = mmsNetworkAgent.getDisconnectedCV();
         mCm.unregisterNetworkCallback(networkCallback);
-        waitFor(cv);
+        mmsNetworkAgent.expectDisconnected();
         verifyActiveNetwork(TRANSPORT_CELLULAR);
     }
 
@@ -2446,12 +2196,12 @@
         mCm.registerNetworkCallback(request, callback);
 
         // Bring up validated mobile data.
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         mCellNetworkAgent.connect(true);
         callback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
 
         // Bring up wifi with partial connectivity.
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connectWithPartialConnectivity();
         callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
         callback.expectCapabilitiesWith(NET_CAPABILITY_PARTIAL_CONNECTIVITY, mWiFiNetworkAgent);
@@ -2484,7 +2234,7 @@
         // Disconnect and reconnect wifi with partial connectivity again.
         mWiFiNetworkAgent.disconnect();
         callback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connectWithPartialConnectivity();
         callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
         callback.expectCapabilitiesWith(NET_CAPABILITY_PARTIAL_CONNECTIVITY, mWiFiNetworkAgent);
@@ -2500,7 +2250,7 @@
         // If user accepted partial connectivity before, and device reconnects to that network
         // again, but now the network has full connectivity. The network shouldn't contain
         // NET_CAPABILITY_PARTIAL_CONNECTIVITY.
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         // acceptUnvalidated is also used as setting for accepting partial networks.
         mWiFiNetworkAgent.explicitlySelected(true /* explicitlySelected */,
                 true /* acceptUnvalidated */);
@@ -2524,7 +2274,7 @@
         // The user accepted partial connectivity and selected "don't ask again". Now the user
         // reconnects to the partial connectivity network. Switch to wifi as soon as partial
         // connectivity is detected.
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.explicitlySelected(true /* explicitlySelected */,
                 true /* acceptUnvalidated */);
         mWiFiNetworkAgent.connectWithPartialConnectivity();
@@ -2548,7 +2298,7 @@
 
         // If the user accepted partial connectivity, and the device auto-reconnects to the partial
         // connectivity network, it should contain both PARTIAL_CONNECTIVITY and VALIDATED.
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.explicitlySelected(false /* explicitlySelected */,
                 true /* acceptUnvalidated */);
 
@@ -2580,7 +2330,7 @@
 
         // Bring up a network with a captive portal.
         // Expect onAvailable callback of listen for NET_CAPABILITY_CAPTIVE_PORTAL.
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         String redirectUrl = "http://android.com/path";
         mWiFiNetworkAgent.connectWithCaptivePortal(redirectUrl);
         captivePortalCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
@@ -2629,7 +2379,7 @@
 
         // Bring up a network with a captive portal.
         // Expect onAvailable callback of listen for NET_CAPABILITY_CAPTIVE_PORTAL.
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         String firstRedirectUrl = "http://example.com/firstPath";
         mWiFiNetworkAgent.connectWithCaptivePortal(firstRedirectUrl);
         captivePortalCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
@@ -2642,7 +2392,7 @@
 
         // Bring up a network with a captive portal.
         // Expect onAvailable callback of listen for NET_CAPABILITY_CAPTIVE_PORTAL.
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         String secondRedirectUrl = "http://example.com/secondPath";
         mWiFiNetworkAgent.connectWithCaptivePortal(secondRedirectUrl);
         captivePortalCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
@@ -2680,7 +2430,7 @@
         mCm.registerNetworkCallback(validatedRequest, validatedCallback);
 
         // Bring up wifi.
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(true);
         validatedCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
         Network wifiNetwork = mWiFiNetworkAgent.getNetwork();
@@ -2740,14 +2490,12 @@
         setCaptivePortalMode(Settings.Global.CAPTIVE_PORTAL_MODE_AVOID);
         // Bring up a network with a captive portal.
         // Expect it to fail to connect and not result in any callbacks.
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         String firstRedirectUrl = "http://example.com/firstPath";
 
-        ConditionVariable disconnectCv = mWiFiNetworkAgent.getDisconnectedCV();
-        ConditionVariable avoidCv = mWiFiNetworkAgent.getPreventReconnectReceived();
         mWiFiNetworkAgent.connectWithCaptivePortal(firstRedirectUrl);
-        waitFor(disconnectCv);
-        waitFor(avoidCv);
+        mWiFiNetworkAgent.expectDisconnected();
+        mWiFiNetworkAgent.expectPreventReconnectReceived();
 
         assertNoCallbacks(captivePortalCallback, validatedCallback);
     }
@@ -2846,7 +2594,7 @@
         LocalStringNetworkSpecifier nsFoo = new LocalStringNetworkSpecifier("foo");
         LocalStringNetworkSpecifier nsBar = new LocalStringNetworkSpecifier("bar");
 
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(false);
         cEmpty1.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
         cEmpty2.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
@@ -2973,7 +2721,7 @@
             public void writeToParcel(Parcel dest, int flags) {}
         }
 
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(false);
 
         UidAwareNetworkSpecifier networkSpecifier = new UidAwareNetworkSpecifier();
@@ -3026,14 +2774,14 @@
         cellNetworkCallback.assertNoCallback();
 
         // Bring up cell and expect CALLBACK_AVAILABLE.
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         mCellNetworkAgent.connect(true);
         cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
         defaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
         assertEquals(defaultNetworkCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
 
         // Bring up wifi and expect CALLBACK_AVAILABLE.
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(true);
         cellNetworkCallback.assertNoCallback();
         defaultNetworkCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
@@ -3046,7 +2794,7 @@
         assertEquals(defaultNetworkCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
 
         // Bring up cell. Expect no default network callback, since it won't be the default.
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         mCellNetworkAgent.connect(true);
         cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
         defaultNetworkCallback.assertNoCallback();
@@ -3065,7 +2813,8 @@
         assertEquals(null, mCm.getActiveNetwork());
 
         final int uid = Process.myUid();
-        final MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN);
+        final TestNetworkAgentWrapper
+                vpnNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_VPN);
         final ArraySet<UidRange> ranges = new ArraySet<>();
         ranges.add(new UidRange(uid, uid));
         mMockVpn.setNetworkAgent(vpnNetworkAgent);
@@ -3090,7 +2839,7 @@
         mCm.requestNetwork(cellRequest, cellNetworkCallback);
 
         // Bring up the mobile network.
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         mCellNetworkAgent.connect(true);
 
         // We should get onAvailable(), onCapabilitiesChanged(), and
@@ -3160,7 +2909,7 @@
         waitForIdle();
     }
 
-    private boolean isForegroundNetwork(MockNetworkAgent network) {
+    private boolean isForegroundNetwork(TestNetworkAgentWrapper network) {
         NetworkCapabilities nc = mCm.getNetworkCapabilities(network.getNetwork());
         assertNotNull(nc);
         return nc.hasCapability(NET_CAPABILITY_FOREGROUND);
@@ -3179,13 +2928,13 @@
         mCm.registerNetworkCallback(request, callback);
         mCm.registerNetworkCallback(fgRequest, fgCallback);
 
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         mCellNetworkAgent.connect(true);
         callback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
         fgCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
         assertTrue(isForegroundNetwork(mCellNetworkAgent));
 
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(true);
 
         // When wifi connects, cell lingers.
@@ -3278,7 +3027,7 @@
             }
         });
 
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         // Don't request that the network validate, because otherwise connect() will block until
         // the network gets NET_CAPABILITY_VALIDATED, after all the callbacks below have fired,
         // and we won't actually measure anything.
@@ -3295,7 +3044,7 @@
                 onAvailableDispatchingDuration <= CONNECT_TIME_LIMIT_MS);
 
         // Give wifi a high enough score that we'll linger cell when wifi comes up.
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.adjustScore(40);
         mWiFiNetworkAgent.connect(false);
 
@@ -3338,7 +3087,7 @@
         assertTrue(testFactory.getMyStartRequested());
 
         // Bring up wifi. The factory stops looking for a network.
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         // Score 60 - 40 penalty for not validated yet, then 60 when it validates
         testFactory.expectAddRequestsWithScores(20, 60);
         mWiFiNetworkAgent.connect(true);
@@ -3355,7 +3104,7 @@
 
         // Bring up cell data and check that the factory stops looking.
         assertLength(1, mCm.getAllNetworks());
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         testFactory.expectAddRequestsWithScores(10, 50);  // Unvalidated, then validated
         mCellNetworkAgent.connect(true);
         cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
@@ -3384,48 +3133,46 @@
     @Test
     public void testAvoidBadWifiSetting() throws Exception {
         final ContentResolver cr = mServiceContext.getContentResolver();
-        final WrappedMultinetworkPolicyTracker tracker = mService.getMultinetworkPolicyTracker();
         final String settingName = Settings.Global.NETWORK_AVOID_BAD_WIFI;
 
-        tracker.configRestrictsAvoidBadWifi = false;
+        mPolicyTracker.mConfigRestrictsAvoidBadWifi = false;
         String[] values = new String[] {null, "0", "1"};
         for (int i = 0; i < values.length; i++) {
             Settings.Global.putInt(cr, settingName, 1);
-            tracker.reevaluate();
+            mPolicyTracker.reevaluate();
             waitForIdle();
             String msg = String.format("config=false, setting=%s", values[i]);
             assertTrue(mService.avoidBadWifi());
-            assertFalse(msg, tracker.shouldNotifyWifiUnvalidated());
+            assertFalse(msg, mPolicyTracker.shouldNotifyWifiUnvalidated());
         }
 
-        tracker.configRestrictsAvoidBadWifi = true;
+        mPolicyTracker.mConfigRestrictsAvoidBadWifi = true;
 
         Settings.Global.putInt(cr, settingName, 0);
-        tracker.reevaluate();
+        mPolicyTracker.reevaluate();
         waitForIdle();
         assertFalse(mService.avoidBadWifi());
-        assertFalse(tracker.shouldNotifyWifiUnvalidated());
+        assertFalse(mPolicyTracker.shouldNotifyWifiUnvalidated());
 
         Settings.Global.putInt(cr, settingName, 1);
-        tracker.reevaluate();
+        mPolicyTracker.reevaluate();
         waitForIdle();
         assertTrue(mService.avoidBadWifi());
-        assertFalse(tracker.shouldNotifyWifiUnvalidated());
+        assertFalse(mPolicyTracker.shouldNotifyWifiUnvalidated());
 
         Settings.Global.putString(cr, settingName, null);
-        tracker.reevaluate();
+        mPolicyTracker.reevaluate();
         waitForIdle();
         assertFalse(mService.avoidBadWifi());
-        assertTrue(tracker.shouldNotifyWifiUnvalidated());
+        assertTrue(mPolicyTracker.shouldNotifyWifiUnvalidated());
     }
 
     @Test
     public void testAvoidBadWifi() throws Exception {
         final ContentResolver cr = mServiceContext.getContentResolver();
-        final WrappedMultinetworkPolicyTracker tracker = mService.getMultinetworkPolicyTracker();
 
         // Pretend we're on a carrier that restricts switching away from bad wifi.
-        tracker.configRestrictsAvoidBadWifi = true;
+        mPolicyTracker.mConfigRestrictsAvoidBadWifi = true;
 
         // File a request for cell to ensure it doesn't go down.
         final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback();
@@ -3444,17 +3191,17 @@
         mCm.registerNetworkCallback(validatedWifiRequest, validatedWifiCallback);
 
         Settings.Global.putInt(cr, Settings.Global.NETWORK_AVOID_BAD_WIFI, 0);
-        tracker.reevaluate();
+        mPolicyTracker.reevaluate();
 
         // Bring up validated cell.
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         mCellNetworkAgent.connect(true);
         cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
         defaultCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
         Network cellNetwork = mCellNetworkAgent.getNetwork();
 
         // Bring up validated wifi.
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(true);
         defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
         validatedWifiCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
@@ -3476,14 +3223,14 @@
 
         // Simulate switching to a carrier that does not restrict avoiding bad wifi, and expect
         // that we switch back to cell.
-        tracker.configRestrictsAvoidBadWifi = false;
-        tracker.reevaluate();
+        mPolicyTracker.mConfigRestrictsAvoidBadWifi = false;
+        mPolicyTracker.reevaluate();
         defaultCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
         assertEquals(mCm.getActiveNetwork(), cellNetwork);
 
         // Switch back to a restrictive carrier.
-        tracker.configRestrictsAvoidBadWifi = true;
-        tracker.reevaluate();
+        mPolicyTracker.mConfigRestrictsAvoidBadWifi = true;
+        mPolicyTracker.reevaluate();
         defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
         assertEquals(mCm.getActiveNetwork(), wifiNetwork);
 
@@ -3498,7 +3245,7 @@
 
         // Disconnect and reconnect wifi to clear the one-time switch above.
         mWiFiNetworkAgent.disconnect();
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(true);
         defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
         validatedWifiCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
@@ -3512,7 +3259,7 @@
 
         // Simulate the user selecting "switch" and checking the don't ask again checkbox.
         Settings.Global.putInt(cr, Settings.Global.NETWORK_AVOID_BAD_WIFI, 1);
-        tracker.reevaluate();
+        mPolicyTracker.reevaluate();
 
         // We now switch to cell.
         defaultCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
@@ -3525,11 +3272,11 @@
         // Simulate the user turning the cellular fallback setting off and then on.
         // We switch to wifi and then to cell.
         Settings.Global.putString(cr, Settings.Global.NETWORK_AVOID_BAD_WIFI, null);
-        tracker.reevaluate();
+        mPolicyTracker.reevaluate();
         defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
         assertEquals(mCm.getActiveNetwork(), wifiNetwork);
         Settings.Global.putInt(cr, Settings.Global.NETWORK_AVOID_BAD_WIFI, 1);
-        tracker.reevaluate();
+        mPolicyTracker.reevaluate();
         defaultCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
         assertEquals(mCm.getActiveNetwork(), cellNetwork);
 
@@ -3547,14 +3294,13 @@
     @Test
     public void testMeteredMultipathPreferenceSetting() throws Exception {
         final ContentResolver cr = mServiceContext.getContentResolver();
-        final WrappedMultinetworkPolicyTracker tracker = mService.getMultinetworkPolicyTracker();
         final String settingName = Settings.Global.NETWORK_METERED_MULTIPATH_PREFERENCE;
 
         for (int config : Arrays.asList(0, 3, 2)) {
             for (String setting: Arrays.asList(null, "0", "2", "1")) {
-                tracker.configMeteredMultipathPreference = config;
+                mPolicyTracker.mConfigMeteredMultipathPreference = config;
                 Settings.Global.putString(cr, settingName, setting);
-                tracker.reevaluate();
+                mPolicyTracker.reevaluate();
                 waitForIdle();
 
                 final int expected = (setting != null) ? Integer.parseInt(setting) : config;
@@ -3575,7 +3321,7 @@
         final TestNetworkCallback networkCallback = new TestNetworkCallback();
         mCm.requestNetwork(nr, networkCallback, TEST_REQUEST_TIMEOUT_MS);
 
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(false);
         networkCallback.expectAvailableCallbacks(mWiFiNetworkAgent, false, false, false,
                 TEST_CALLBACK_TIMEOUT_MS);
@@ -3595,7 +3341,7 @@
         final TestNetworkCallback networkCallback = new TestNetworkCallback();
         mCm.requestNetwork(nr, networkCallback, TEST_REQUEST_TIMEOUT_MS);
 
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(false);
         networkCallback.expectAvailableCallbacks(mWiFiNetworkAgent, false, false, false,
                 TEST_CALLBACK_TIMEOUT_MS);
@@ -3623,7 +3369,7 @@
         networkCallback.expectCallback(CallbackRecord.UNAVAILABLE, null);
 
         // create a network satisfying request - validate that request not triggered
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(false);
         networkCallback.assertNoCallback();
     }
@@ -3646,7 +3392,7 @@
         networkCallback.assertNoCallback();
 
         // create a network satisfying request - validate that request not triggered
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(false);
         networkCallback.assertNoCallback();
     }
@@ -3876,7 +3622,7 @@
             assertNull(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()));
         }
 
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         ConditionVariable cv = waitForConnectivityBroadcasts(1);
         mWiFiNetworkAgent.connect(true);
         waitFor(cv);
@@ -3940,10 +3686,10 @@
         callback.expectError(PacketKeepalive.ERROR_HARDWARE_UNSUPPORTED);
 
         // Check that a started keepalive can be stopped.
-        mWiFiNetworkAgent.setStartKeepaliveError(PacketKeepalive.SUCCESS);
+        mWiFiNetworkAgent.setStartKeepaliveEvent(PacketKeepalive.SUCCESS);
         ka = mCm.startNattKeepalive(myNet, validKaInterval, callback, myIPv4, 12345, dstIPv4);
         callback.expectStarted();
-        mWiFiNetworkAgent.setStopKeepaliveError(PacketKeepalive.SUCCESS);
+        mWiFiNetworkAgent.setStopKeepaliveEvent(PacketKeepalive.SUCCESS);
         ka.stop();
         callback.expectStopped();
 
@@ -3961,7 +3707,7 @@
         ka = mCm.startNattKeepalive(myNet, validKaInterval, callback, myIPv4, 12345, dstIPv4);
         callback.expectStarted();
         mWiFiNetworkAgent.disconnect();
-        waitFor(mWiFiNetworkAgent.getDisconnectedCV());
+        mWiFiNetworkAgent.expectDisconnected();
         callback.expectError(PacketKeepalive.ERROR_INVALID_NETWORK);
 
         // ... and that stopping it after that has no adverse effects.
@@ -3972,7 +3718,7 @@
 
         // Reconnect.
         myNet = connectKeepaliveNetwork(lp);
-        mWiFiNetworkAgent.setStartKeepaliveError(PacketKeepalive.SUCCESS);
+        mWiFiNetworkAgent.setStartKeepaliveEvent(PacketKeepalive.SUCCESS);
 
         // Check that keepalive slots start from 1 and increment. The first one gets slot 1.
         mWiFiNetworkAgent.setExpectedKeepaliveSlot(1);
@@ -4092,12 +3838,12 @@
         }
 
         // Check that a started keepalive can be stopped.
-        mWiFiNetworkAgent.setStartKeepaliveError(SocketKeepalive.SUCCESS);
+        mWiFiNetworkAgent.setStartKeepaliveEvent(SocketKeepalive.SUCCESS);
         try (SocketKeepalive ka = mCm.createSocketKeepalive(
                 myNet, testSocket, myIPv4, dstIPv4, executor, callback)) {
             ka.start(validKaInterval);
             callback.expectStarted();
-            mWiFiNetworkAgent.setStopKeepaliveError(SocketKeepalive.SUCCESS);
+            mWiFiNetworkAgent.setStopKeepaliveEvent(SocketKeepalive.SUCCESS);
             ka.stop();
             callback.expectStopped();
 
@@ -4137,7 +3883,7 @@
             ka.start(validKaInterval);
             callback.expectStarted();
             mWiFiNetworkAgent.disconnect();
-            waitFor(mWiFiNetworkAgent.getDisconnectedCV());
+            mWiFiNetworkAgent.expectDisconnected();
             callback.expectError(SocketKeepalive.ERROR_INVALID_NETWORK);
 
             // ... and that stopping it after that has no adverse effects.
@@ -4150,7 +3896,7 @@
 
         // Reconnect.
         myNet = connectKeepaliveNetwork(lp);
-        mWiFiNetworkAgent.setStartKeepaliveError(SocketKeepalive.SUCCESS);
+        mWiFiNetworkAgent.setStartKeepaliveEvent(SocketKeepalive.SUCCESS);
 
         // Check that keepalive slots start from 1 and increment. The first one gets slot 1.
         mWiFiNetworkAgent.setExpectedKeepaliveSlot(1);
@@ -4187,7 +3933,7 @@
         // assertFalse(isUdpPortInUse(srcPort2));
 
         mWiFiNetworkAgent.disconnect();
-        waitFor(mWiFiNetworkAgent.getDisconnectedCV());
+        mWiFiNetworkAgent.expectDisconnected();
         mWiFiNetworkAgent = null;
     }
 
@@ -4263,7 +4009,7 @@
         testSocketV6.close();
 
         mWiFiNetworkAgent.disconnect();
-        waitFor(mWiFiNetworkAgent.getDisconnectedCV());
+        mWiFiNetworkAgent.expectDisconnected();
         mWiFiNetworkAgent = null;
     }
 
@@ -4279,8 +4025,8 @@
         lp.addLinkAddress(new LinkAddress(myIPv4, 25));
         lp.addRoute(new RouteInfo(InetAddress.getByName("192.0.2.254")));
         Network myNet = connectKeepaliveNetwork(lp);
-        mWiFiNetworkAgent.setStartKeepaliveError(SocketKeepalive.SUCCESS);
-        mWiFiNetworkAgent.setStopKeepaliveError(SocketKeepalive.SUCCESS);
+        mWiFiNetworkAgent.setStartKeepaliveEvent(SocketKeepalive.SUCCESS);
+        mWiFiNetworkAgent.setStopKeepaliveEvent(SocketKeepalive.SUCCESS);
 
         TestSocketKeepaliveCallback callback = new TestSocketKeepaliveCallback(executor);
 
@@ -4316,7 +4062,7 @@
         // assertFalse(isUdpPortInUse(srcPort));
 
         mWiFiNetworkAgent.disconnect();
-        waitFor(mWiFiNetworkAgent.getDisconnectedCV());
+        mWiFiNetworkAgent.expectDisconnected();
         mWiFiNetworkAgent = null;
     }
 
@@ -4379,9 +4125,9 @@
         TestNetworkPinner.pin(mServiceContext, wifiRequest);
         assertNull(mCm.getBoundNetworkForProcess());
 
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         mCellNetworkAgent.connect(true);
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(false);
 
         // When wi-fi connects, expect to be pinned.
@@ -4394,7 +4140,7 @@
         assertNotPinnedToWifi();
 
         // Reconnecting does not cause the pin to come back.
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(false);
         assertFalse(TestNetworkPinner.awaitPin(100));
         assertNotPinnedToWifi();
@@ -4416,14 +4162,14 @@
 
         // Pinning takes effect even if the pinned network is the default when the pin is set...
         TestNetworkPinner.pin(mServiceContext, wifiRequest);
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(false);
         assertTrue(TestNetworkPinner.awaitPin(100));
         assertPinnedToWifiWithWifiDefault();
 
         // ... and is maintained even when that network is no longer the default.
         cv = waitForConnectivityBroadcasts(1);
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mCellNetworkAgent.connect(true);
         waitFor(cv);
         assertPinnedToWifiWithCellDefault();
@@ -4526,7 +4272,7 @@
         ConditionVariable broadcastCV = waitForConnectivityBroadcasts(1);
 
         verifyNoNetwork();
-        MockNetworkAgent wifiAware = new MockNetworkAgent(TRANSPORT_WIFI_AWARE);
+        TestNetworkAgentWrapper wifiAware = new TestNetworkAgentWrapper(TRANSPORT_WIFI_AWARE);
         assertNull(mCm.getActiveNetworkInfo());
 
         Network[] allNetworks = mCm.getAllNetworks();
@@ -4599,7 +4345,7 @@
 
         // Verify direct routes are added when network agent is first registered in
         // ConnectivityService.
-        MockNetworkAgent networkAgent = new MockNetworkAgent(TRANSPORT_WIFI, lp);
+        TestNetworkAgentWrapper networkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, lp);
         networkAgent.connect(true);
         networkCallback.expectCallback(CallbackRecord.AVAILABLE, networkAgent);
         networkCallback.expectCallback(CallbackRecord.NETWORK_CAPS_UPDATED, networkAgent);
@@ -4631,8 +4377,8 @@
 
     @Test
     public void testStatsIfacesChanged() throws Exception {
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
 
         Network[] onlyCell = new Network[] {mCellNetworkAgent.getNetwork()};
         Network[] onlyWifi = new Network[] {mWiFiNetworkAgent.getNetwork()};
@@ -4708,7 +4454,7 @@
         // Clear any interactions that occur as a result of CS starting up.
         reset(mMockDnsResolver);
 
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         waitForIdle();
         verify(mMockDnsResolver, never()).setResolverConfiguration(any());
         verifyNoMoreInteractions(mMockDnsResolver);
@@ -4791,7 +4537,7 @@
                 .addTransportType(TRANSPORT_CELLULAR).build();
         mCm.requestNetwork(cellRequest, cellNetworkCallback);
 
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         waitForIdle();
         // CS tells netd about the empty DNS config for this network.
         verify(mMockDnsResolver, never()).setResolverConfiguration(any());
@@ -4880,7 +4626,7 @@
                 .addTransportType(TRANSPORT_CELLULAR).build();
         mCm.requestNetwork(cellRequest, cellNetworkCallback);
 
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         waitForIdle();
         LinkProperties lp = new LinkProperties();
         mCellNetworkAgent.sendLinkProperties(lp);
@@ -5015,7 +4761,7 @@
         mCm.registerDefaultNetworkCallback(defaultCallback);
         defaultCallback.assertNoCallback();
 
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(false);
 
         genericNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
@@ -5025,14 +4771,16 @@
         vpnNetworkCallback.assertNoCallback();
         assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
 
-        final MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN);
+        final TestNetworkAgentWrapper
+                vpnNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_VPN);
         final ArraySet<UidRange> ranges = new ArraySet<>();
         ranges.add(new UidRange(uid, uid));
         mMockVpn.setNetworkAgent(vpnNetworkAgent);
         mMockVpn.setUids(ranges);
         // VPN networks do not satisfy the default request and are automatically validated
         // by NetworkMonitor
-        assertFalse(NetworkMonitorUtils.isValidationRequired(vpnNetworkAgent.mNetworkCapabilities));
+        assertFalse(NetworkMonitorUtils.isValidationRequired(
+                vpnNetworkAgent.getNetworkCapabilities()));
         vpnNetworkAgent.setNetworkValid();
 
         vpnNetworkAgent.connect(false);
@@ -5110,13 +4858,14 @@
         final TestNetworkCallback defaultCallback = new TestNetworkCallback();
         mCm.registerDefaultNetworkCallback(defaultCallback);
 
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(true);
 
         defaultCallback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent);
         assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
 
-        MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN);
+        TestNetworkAgentWrapper
+                vpnNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_VPN);
         final ArraySet<UidRange> ranges = new ArraySet<>();
         ranges.add(new UidRange(uid, uid));
         mMockVpn.setNetworkAgent(vpnNetworkAgent);
@@ -5140,13 +4889,14 @@
         final TestNetworkCallback defaultCallback = new TestNetworkCallback();
         mCm.registerDefaultNetworkCallback(defaultCallback);
 
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(true);
 
         defaultCallback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent);
         assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
 
-        MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN);
+        TestNetworkAgentWrapper
+                vpnNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_VPN);
         final ArraySet<UidRange> ranges = new ArraySet<>();
         ranges.add(new UidRange(uid, uid));
         mMockVpn.setNetworkAgent(vpnNetworkAgent);
@@ -5170,14 +4920,15 @@
         mCm.registerDefaultNetworkCallback(callback);
 
         // Bring up Ethernet.
-        mEthernetNetworkAgent = new MockNetworkAgent(TRANSPORT_ETHERNET);
+        mEthernetNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_ETHERNET);
         mEthernetNetworkAgent.connect(true);
         callback.expectAvailableThenValidatedCallbacks(mEthernetNetworkAgent);
         callback.assertNoCallback();
 
         // Bring up a VPN that has the INTERNET capability, initially unvalidated.
         final int uid = Process.myUid();
-        final MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN);
+        final TestNetworkAgentWrapper
+                vpnNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_VPN);
         final ArraySet<UidRange> ranges = new ArraySet<>();
         ranges.add(new UidRange(uid, uid));
         mMockVpn.setNetworkAgent(vpnNetworkAgent);
@@ -5199,9 +4950,10 @@
         assertFalse(nc.hasCapability(NET_CAPABILITY_VALIDATED));
         assertTrue(nc.hasCapability(NET_CAPABILITY_INTERNET));
 
-        assertFalse(NetworkMonitorUtils.isValidationRequired(vpnNetworkAgent.mNetworkCapabilities));
+        assertFalse(NetworkMonitorUtils.isValidationRequired(
+                vpnNetworkAgent.getNetworkCapabilities()));
         assertTrue(NetworkMonitorUtils.isPrivateDnsValidationRequired(
-                vpnNetworkAgent.mNetworkCapabilities));
+                vpnNetworkAgent.getNetworkCapabilities()));
 
         // Pretend that the VPN network validates.
         vpnNetworkAgent.setNetworkValid();
@@ -5229,7 +4981,8 @@
         mCm.registerNetworkCallback(vpnNetworkRequest, vpnNetworkCallback);
         vpnNetworkCallback.assertNoCallback();
 
-        final MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN);
+        final TestNetworkAgentWrapper
+                vpnNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_VPN);
         final ArraySet<UidRange> ranges = new ArraySet<>();
         ranges.add(new UidRange(uid, uid));
         mMockVpn.setNetworkAgent(vpnNetworkAgent);
@@ -5246,7 +4999,7 @@
         assertFalse(nc.hasCapability(NET_CAPABILITY_NOT_METERED));
 
         // Connect cell and use it as an underlying network.
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         mCellNetworkAgent.connect(true);
 
         mService.setUnderlyingNetworksForVpn(
@@ -5257,7 +5010,7 @@
                 && caps.hasTransport(TRANSPORT_CELLULAR) && !caps.hasTransport(TRANSPORT_WIFI)
                 && !caps.hasCapability(NET_CAPABILITY_NOT_METERED));
 
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
         mWiFiNetworkAgent.connect(true);
 
@@ -5327,7 +5080,8 @@
         mCm.registerNetworkCallback(vpnNetworkRequest, vpnNetworkCallback);
         vpnNetworkCallback.assertNoCallback();
 
-        final MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN);
+        final TestNetworkAgentWrapper
+                vpnNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_VPN);
         final ArraySet<UidRange> ranges = new ArraySet<>();
         ranges.add(new UidRange(uid, uid));
         mMockVpn.setNetworkAgent(vpnNetworkAgent);
@@ -5345,7 +5099,7 @@
         assertFalse(nc.hasCapability(NET_CAPABILITY_NOT_METERED));
 
         // Connect to Cell; Cell is the default network.
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         mCellNetworkAgent.connect(true);
 
         vpnNetworkCallback.expectCapabilitiesThat(vpnNetworkAgent,
@@ -5354,7 +5108,7 @@
                 && !caps.hasCapability(NET_CAPABILITY_NOT_METERED));
 
         // Connect to WiFi; WiFi is the new default.
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
         mWiFiNetworkAgent.connect(true);
 
@@ -5382,7 +5136,7 @@
     public void testIsActiveNetworkMeteredOverWifi() throws Exception {
         // Returns true by default when no network is available.
         assertTrue(mCm.isActiveNetworkMetered());
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
         mWiFiNetworkAgent.connect(true);
         waitForIdle();
@@ -5394,7 +5148,7 @@
     public void testIsActiveNetworkMeteredOverCell() throws Exception {
         // Returns true by default when no network is available.
         assertTrue(mCm.isActiveNetworkMetered());
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         mCellNetworkAgent.removeCapability(NET_CAPABILITY_NOT_METERED);
         mCellNetworkAgent.connect(true);
         waitForIdle();
@@ -5406,14 +5160,15 @@
     public void testIsActiveNetworkMeteredOverVpnTrackingPlatformDefault() throws Exception {
         // Returns true by default when no network is available.
         assertTrue(mCm.isActiveNetworkMetered());
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         mCellNetworkAgent.removeCapability(NET_CAPABILITY_NOT_METERED);
         mCellNetworkAgent.connect(true);
         waitForIdle();
         assertTrue(mCm.isActiveNetworkMetered());
 
         // Connect VPN network. By default it is using current default network (Cell).
-        MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN);
+        TestNetworkAgentWrapper
+                vpnNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_VPN);
         final ArraySet<UidRange> ranges = new ArraySet<>();
         final int uid = Process.myUid();
         ranges.add(new UidRange(uid, uid));
@@ -5429,7 +5184,7 @@
         assertTrue(mCm.isActiveNetworkMetered());
 
         // Connect WiFi.
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
         mWiFiNetworkAgent.connect(true);
         waitForIdle();
@@ -5460,20 +5215,21 @@
    public void testIsActiveNetworkMeteredOverVpnSpecifyingUnderlyingNetworks() throws Exception {
         // Returns true by default when no network is available.
         assertTrue(mCm.isActiveNetworkMetered());
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         mCellNetworkAgent.removeCapability(NET_CAPABILITY_NOT_METERED);
         mCellNetworkAgent.connect(true);
         waitForIdle();
         assertTrue(mCm.isActiveNetworkMetered());
 
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
         mWiFiNetworkAgent.connect(true);
         waitForIdle();
         assertFalse(mCm.isActiveNetworkMetered());
 
         // Connect VPN network.
-        MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN);
+        TestNetworkAgentWrapper
+                vpnNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_VPN);
         final ArraySet<UidRange> ranges = new ArraySet<>();
         final int uid = Process.myUid();
         ranges.add(new UidRange(uid, uid));
@@ -5531,14 +5287,15 @@
     public void testIsActiveNetworkMeteredOverAlwaysMeteredVpn() throws Exception {
         // Returns true by default when no network is available.
         assertTrue(mCm.isActiveNetworkMetered());
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
         mWiFiNetworkAgent.connect(true);
         waitForIdle();
         assertFalse(mCm.isActiveNetworkMetered());
 
         // Connect VPN network.
-        MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN);
+        TestNetworkAgentWrapper
+                vpnNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_VPN);
         final ArraySet<UidRange> ranges = new ArraySet<>();
         final int uid = Process.myUid();
         ranges.add(new UidRange(uid, uid));
@@ -5582,21 +5339,21 @@
                 .build();
         mCm.registerNetworkCallback(cellRequest, cellNetworkCallback);
 
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         mCellNetworkAgent.connect(true);
         cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
 
-        mService.setUidRulesChanged(RULE_REJECT_ALL);
+        setUidRulesChanged(RULE_REJECT_ALL);
         cellNetworkCallback.expectBlockedStatusCallback(true, mCellNetworkAgent);
 
         // ConnectivityService should cache it not to invoke the callback again.
-        mService.setUidRulesChanged(RULE_REJECT_METERED);
+        setUidRulesChanged(RULE_REJECT_METERED);
         cellNetworkCallback.assertNoCallback();
 
-        mService.setUidRulesChanged(RULE_NONE);
+        setUidRulesChanged(RULE_NONE);
         cellNetworkCallback.expectBlockedStatusCallback(false, mCellNetworkAgent);
 
-        mService.setUidRulesChanged(RULE_REJECT_METERED);
+        setUidRulesChanged(RULE_REJECT_METERED);
         cellNetworkCallback.expectBlockedStatusCallback(true, mCellNetworkAgent);
 
         // Restrict the network based on UID rule and NOT_METERED capability change.
@@ -5607,18 +5364,18 @@
         cellNetworkCallback.expectCapabilitiesWithout(NET_CAPABILITY_NOT_METERED,
                 mCellNetworkAgent);
         cellNetworkCallback.expectBlockedStatusCallback(true, mCellNetworkAgent);
-        mService.setUidRulesChanged(RULE_ALLOW_METERED);
+        setUidRulesChanged(RULE_ALLOW_METERED);
         cellNetworkCallback.expectBlockedStatusCallback(false, mCellNetworkAgent);
 
-        mService.setUidRulesChanged(RULE_NONE);
+        setUidRulesChanged(RULE_NONE);
         cellNetworkCallback.assertNoCallback();
 
         // Restrict the network based on BackgroundRestricted.
-        mService.setRestrictBackgroundChanged(true);
+        setRestrictBackgroundChanged(true);
         cellNetworkCallback.expectBlockedStatusCallback(true, mCellNetworkAgent);
-        mService.setRestrictBackgroundChanged(true);
+        setRestrictBackgroundChanged(true);
         cellNetworkCallback.assertNoCallback();
-        mService.setRestrictBackgroundChanged(false);
+        setRestrictBackgroundChanged(false);
         cellNetworkCallback.expectBlockedStatusCallback(false, mCellNetworkAgent);
         cellNetworkCallback.assertNoCallback();
 
@@ -5631,18 +5388,18 @@
         mCm.registerDefaultNetworkCallback(defaultCallback);
 
         // No Networkcallbacks invoked before any network is active.
-        mService.setUidRulesChanged(RULE_REJECT_ALL);
-        mService.setUidRulesChanged(RULE_NONE);
-        mService.setUidRulesChanged(RULE_REJECT_METERED);
+        setUidRulesChanged(RULE_REJECT_ALL);
+        setUidRulesChanged(RULE_NONE);
+        setUidRulesChanged(RULE_REJECT_METERED);
         defaultCallback.assertNoCallback();
 
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         mCellNetworkAgent.connect(true);
         defaultCallback.expectAvailableCallbacksUnvalidatedAndBlocked(mCellNetworkAgent);
         defaultCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mCellNetworkAgent);
 
         // Allow to use the network after switching to NOT_METERED network.
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
         mWiFiNetworkAgent.connect(true);
         defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
@@ -5658,8 +5415,8 @@
         defaultCallback.expectBlockedStatusCallback(false, mCellNetworkAgent);
 
         // Verify there's no Networkcallbacks invoked after data saver on/off.
-        mService.setRestrictBackgroundChanged(true);
-        mService.setRestrictBackgroundChanged(false);
+        setRestrictBackgroundChanged(true);
+        setRestrictBackgroundChanged(false);
         defaultCallback.assertNoCallback();
 
         mCellNetworkAgent.disconnect();
@@ -5709,7 +5466,7 @@
         mCm.registerNetworkCallback(networkRequest, networkCallback);
 
         // Prepare ipv6 only link properties.
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         final int cellNetId = mCellNetworkAgent.getNetwork().netId;
         final LinkProperties cellLp = new LinkProperties();
         cellLp.setInterfaceName(MOBILE_IFNAME);
@@ -5756,7 +5513,7 @@
         verify(mMockDnsResolver, times(1)).startPrefix64Discovery(cellNetId);
 
         // When NAT64 prefix discovery succeeds, LinkProperties are updated and clatd is started.
-        Nat464Xlat clat = mService.getNat464Xlat(mCellNetworkAgent);
+        Nat464Xlat clat = getNat464Xlat(mCellNetworkAgent);
         assertNull(mCm.getLinkProperties(mCellNetworkAgent.getNetwork()).getNat64Prefix());
         mService.mNetdEventCallback.onNat64PrefixEvent(cellNetId, true /* added */,
                 kNat64PrefixString, 96);
@@ -5863,7 +5620,7 @@
                 .build();
         mCm.registerNetworkCallback(networkRequest, networkCallback);
 
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         final LinkProperties cellLp = new LinkProperties();
         cellLp.setInterfaceName(MOBILE_IFNAME);
         mCellNetworkAgent.sendLinkProperties(cellLp);
@@ -5873,7 +5630,7 @@
         verify(mNetworkManagementService, times(1)).addIdleTimer(eq(MOBILE_IFNAME), anyInt(),
                 eq(ConnectivityManager.TYPE_MOBILE));
 
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         final LinkProperties wifiLp = new LinkProperties();
         wifiLp.setInterfaceName(WIFI_IFNAME);
         mWiFiNetworkAgent.sendLinkProperties(wifiLp);
@@ -5898,7 +5655,7 @@
                 eq(ConnectivityManager.TYPE_MOBILE));
 
         // reconnect wifi
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         wifiLp.setInterfaceName(WIFI_IFNAME);
         mWiFiNetworkAgent.sendLinkProperties(wifiLp);
         mWiFiNetworkAgent.connect(true);
@@ -5944,7 +5701,7 @@
     public void testTcpBufferReset() throws Exception {
         final String testTcpBufferSizes = "1,2,3,4,5,6";
 
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         reset(mMockNetd);
         // Switching default network updates TCP buffer sizes.
         mCellNetworkAgent.connect(false);
@@ -5960,7 +5717,7 @@
     @Test
     public void testGetGlobalProxyForNetwork() throws Exception {
         final ProxyInfo testProxyInfo = ProxyInfo.buildDirectProxy("test", 8888);
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         final Network wifiNetwork = mWiFiNetworkAgent.getNetwork();
         when(mService.mProxyTracker.getGlobalProxy()).thenReturn(testProxyInfo);
         assertEquals(testProxyInfo, mService.getProxyForNetwork(wifiNetwork));
@@ -5969,7 +5726,7 @@
     @Test
     public void testGetProxyForActiveNetwork() throws Exception {
         final ProxyInfo testProxyInfo = ProxyInfo.buildDirectProxy("test", 8888);
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(true);
         waitForIdle();
         assertNull(mService.getProxyForNetwork(null));
@@ -5988,14 +5745,15 @@
         final ProxyInfo testProxyInfo = ProxyInfo.buildDirectProxy("test", 8888);
 
         // Set up a WiFi network with no proxy
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(true);
         waitForIdle();
         assertNull(mService.getProxyForNetwork(null));
 
         // Set up a VPN network with a proxy
         final int uid = Process.myUid();
-        final MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN);
+        final TestNetworkAgentWrapper
+                vpnNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_VPN);
         final ArraySet<UidRange> ranges = new ArraySet<>();
         ranges.add(new UidRange(uid, uid));
         mMockVpn.setUids(ranges);
@@ -6044,7 +5802,7 @@
         lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null));
         // The uid range needs to cover the test app so the network is visible to it.
         final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(VPN_USER));
-        final MockNetworkAgent vpnNetworkAgent = establishVpn(lp, VPN_UID, vpnRange);
+        final TestNetworkAgentWrapper vpnNetworkAgent = establishVpn(lp, VPN_UID, vpnRange);
 
         // Connected VPN should have interface rules set up. There are two expected invocations,
         // one during VPN uid update, one during VPN LinkProperties update
@@ -6070,7 +5828,8 @@
         lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null));
         // The uid range needs to cover the test app so the network is visible to it.
         final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(VPN_USER));
-        final MockNetworkAgent vpnNetworkAgent = establishVpn(lp, Process.SYSTEM_UID, vpnRange);
+        final TestNetworkAgentWrapper vpnNetworkAgent = establishVpn(
+                lp, Process.SYSTEM_UID, vpnRange);
 
         // Legacy VPN should not have interface rules set up
         verify(mMockNetd, never()).firewallAddUidInterfaceRules(any(), any());
@@ -6085,7 +5844,8 @@
         lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), RTN_UNREACHABLE));
         // The uid range needs to cover the test app so the network is visible to it.
         final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(VPN_USER));
-        final MockNetworkAgent vpnNetworkAgent = establishVpn(lp, Process.SYSTEM_UID, vpnRange);
+        final TestNetworkAgentWrapper vpnNetworkAgent = establishVpn(
+                lp, Process.SYSTEM_UID, vpnRange);
 
         // IPv6 unreachable route should not be misinterpreted as a default route
         verify(mMockNetd, never()).firewallAddUidInterfaceRules(any(), any());
@@ -6098,7 +5858,7 @@
         lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null));
         // The uid range needs to cover the test app so the network is visible to it.
         final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(VPN_USER));
-        final MockNetworkAgent vpnNetworkAgent = establishVpn(lp, VPN_UID, vpnRange);
+        final TestNetworkAgentWrapper vpnNetworkAgent = establishVpn(lp, VPN_UID, vpnRange);
 
         // Connected VPN should have interface rules set up. There are two expected invocations,
         // one during VPN uid update, one during VPN LinkProperties update
@@ -6147,7 +5907,7 @@
         lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null));
         // The uid range needs to cover the test app so the network is visible to it.
         final UidRange vpnRange = UidRange.createForUser(VPN_USER);
-        final MockNetworkAgent vpnNetworkAgent = establishVpn(lp, VPN_UID,
+        final TestNetworkAgentWrapper vpnNetworkAgent = establishVpn(lp, VPN_UID,
                 Collections.singleton(vpnRange));
 
         reset(mMockNetd);
@@ -6169,9 +5929,10 @@
     }
 
 
-    private MockNetworkAgent establishVpn(LinkProperties lp, int establishingUid,
+    private TestNetworkAgentWrapper establishVpn(LinkProperties lp, int establishingUid,
             Set<UidRange> vpnRange) throws Exception {
-        final MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN, lp);
+        final TestNetworkAgentWrapper
+                vpnNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_VPN, lp);
         vpnNetworkAgent.getNetworkCapabilities().setEstablishingVpnAppUid(establishingUid);
         mMockVpn.setNetworkAgent(vpnNetworkAgent);
         mMockVpn.connect();
diff --git a/tools/aapt2/dump/DumpManifest.cpp b/tools/aapt2/dump/DumpManifest.cpp
index 54f0816..31aa249 100644
--- a/tools/aapt2/dump/DumpManifest.cpp
+++ b/tools/aapt2/dump/DumpManifest.cpp
@@ -468,14 +468,12 @@
     }
     if (platformVersionName) {
       printer->Print(StringPrintf(" platformBuildVersionName='%s'", platformVersionName->data()));
-    }
-    if (platformVersionNameInt) {
+    } else if (platformVersionNameInt) {
       printer->Print(StringPrintf(" platformBuildVersionName='%d'", *platformVersionNameInt));
     }
     if (platformVersionCode) {
       printer->Print(StringPrintf(" platformBuildVersionCode='%s'", platformVersionCode->data()));
-    }
-    if (platformVersionCodeInt) {
+    } else if (platformVersionCodeInt) {
       printer->Print(StringPrintf(" platformBuildVersionCode='%d'", *platformVersionCodeInt));
     }
     if (compilesdkVersion) {
diff --git a/tools/aapt2/optimize/ResourcePathShortener.cpp b/tools/aapt2/optimize/ResourcePathShortener.cpp
index 7f5d104..7ff9bf5 100644
--- a/tools/aapt2/optimize/ResourcePathShortener.cpp
+++ b/tools/aapt2/optimize/ResourcePathShortener.cpp
@@ -16,6 +16,7 @@
 
 #include "optimize/ResourcePathShortener.h"
 
+#include <set>
 #include <unordered_set>
 
 #include "androidfw/StringPiece.h"
@@ -71,10 +72,19 @@
   return shortened_path;
 }
 
+// implement custom comparator of FileReference pointers so as to use the
+// underlying filepath as key rather than the integer address. This is to ensure
+// determinism of output for colliding files.
+struct PathComparator {
+    bool operator() (const FileReference* lhs, const FileReference* rhs) const {
+        return lhs->path->compare(*rhs->path);
+    }
+};
+
 bool ResourcePathShortener::Consume(IAaptContext* context, ResourceTable* table) {
   // used to detect collisions
   std::unordered_set<std::string> shortened_paths;
-  std::unordered_set<FileReference*> file_refs;
+  std::set<FileReference*, PathComparator> file_refs;
   for (auto& package : table->packages) {
     for (auto& type : package->types) {
       for (auto& entry : type->entries) {
diff --git a/tools/aapt2/optimize/ResourcePathShortener_test.cpp b/tools/aapt2/optimize/ResourcePathShortener_test.cpp
index 1f45694..f5a02be 100644
--- a/tools/aapt2/optimize/ResourcePathShortener_test.cpp
+++ b/tools/aapt2/optimize/ResourcePathShortener_test.cpp
@@ -29,6 +29,14 @@
   return android::StringPiece(iter, path.end() - iter);
 }
 
+void FillTable(aapt::test::ResourceTableBuilder& builder, int start, int end) {
+  for (int i=start; i<end; i++) {
+    builder.AddFileReference(
+        "android:drawable/xmlfile" + std::to_string(i),
+        "res/drawable/xmlfile" + std::to_string(i) + ".xml");
+  }
+}
+
 namespace aapt {
 
 TEST(ResourcePathShortenerTest, FileRefPathsChangedInResourceTable) {
@@ -114,4 +122,45 @@
   EXPECT_THAT(GetExtension(path_map[original_png_path]), Eq(android::StringPiece(".png")));
 }
 
+TEST(ResourcePathShortenerTest, DeterministicallyHandleCollisions) {
+  std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
+
+  // 4000 resources is the limit at which the hash space is expanded to 3
+  // letters to reduce collisions, we want as many collisions as possible thus
+  // N-1.
+  const auto kNumResources = 3999;
+  const auto kNumTries = 5;
+
+  test::ResourceTableBuilder builder1;
+  FillTable(builder1, 0, kNumResources);
+  std::unique_ptr<ResourceTable> table1 = builder1.Build();
+  std::map<std::string, std::string> expected_mapping;
+  ASSERT_TRUE(ResourcePathShortener(expected_mapping).Consume(context.get(), table1.get()));
+
+  // We are trying to ensure lack of non-determinism, it is not simple to prove
+  // a negative, thus we must try the test a few times so that the test itself
+  // is non-flaky. Basically create the pathmap 5 times from the same set of
+  // resources but a different order of addition and then ensure they are always
+  // mapped to the same short path.
+  for (int i=0; i<kNumTries; i++) {
+    test::ResourceTableBuilder builder2;
+    // This loop adds resources to the resource table in the range of
+    // [0:kNumResources).  Adding the file references in different order makes
+    // non-determinism more likely to surface. Thus we add resources
+    // [start_index:kNumResources) first then [0:start_index). We also use a
+    // different start_index each run.
+    int start_index = (kNumResources/kNumTries)*i;
+    FillTable(builder2, start_index, kNumResources);
+    FillTable(builder2, 0, start_index);
+    std::unique_ptr<ResourceTable> table2 = builder2.Build();
+
+    std::map<std::string, std::string> actual_mapping;
+    ASSERT_TRUE(ResourcePathShortener(actual_mapping).Consume(context.get(), table2.get()));
+
+    for (auto& item : actual_mapping) {
+      ASSERT_THAT(expected_mapping[item.first], Eq(item.second));
+    }
+  }
+}
+
 }   // namespace aapt
diff --git a/tools/codegen/src/com/android/codegen/ClassInfo.kt b/tools/codegen/src/com/android/codegen/ClassInfo.kt
index 7ee79f6..5061be2 100644
--- a/tools/codegen/src/com/android/codegen/ClassInfo.kt
+++ b/tools/codegen/src/com/android/codegen/ClassInfo.kt
@@ -1,30 +1,39 @@
 package com.android.codegen
 
-import com.github.javaparser.JavaParser
 import com.github.javaparser.ParseProblemException
+import com.github.javaparser.ParseResult
+import com.github.javaparser.ast.CompilationUnit
 import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration
 
 open class ClassInfo(val sourceLines: List<String>) {
 
     private val userSourceCode = (sourceLines + "}").joinToString("\n")
-    val fileAst = try {
-        JavaParser.parse(userSourceCode)!!
+    val fileAst: CompilationUnit = try {
+        JAVA_PARSER.parse(userSourceCode).throwIfFailed()
     } catch (e: ParseProblemException) {
-        throw RuntimeException("Failed to parse code:\n" +
+        throw parseFailed(cause = e)
+    }
+
+    fun <T> ParseResult<T>.throwIfFailed(): T {
+        if (problems.isNotEmpty()) {
+            throw parseFailed(
+                    desc = this@throwIfFailed.problems.joinToString("\n"),
+                    cause = this@throwIfFailed.problems.mapNotNull { it.cause.orElse(null) }.firstOrNull())
+        }
+        return result.get()
+    }
+
+    private fun parseFailed(cause: Throwable? = null, desc: String = ""): RuntimeException {
+        return RuntimeException("Failed to parse code:\n" +
                 userSourceCode
                         .lines()
                         .mapIndexed { lnNum, ln -> "/*$lnNum*/$ln" }
-                        .joinToString("\n"),
-                e)
+                        .joinToString("\n") + "\n$desc",
+                cause)
     }
-    val classAst = fileAst.types[0] as ClassOrInterfaceDeclaration
 
-    fun hasMethod(name: String, vararg argTypes: String): Boolean {
-        return classAst.methods.any {
-            it.name.asString() == name &&
-                    it.parameters.map { it.type.asString() } == argTypes.toList()
-        }
-    }
+    val classAst = fileAst.types[0] as ClassOrInterfaceDeclaration
+    val nestedClasses = classAst.members.filterIsInstance<ClassOrInterfaceDeclaration>()
 
     val superInterfaces = (fileAst.types[0] as ClassOrInterfaceDeclaration)
             .implementedTypes.map { it.asString() }
@@ -42,8 +51,4 @@
             .filterNot { it.isTransient || it.isStatic }
             .mapIndexed { i, node -> FieldInfo(index = i, fieldAst = node, classInfo = this) }
             .apply { lastOrNull()?.isLast = true }
-    val lazyTransientFields = classAst.fields
-            .filter { it.isTransient && !it.isStatic }
-            .mapIndexed { i, node -> FieldInfo(index = i, fieldAst = node, classInfo = this) }
-            .filter { hasMethod("lazyInit${it.NameUpperCamel}") }
 }
\ No newline at end of file
diff --git a/tools/codegen/src/com/android/codegen/ClassPrinter.kt b/tools/codegen/src/com/android/codegen/ClassPrinter.kt
index 33256b7..1f0d4b8 100644
--- a/tools/codegen/src/com/android/codegen/ClassPrinter.kt
+++ b/tools/codegen/src/com/android/codegen/ClassPrinter.kt
@@ -1,9 +1,9 @@
 package com.android.codegen
 
+import com.github.javaparser.ast.Modifier
 import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration
 import com.github.javaparser.ast.body.TypeDeclaration
-import com.github.javaparser.ast.expr.BooleanLiteralExpr
-import com.github.javaparser.ast.expr.NormalAnnotationExpr
+import com.github.javaparser.ast.expr.*
 import com.github.javaparser.ast.type.ClassOrInterfaceType
 
 /**
@@ -32,10 +32,31 @@
     val PluralOf by lazy { classRef("com.android.internal.util.DataClass.PluralOf") }
     val Each by lazy { classRef("com.android.internal.util.DataClass.Each") }
     val DataClassGenerated by lazy { classRef("com.android.internal.util.DataClass.Generated") }
+    val DataClassSuppressConstDefs by lazy { classRef("com.android.internal.util.DataClass.SuppressConstDefsGeneration") }
+    val DataClassSuppress by lazy { classRef("com.android.internal.util.DataClass.Suppress") }
     val GeneratedMember by lazy { classRef("com.android.internal.util.DataClass.Generated.Member") }
     val Parcelling by lazy { classRef("com.android.internal.util.Parcelling") }
+    val Parcelable by lazy { classRef("android.os.Parcelable") }
     val UnsupportedAppUsage by lazy { classRef("android.annotation.UnsupportedAppUsage") }
 
+    init {
+        val fieldsWithMissingNullablity = fields.filter { field ->
+            !field.isPrimitive
+                    && field.fieldAst.modifiers.none { it.keyword == Modifier.Keyword.TRANSIENT }
+                    && "@$Nullable" !in field.annotations
+                    && "@$NonNull" !in field.annotations
+        }
+        if (fieldsWithMissingNullablity.isNotEmpty()) {
+            abort("Non-primitive fields must have @$Nullable or @$NonNull annotation.\n" +
+                    "Missing nullability annotations on: "
+                    + fieldsWithMissingNullablity.joinToString(", ") { it.name })
+        }
+
+        if (!classAst.isFinal &&
+                classAst.extendedTypes.any { it.nameAsString == Parcelable }) {
+            abort("Parcelable classes must be final")
+        }
+    }
 
     /**
      * Optionally shortens a class reference if there's a corresponding import present
@@ -54,7 +75,7 @@
             return simpleName
         } else {
             val outerClass = pkg.substringAfterLast(".", "")
-            if (outerClass.firstOrNull()?.isUpperCase() ?: false) {
+            if (outerClass.firstOrNull()?.isUpperCase() == true) {
                 return classRef(pkg) + "." + simpleName
             }
         }
@@ -89,7 +110,9 @@
             ?.toMap()
             ?: emptyMap()
 
-    val internalAnnotations = setOf(ParcelWith, DataClassEnum, PluralOf, Each, UnsupportedAppUsage)
+    val internalAnnotations = setOf(ParcelWith, DataClassEnum, PluralOf, UnsupportedAppUsage,
+            DataClassSuppressConstDefs)
+    val knownNonValidationAnnotations = internalAnnotations + Each + Nullable
 
     /**
      * @return whether the given feature is enabled
@@ -99,9 +122,13 @@
         if (cliArgs.contains("--$kebabCase")) return true
 
         val annotationKey = "gen$upperCamelCase"
+        val annotationHiddenKey = "genHidden$upperCamelCase"
         if (dataClassAnnotationFeatures.containsKey(annotationKey)) {
             return dataClassAnnotationFeatures[annotationKey]!!
         }
+        if (dataClassAnnotationFeatures.containsKey(annotationHiddenKey)) {
+            return dataClassAnnotationFeatures[annotationHiddenKey]!!
+        }
 
         if (cliArgs.contains("--all")) return true
         if (hidden) return true
@@ -109,7 +136,9 @@
         return when (this) {
             FeatureFlag.SETTERS ->
                 !FeatureFlag.CONSTRUCTOR() && !FeatureFlag.BUILDER() && fields.any { !it.isFinal }
-            FeatureFlag.BUILDER -> cliArgs.contains(FLAG_BUILDER_PROTECTED_SETTERS) || onByDefault
+            FeatureFlag.BUILDER -> cliArgs.contains(FLAG_BUILDER_PROTECTED_SETTERS)
+                    || fields.any { it.hasDefault }
+                    || onByDefault
             FeatureFlag.CONSTRUCTOR -> !FeatureFlag.BUILDER()
             FeatureFlag.PARCELABLE -> "Parcelable" in superInterfaces
             FeatureFlag.AIDL -> FeatureFlag.PARCELABLE()
@@ -119,11 +148,17 @@
         }
     }
 
-    val FeatureFlag.hidden
-        get(): Boolean = when {
-            cliArgs.contains("--hidden-$kebabCase") -> true
-            this == FeatureFlag.BUILD_UPON -> FeatureFlag.BUILDER.hidden
-            else -> false
+    val FeatureFlag.hidden: Boolean
+        get(): Boolean {
+            val annotationHiddenKey = "genHidden$upperCamelCase"
+            if (dataClassAnnotationFeatures.containsKey(annotationHiddenKey)) {
+                return dataClassAnnotationFeatures[annotationHiddenKey]!!
+            }
+            return when {
+                cliArgs.contains("--hidden-$kebabCase") -> true
+                this == FeatureFlag.BUILD_UPON -> FeatureFlag.BUILDER.hidden
+                else -> false
+            }
         }
 
     var currentIndent = INDENT_SINGLE
@@ -287,6 +322,48 @@
 
     var BuilderClass = CANONICAL_BUILDER_CLASS
     var BuilderType = BuilderClass + genericArgs
+    val customBaseBuilderAst: ClassOrInterfaceDeclaration? by lazy {
+        nestedClasses.find { it.nameAsString == BASE_BUILDER_CLASS }
+    }
+
+    val suppressedMembers by lazy {
+        getSuppressedMembers(classAst)
+    }
+    val builderSuppressedMembers by lazy {
+        getSuppressedMembers(customBaseBuilderAst)
+    }
+
+    private fun getSuppressedMembers(clazz: ClassOrInterfaceDeclaration?): List<String> {
+        return clazz
+                ?.annotations
+                ?.find { it.nameAsString == DataClassSuppress }
+                ?.as_<SingleMemberAnnotationExpr>()
+                ?.memberValue
+                ?.run {
+                    when (this) {
+                        is ArrayInitializerExpr -> values.map { it.asLiteralStringValueExpr().value }
+                        is StringLiteralExpr -> listOf(value)
+                        else -> abort("Can't parse annotation arg: $this")
+                    }
+                }
+                ?: emptyList()
+    }
+
+    fun isMethodGenerationSuppressed(name: String, vararg argTypes: String): Boolean {
+        return name in suppressedMembers || hasMethod(name, *argTypes)
+    }
+
+    fun hasMethod(name: String, vararg argTypes: String): Boolean {
+        return classAst.methods.any {
+            it.name.asString() == name &&
+                    it.parameters.map { it.type.asString() } == argTypes.toList()
+        }
+    }
+
+    val lazyTransientFields = classAst.fields
+            .filter { it.isTransient && !it.isStatic }
+            .mapIndexed { i, node -> FieldInfo(index = i, fieldAst = node, classInfo = this) }
+            .filter { hasMethod("lazyInit${it.NameUpperCamel}") }
 
     init {
         val builderFactoryOverride = classAst.methods.find {
@@ -301,7 +378,7 @@
                 it.nameAsString == CANONICAL_BUILDER_CLASS
             }
             if (builderExtension != null) {
-                BuilderClass = GENERATED_BUILDER_CLASS
+                BuilderClass = BASE_BUILDER_CLASS
                 val tp = (builderExtension as ClassOrInterfaceDeclaration).typeParameters
                 BuilderType = if (tp.isEmpty()) BuilderClass
                 else "$BuilderClass<${tp.map { it.nameAsString }.joinToString(", ")}>"
diff --git a/tools/codegen/src/com/android/codegen/FieldInfo.kt b/tools/codegen/src/com/android/codegen/FieldInfo.kt
index f326fd5..ba00264 100644
--- a/tools/codegen/src/com/android/codegen/FieldInfo.kt
+++ b/tools/codegen/src/com/android/codegen/FieldInfo.kt
@@ -1,6 +1,5 @@
 package com.android.codegen
 
-import com.github.javaparser.JavaParser
 import com.github.javaparser.ast.body.FieldDeclaration
 import com.github.javaparser.ast.expr.ClassExpr
 import com.github.javaparser.ast.expr.Name
@@ -9,7 +8,6 @@
 import com.github.javaparser.ast.type.ArrayType
 import com.github.javaparser.ast.type.ClassOrInterfaceType
 import com.github.javaparser.javadoc.Javadoc
-import java.lang.Long
 
 data class FieldInfo(
     val index: Int,
@@ -85,8 +83,7 @@
             variableAst.initializer.orElse(null)?.let { return it }
             classInfo.classAst.methods.find {
                 it.nameAsString == "default$NameUpperCamel" && it.parameters.isEmpty()
-            }?.run { "$nameAsString()" }?.let { return it }
-            if (FieldClass == "List") return "${classPrinter.memberRef("java.util.Collections.emptyList")}()"
+            }?.run { return "$nameAsString()" }
             return null
         }
     val hasDefault get() = defaultExpr != null
@@ -95,7 +92,7 @@
     // Generic args
     val isArray = Type.endsWith("[]")
     val isList = FieldClass == "List" || FieldClass == "ArrayList"
-    val fieldBit = "0x${Long.toHexString(1L shl index)}"
+    val fieldBit = bitAtExpr(index)
     var isLast = false
     val isFinal = fieldAst.isFinal
     val fieldTypeGenegicArgs = when (typeAst) {
@@ -116,8 +113,9 @@
             classPrinter {
                 fieldAst.addAnnotation(SingleMemberAnnotationExpr(
                         Name(ParcelWith),
-                        ClassExpr(JavaParser.parseClassOrInterfaceType(
-                                "$Parcelling.BuiltIn.For$FieldClass"))))
+                        ClassExpr(JAVA_PARSER
+                                .parseClassOrInterfaceType("$Parcelling.BuiltIn.For$FieldClass")
+                                .throwIfFailed())))
             }
         }
         fieldAst.annotations.map { it.removeComment().toString() }
@@ -143,8 +141,10 @@
     }
     val annotationsAndType by lazy { (annotationsNoInternal + Type).joinToString(" ") }
     val sParcelling by lazy { customParcellingClass?.let { "sParcellingFor$NameUpperCamel" } }
+
+    val SetterParamType = if (isArray) "$FieldInnerType..." else Type
     val annotatedTypeForSetterParam by lazy {
-        (annotationsNoInternal + if (isArray) "$FieldInnerType..." else Type).joinToString(" ")
+        (annotationsNoInternal + SetterParamType).joinToString(" ")
     }
 
     // Utilities
diff --git a/tools/codegen/src/com/android/codegen/Generators.kt b/tools/codegen/src/com/android/codegen/Generators.kt
index ab64f4e..914e475 100644
--- a/tools/codegen/src/com/android/codegen/Generators.kt
+++ b/tools/codegen/src/com/android/codegen/Generators.kt
@@ -1,6 +1,7 @@
 package com.android.codegen
 
 import com.github.javaparser.ast.body.FieldDeclaration
+import com.github.javaparser.ast.body.MethodDeclaration
 import com.github.javaparser.ast.body.VariableDeclarator
 import com.github.javaparser.ast.expr.*
 import java.io.File
@@ -16,7 +17,7 @@
             val isLiteral = initializer is LiteralExpr
                     || (initializer is UnaryExpr && initializer.expression is LiteralExpr)
             isLiteral && variable.type.asString() in listOf("int", "String")
-        }
+        } && it.annotations.none { it.nameAsString == DataClassSuppressConstDefs }
     }.flatMap { field -> field.variables.map { it to field } }
     val intConsts = consts.filter { it.first.type.asString() == "int" }
     val strConsts = consts.filter { it.first.type.asString() == "String" }
@@ -67,12 +68,15 @@
         }
     }
 
-    val visibility = if (consts[0].second.isPublic) "public" else "/* package-*/"
+    val visibility = if (consts[0].second.isPublic) "public" else "/* package-private */"
 
     val Retention = classRef("java.lang.annotation.Retention")
     val RetentionPolicySource = memberRef("java.lang.annotation.RetentionPolicy.SOURCE")
     val ConstDef = classRef("android.annotation.${type.capitalize()}Def")
 
+    if (FeatureFlag.CONST_DEFS.hidden) {
+        +"/** @hide */"
+    }
     "@$ConstDef(${if_(flag, "flag = true, ")}prefix = \"${prefix}_\", value = {" {
         names.forEachLastAware { name, isLast ->
             +"$name${if_(!isLast, ",")}"
@@ -84,6 +88,9 @@
     +""
 
     if (type == "int") {
+        if (FeatureFlag.CONST_DEFS.hidden) {
+            +"/** @hide */"
+        }
         +GENERATED_MEMBER_HEADER
         val methodDefLine = "$visibility static String ${AnnotationName.decapitalize()}ToString(" +
                 "@$AnnotationName int value)"
@@ -131,7 +138,7 @@
 fun ClassPrinter.generateWithers() {
     fields.forEachApply {
         val metodName = "with$NameUpperCamel"
-        if (!hasMethod(metodName, Type)) {
+        if (!isMethodGenerationSuppressed(metodName, Type)) {
             generateFieldJavadoc(forceHide = FeatureFlag.WITHERS.hidden)
             """@$NonNull
                         $GENERATED_MEMBER_HEADER
@@ -171,7 +178,7 @@
  * ```
  */
 fun ClassPrinter.generateBuildUpon() {
-    if (hasMethod("buildUpon")) return
+    if (isMethodGenerationSuppressed("buildUpon")) return
 
     +"/**"
     +" * Provides an instance of {@link $BuilderClass} with state corresponding to this instance."
@@ -195,7 +202,15 @@
     val constructorVisibility = if (BuilderClass == CANONICAL_BUILDER_CLASS)
         "public" else "/* package-*/"
 
-    val OneTimeUseBuilder = classRef("android.provider.OneTimeUseBuilder")
+    val providedSubclassAst = nestedClasses.find {
+        it.extendedTypes.any { it.nameAsString == BASE_BUILDER_CLASS }
+    }
+
+    val BuilderSupertype = if (customBaseBuilderAst != null) {
+        customBaseBuilderAst!!.nameAsString
+    } else {
+        "Object"
+    }
 
     +"/**"
     +" * A builder for {@link $ClassName}"
@@ -203,104 +218,155 @@
     +" */"
     +"@SuppressWarnings(\"WeakerAccess\")"
     +GENERATED_MEMBER_HEADER
-    "public static class $BuilderClass$genericArgs" {
-        +"extends $OneTimeUseBuilder<$ClassType>"
+    !"public static class $BuilderClass$genericArgs"
+    if (BuilderSupertype != "Object") {
+        appendSameLine(" extends $BuilderSupertype")
     }
     " {" {
 
         +""
         fields.forEachApply {
-            +"protected $annotationsAndType $name;"
+            +"private $annotationsAndType $name;"
         }
         +""
-        +"protected long mBuilderFieldsSet = 0L;"
+        +"private long mBuilderFieldsSet = 0L;"
         +""
-        +"$constructorVisibility $BuilderClass() {};"
-        +""
+
+        val requiredFields = fields.filter { !it.hasDefault }
+
+        generateConstructorJavadoc(
+                fields = requiredFields,
+                ClassName = BuilderClass,
+                hidden = false)
+        "$constructorVisibility $BuilderClass(" {
+            requiredFields.forEachLastAware { field, isLast ->
+                +"${field.annotationsAndType} ${field._name}${if_(!isLast, ",")}"
+            }
+        }; " {" {
+            requiredFields.forEachApply {
+                generateSetFrom(_name)
+            }
+        }
 
         generateBuilderSetters(setterVisibility)
 
         generateBuilderBuild()
 
+        "private void checkNotUsed() {" {
+            "if ((mBuilderFieldsSet & ${bitAtExpr(fields.size)}) != 0)" {
+                "throw new IllegalStateException(" {
+                    +"\"This Builder should not be reused. Use a new Builder instance instead\""
+                }
+                +";"
+            }
+        }
+
         rmEmptyLine()
     }
 }
 
+private fun ClassPrinter.generateBuilderMethod(
+        defVisibility: String,
+        name: String,
+        ParamAnnotations: String? = null,
+        paramTypes: List<String>,
+        paramNames: List<String> = listOf("value"),
+        genJavadoc: ClassPrinter.() -> Unit,
+        genBody: ClassPrinter.() -> Unit) {
+
+    val providedMethod = customBaseBuilderAst?.members?.find {
+        it is MethodDeclaration
+                && it.nameAsString == name
+                && it.parameters.map { it.typeAsString } == paramTypes.toTypedArray().toList()
+    } as? MethodDeclaration
+
+    if ((providedMethod == null || providedMethod.isAbstract)
+            && name !in builderSuppressedMembers) {
+        val visibility = providedMethod?.visibility?.asString() ?: defVisibility
+        val ReturnType = providedMethod?.typeAsString ?: CANONICAL_BUILDER_CLASS
+        val Annotations = providedMethod?.annotations?.joinToString("\n")
+
+        genJavadoc()
+        +GENERATED_MEMBER_HEADER
+        if (providedMethod?.isAbstract == true) +"@Override"
+        if (!Annotations.isNullOrEmpty()) +Annotations
+        "$visibility @$NonNull $ReturnType $name(${if_(!ParamAnnotations.isNullOrEmpty(), "$ParamAnnotations ")}${
+                paramTypes.zip(paramNames).joinToString(", ") { (Type, paramName) -> "$Type $paramName" }
+        })" {
+            genBody()
+        }
+    }
+}
+
 private fun ClassPrinter.generateBuilderSetters(visibility: String) {
 
     fields.forEachApply {
         val maybeCast =
                 if_(BuilderClass != CANONICAL_BUILDER_CLASS, " ($CANONICAL_BUILDER_CLASS)")
 
-        generateFieldJavadoc()
-        +GENERATED_MEMBER_HEADER
-        "$visibility $CANONICAL_BUILDER_CLASS set$NameUpperCamel($annotatedTypeForSetterParam value)" {
+        val setterName = "set$NameUpperCamel"
+
+        generateBuilderMethod(
+                name = setterName,
+                defVisibility = visibility,
+                ParamAnnotations = annotationsNoInternal.joinToString(" "),
+                paramTypes = listOf(SetterParamType),
+                genJavadoc = { generateFieldJavadoc() }) {
             +"checkNotUsed();"
             +"mBuilderFieldsSet |= $fieldBit;"
             +"$name = value;"
             +"return$maybeCast this;"
         }
 
+        val javadocSeeSetter = "/** @see #$setterName */"
+        val adderName = "add$SingularName"
 
-        val javadocSeeSetter = "/** @see #set$NameUpperCamel */"
         val singularNameCustomizationHint = if (SingularNameOrNull == null) {
             "// You can refine this method's name by providing item's singular name, e.g.:\n" +
                     "// @DataClass.PluralOf(\"item\")) mItems = ...\n\n"
         } else ""
 
-        if (isList && FieldInnerType != null) {
 
-            +javadocSeeSetter
-            +GENERATED_MEMBER_HEADER
-            "$visibility $CANONICAL_BUILDER_CLASS add$SingularName(@$NonNull $FieldInnerType value)" {
+        if (isList && FieldInnerType != null) {
+            generateBuilderMethod(
+                    name = adderName,
+                    defVisibility = visibility,
+                    paramTypes = listOf(FieldInnerType),
+                    genJavadoc = { +javadocSeeSetter }) {
+
                 !singularNameCustomizationHint
-                +"if ($name == null) set$NameUpperCamel(new $ArrayList<>());"
+                +"if ($name == null) $setterName(new $ArrayList<>());"
                 +"$name.add(value);"
                 +"return$maybeCast this;"
             }
         }
 
         if (Type.contains("Map<")) {
-            val (Key, Value) = fieldTypeGenegicArgs
-
-            +javadocSeeSetter
-            +GENERATED_MEMBER_HEADER
-            "$visibility $CANONICAL_BUILDER_CLASS add$SingularName($Key key, $Value value)" {
+            generateBuilderMethod(
+                    name = adderName,
+                    defVisibility = visibility,
+                    paramTypes = fieldTypeGenegicArgs,
+                    paramNames = listOf("key", "value"),
+                    genJavadoc = { +javadocSeeSetter }) {
                 !singularNameCustomizationHint
-                +"if ($name == null) set$NameUpperCamel(new $LinkedHashMap());"
+                +"if ($name == null) $setterName(new $LinkedHashMap());"
                 +"$name.put(key, value);"
                 +"return$maybeCast this;"
             }
         }
-
-        if (Type == "boolean") {
-            +javadocSeeSetter
-            +GENERATED_MEMBER_HEADER
-            "$visibility $CANONICAL_BUILDER_CLASS mark$NameUpperCamel()" {
-                +"return set$NameUpperCamel(true);"
-            }
-
-            +javadocSeeSetter
-            +GENERATED_MEMBER_HEADER
-            "$visibility $CANONICAL_BUILDER_CLASS markNot$NameUpperCamel()" {
-                +"return set$NameUpperCamel(false);"
-            }
-        }
     }
 }
 
 private fun ClassPrinter.generateBuilderBuild() {
     +"/** Builds the instance. This builder should not be touched after calling this! */"
     "public $ClassType build()" {
-        +"markUsed();"
+        +"checkNotUsed();"
+        +"mBuilderFieldsSet |= ${bitAtExpr(fields.size)}; // Mark builder used"
+        +""
         fields.forEachApply {
-            if (!isNullable || hasDefault) {
+            if (hasDefault) {
                 "if ((mBuilderFieldsSet & $fieldBit) == 0)" {
-                    if (!isNullable && !hasDefault) {
-                        +"throw new IllegalStateException(\"Required field not set: $nameLowerCamel\");"
-                    } else {
-                        +"$name = $defaultExpr;"
-                    }
+                    +"$name = $defaultExpr;"
                 }
             }
         }
@@ -348,7 +414,7 @@
     }
 
     val Parcel = classRef("android.os.Parcel")
-    if (!hasMethod("writeToParcel", Parcel, "int")) {
+    if (!isMethodGenerationSuppressed("writeToParcel", Parcel, "int")) {
         +"@Override"
         +GENERATED_MEMBER_HEADER
         "public void writeToParcel($Parcel dest, int flags)" {
@@ -390,7 +456,7 @@
         }
     }
 
-    if (!hasMethod("describeContents")) {
+    if (!isMethodGenerationSuppressed("describeContents")) {
         +"@Override"
         +GENERATED_MEMBER_HEADER
         +"public int describeContents() { return 0; }"
@@ -442,8 +508,6 @@
                             FieldClass.endsWith("Map") -> "new $LinkedHashMap<>()"
                             FieldClass == "List" || FieldClass == "ArrayList" ->
                                 "new ${classRef("java.util.ArrayList")}<>()"
-//                            isArray && FieldInnerType in (PRIMITIVE_TYPES + "String") ->
-//                                "new $FieldInnerType[in.readInt()]"
                             else -> ""
                         }
                         val passContainer = containerInitExpr.isNotEmpty()
@@ -519,7 +583,7 @@
 }
 
 fun ClassPrinter.generateEqualsHashcode() {
-    if (!hasMethod("equals", "Object")) {
+    if (!isMethodGenerationSuppressed("equals", "Object")) {
         +"@Override"
         +GENERATED_MEMBER_HEADER
         "public boolean equals(Object o)" {
@@ -546,7 +610,7 @@
         }
     }
 
-    if (!hasMethod("hashCode")) {
+    if (!isMethodGenerationSuppressed("hashCode")) {
         +"@Override"
         +GENERATED_MEMBER_HEADER
         "public int hashCode()" {
@@ -572,7 +636,7 @@
 
 //TODO support IntDef flags?
 fun ClassPrinter.generateToString() {
-    if (!hasMethod("toString")) {
+    if (!isMethodGenerationSuppressed("toString")) {
         +"@Override"
         +GENERATED_MEMBER_HEADER
         "public String toString()" {
@@ -599,7 +663,7 @@
 
 fun ClassPrinter.generateSetters() {
     fields.forEachApply {
-        if (!hasMethod("set$NameUpperCamel", Type)
+        if (!isMethodGenerationSuppressed("set$NameUpperCamel", Type)
                 && !fieldAst.isPublic
                 && !isFinal) {
 
@@ -618,7 +682,7 @@
         val methodPrefix = if (Type == "boolean") "is" else "get"
         val methodName = methodPrefix + NameUpperCamel
 
-        if (!hasMethod(methodName) && !fieldAst.isPublic) {
+        if (!isMethodGenerationSuppressed(methodName) && !fieldAst.isPublic) {
 
             generateFieldJavadoc(forceHide = FeatureFlag.GETTERS.hidden)
             +GENERATED_MEMBER_HEADER
@@ -662,23 +726,8 @@
 }
 
 fun FieldInfo.generateSetFrom(source: String) = classPrinter {
-    !"$name = "
-    if (Type in PRIMITIVE_TYPES || mayBeNull) {
-        +"$source;"
-    } else if (defaultExpr != null) {
-        "$source != null" {
-            +"? $source"
-            +": $defaultExpr;"
-        }
-    } else {
-        val checkNotNull = memberRef("com.android.internal.util.Preconditions.checkNotNull")
-        +"$checkNotNull($source);"
-    }
-    if (isNonEmpty) {
-        "if ($isEmptyExpr)" {
-            +"throw new IllegalArgumentException(\"$nameLowerCamel cannot be empty\");"
-        }
-    }
+    +"$name = $source;"
+    generateFieldValidation(field = this@generateSetFrom)
 }
 
 fun ClassPrinter.generateConstructor(visibility: String = "public") {
@@ -697,15 +746,18 @@
             generateSetFrom(nameLowerCamel)
         }
 
-        generateStateValidation()
-
         generateOnConstructedCallback()
     }
 }
 
-private fun ClassPrinter.generateConstructorJavadoc() {
+private fun ClassPrinter.generateConstructorJavadoc(
+        fields: List<FieldInfo> = this.fields,
+        ClassName: String = this.ClassName,
+        hidden: Boolean = FeatureFlag.CONSTRUCTOR.hidden) {
     if (fields.all { it.javadoc == null } && !FeatureFlag.CONSTRUCTOR.hidden) return
     +"/**"
+    +" * Creates a new $ClassName."
+    +" *"
     fields.filter { it.javadoc != null }.forEachApply {
         javadocTextNoAnnotationLines?.apply {
             +" * @param $nameLowerCamel"
@@ -718,87 +770,97 @@
     +" */"
 }
 
-private fun ClassPrinter.generateStateValidation() {
-    val Size = classRef("android.annotation.Size")
-    val knownNonValidationAnnotations = internalAnnotations + Nullable
-
-    val validate = memberRef("com.android.internal.util.AnnotationValidations.validate")
-    fun appendValidateCall(annotation: AnnotationExpr, valueToValidate: String) {
-        "$validate(" {
-            !"${annotation.nameAsString}.class, null, $valueToValidate"
-            val params = when (annotation) {
-                is MarkerAnnotationExpr -> emptyMap()
-                is SingleMemberAnnotationExpr -> mapOf("value" to annotation.memberValue)
-                is NormalAnnotationExpr ->
-                    annotation.pairs.map { it.name.asString() to it.value }.toMap()
-                else -> throw IllegalStateException()
-            }
-            params.forEach { name, value ->
-                !",\n\"$name\", $value"
+private fun ClassPrinter.appendLinesWithContinuationIndent(text: String) {
+    val lines = text.lines()
+    if (lines.isNotEmpty()) {
+        !lines[0]
+    }
+    if (lines.size >= 2) {
+        "" {
+            lines.drop(1).forEach {
+                +it
             }
         }
-        +";"
     }
+}
 
-    fields.forEachApply {
-        if (intOrStringDef != null) {
-            if (intOrStringDef!!.type == ConstDef.Type.INT_FLAGS) {
-                +""
-                +"//noinspection PointlessBitwiseExpression"
-                "$Preconditions.checkFlagsArgument(" {
-                    "$name, 0" {
-                        intOrStringDef!!.CONST_NAMES.forEach {
-                            +"| $it"
+private fun ClassPrinter.generateFieldValidation(field: FieldInfo) = field.run {
+    if (isNonEmpty) {
+        "if ($isEmptyExpr)" {
+            +"throw new IllegalArgumentException(\"$nameLowerCamel cannot be empty\");"
+        }
+    }
+    if (intOrStringDef != null) {
+        if (intOrStringDef!!.type == ConstDef.Type.INT_FLAGS) {
+            +""
+            "$Preconditions.checkFlagsArgument(" {
+                +"$name, "
+                appendLinesWithContinuationIndent(intOrStringDef!!.CONST_NAMES.joinToString("\n| "))
+            }
+            +";"
+        } else {
+            +""
+            !"if ("
+            appendLinesWithContinuationIndent(intOrStringDef!!.CONST_NAMES.joinToString("\n&& ") {
+                "!(${isEqualToExpr(it)})"
+            })
+            rmEmptyLine(); ") {" {
+                "throw new ${classRef<IllegalArgumentException>()}(" {
+                    "\"$nameLowerCamel was \" + $internalGetter + \" but must be one of: \"" {
+
+                        intOrStringDef!!.CONST_NAMES.forEachLastAware { CONST_NAME, isLast ->
+                            +"""+ "$CONST_NAME(" + $CONST_NAME + ")${if_(!isLast, ", ")}""""
                         }
                     }
                 }
                 +";"
-            } else {
-                +""
-                +"//noinspection PointlessBooleanExpression"
-                "if (true" {
-                    intOrStringDef!!.CONST_NAMES.forEach { CONST_NAME ->
-                        +"&& !(${isEqualToExpr(CONST_NAME)})"
-                    }
-                }; rmEmptyLine(); ") {" {
-                    "throw new ${classRef<IllegalArgumentException>()}(" {
-                        "\"$nameLowerCamel was \" + $internalGetter + \" but must be one of: \"" {
-
-                            intOrStringDef!!.CONST_NAMES.forEachLastAware { CONST_NAME, isLast ->
-                                +"""+ "$CONST_NAME(" + $CONST_NAME + ")${if_(!isLast, ", ")}""""
-                            }
-                        }
-                    }
-                    +";"
-                }
-            }
-        }
-
-        val eachLine = fieldAst.annotations.find { it.nameAsString == Each }?.range?.orElse(null)?.end?.line
-        val perElementValidations = if (eachLine == null) emptyList() else fieldAst.annotations.filter {
-            it.nameAsString != Each &&
-                it.range.orElse(null)?.begin?.line?.let { it >= eachLine } ?: false
-        }
-
-        fieldAst.annotations.filterNot {
-            it.nameAsString == intOrStringDef?.AnnotationName
-                    || it.nameAsString in knownNonValidationAnnotations
-                    || it in perElementValidations
-        }.forEach { annotation ->
-            appendValidateCall(annotation,
-                    valueToValidate = if (annotation.nameAsString == Size) sizeExpr else name)
-        }
-
-        if (perElementValidations.isNotEmpty()) {
-            +"int ${nameLowerCamel}Size = $sizeExpr;"
-            "for (int i = 0; i < ${nameLowerCamel}Size; i++) {" {
-                perElementValidations.forEach { annotation ->
-                    appendValidateCall(annotation,
-                            valueToValidate = elemAtIndexExpr("i"))
-                }
             }
         }
     }
+
+    val eachLine = fieldAst.annotations.find { it.nameAsString == Each }?.range?.orElse(null)?.end?.line
+    val perElementValidations = if (eachLine == null) emptyList() else fieldAst.annotations.filter {
+        it.nameAsString != Each &&
+                it.range.orElse(null)?.begin?.line?.let { it >= eachLine } ?: false
+    }
+
+    val Size = classRef("android.annotation.Size")
+    fieldAst.annotations.filterNot {
+        it.nameAsString == intOrStringDef?.AnnotationName
+                || it.nameAsString in knownNonValidationAnnotations
+                || it in perElementValidations
+    }.forEach { annotation ->
+        appendValidateCall(annotation,
+                valueToValidate = if (annotation.nameAsString == Size) sizeExpr else name)
+    }
+
+    if (perElementValidations.isNotEmpty()) {
+        +"int ${nameLowerCamel}Size = $sizeExpr;"
+        "for (int i = 0; i < ${nameLowerCamel}Size; i++) {" {
+            perElementValidations.forEach { annotation ->
+                appendValidateCall(annotation,
+                        valueToValidate = elemAtIndexExpr("i"))
+            }
+        }
+    }
+}
+
+fun ClassPrinter.appendValidateCall(annotation: AnnotationExpr, valueToValidate: String) {
+    val validate = memberRef("com.android.internal.util.AnnotationValidations.validate")
+    "$validate(" {
+        !"${annotation.nameAsString}.class, null, $valueToValidate"
+        val params = when (annotation) {
+            is MarkerAnnotationExpr -> emptyMap()
+            is SingleMemberAnnotationExpr -> mapOf("value" to annotation.memberValue)
+            is NormalAnnotationExpr ->
+                annotation.pairs.map { it.name.asString() to it.value }.toMap()
+            else -> throw IllegalStateException()
+        }
+        params.forEach { name, value ->
+            !",\n\"$name\", $value"
+        }
+    }
+    +";"
 }
 
 private fun ClassPrinter.generateOnConstructedCallback(prefix: String = "") {
@@ -845,3 +907,15 @@
         }
     }
 }
+
+fun ClassPrinter.generateMetadata(file: File) {
+    "@$DataClassGenerated(" {
+        +"time = ${System.currentTimeMillis()}L,"
+        +"codegenVersion = \"$CODEGEN_VERSION\","
+        +"sourceFile = \"${file.relativeTo(File(System.getenv("ANDROID_BUILD_TOP")))}\","
+        +"inputSignatures = \"${getInputSignatures().joinToString("\\n")}\""
+    }
+    +""
+    +"@Deprecated"
+    +"private void __metadata() {}\n"
+}
\ No newline at end of file
diff --git a/tools/codegen/src/com/android/codegen/InputSignaturesComputation.kt b/tools/codegen/src/com/android/codegen/InputSignaturesComputation.kt
index d1dc88f..24cf469 100644
--- a/tools/codegen/src/com/android/codegen/InputSignaturesComputation.kt
+++ b/tools/codegen/src/com/android/codegen/InputSignaturesComputation.kt
@@ -1,6 +1,6 @@
 package com.android.codegen
 
-import com.github.javaparser.ast.body.TypeDeclaration
+import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration
 import com.github.javaparser.ast.expr.*
 import com.github.javaparser.ast.nodeTypes.NodeWithAnnotations
 import com.github.javaparser.ast.type.ClassOrInterfaceType
@@ -8,9 +8,17 @@
 
 
 fun ClassPrinter.getInputSignatures(): List<String> {
+    return generateInputSignaturesForClass(classAst) +
+            annotationToString(classAst.annotations.find { it.nameAsString == DataClass }) +
+            generateInputSignaturesForClass(customBaseBuilderAst)
+}
+
+private fun ClassPrinter.generateInputSignaturesForClass(classAst: ClassOrInterfaceDeclaration?): List<String> {
+    if (classAst == null) return emptyList()
+
     return classAst.fields.map { fieldAst ->
         buildString {
-            append(fieldAst.modifiers.joinToString(" ") {it.asString()})
+            append(fieldAst.modifiers.joinToString(" ") { it.keyword.asString() })
             append(" ")
             append(annotationsToString(fieldAst))
             append(" ")
@@ -20,7 +28,7 @@
         }
     } + classAst.methods.map { methodAst ->
         buildString {
-            append(methodAst.modifiers.joinToString(" ") {it.asString()})
+            append(methodAst.modifiers.joinToString(" ") { it.keyword.asString() })
             append(" ")
             append(annotationsToString(methodAst))
             append(" ")
@@ -28,19 +36,26 @@
             append(" ")
             append(methodAst.nameAsString)
             append("(")
-            append(methodAst.parameters.joinToString(",") {getFullClassName(it.type)})
+            append(methodAst.parameters.joinToString(",") { getFullClassName(it.type) })
             append(")")
         }
-    }
+    } + ("class ${classAst.nameAsString}" +
+            " extends ${classAst.extendedTypes.map { getFullClassName(it) }.ifEmpty { listOf("java.lang.Object") }.joinToString(", ")}" +
+            " implements [${classAst.implementedTypes.joinToString(", ") { getFullClassName(it) }}]")
 }
 
 private fun ClassPrinter.annotationsToString(annotatedAst: NodeWithAnnotations<*>): String {
-    return annotatedAst.annotations.joinToString(" ") {
-        annotationToString(it)
-    }
+    return annotatedAst
+            .annotations
+            .groupBy { it.nameAsString } // dedupe annotations by name (javaparser bug?)
+            .values
+            .joinToString(" ") {
+                annotationToString(it[0])
+            }
 }
 
-private fun ClassPrinter.annotationToString(ann: AnnotationExpr): String {
+private fun ClassPrinter.annotationToString(ann: AnnotationExpr?): String {
+    if (ann == null) return ""
     return buildString {
         append("@")
         append(getFullClassName(ann.nameAsString))
@@ -78,11 +93,11 @@
 
 private fun ClassPrinter.getFullClassName(type: Type): String {
     return if (type is ClassOrInterfaceType) {
+
         getFullClassName(buildString {
             type.scope.ifPresent { append(it).append(".") }
-            type.isArrayType
             append(type.nameAsString)
-        }) + (type.typeArguments.orElse(null)?.let { args -> args.joinToString(", ") {getFullClassName(it)}}?.let { "<$it>" } ?: "")
+        }) + (type.typeArguments.orElse(null)?.let { args -> args.joinToString(",") {getFullClassName(it)}}?.let { "<$it>" } ?: "")
     } else getFullClassName(type.asString())
 }
 
@@ -100,10 +115,16 @@
     val thisPackagePrefix = fileAst.packageDeclaration.map { it.nameAsString + "." }.orElse("")
     val thisClassPrefix = thisPackagePrefix + classAst.nameAsString + "."
 
-    classAst.childNodes.filterIsInstance<TypeDeclaration<*>>().find {
+    if (classAst.nameAsString == className) return thisPackagePrefix + classAst.nameAsString
+
+    nestedClasses.find {
         it.nameAsString == className
     }?.let { return thisClassPrefix + it.nameAsString }
 
+    if (className == CANONICAL_BUILDER_CLASS || className == BASE_BUILDER_CLASS) {
+        return thisClassPrefix + className
+    }
+
     constDefs.find { it.AnnotationName == className }?.let { return thisClassPrefix + className }
 
     if (tryOrNull { Class.forName("java.lang.$className") } != null) {
diff --git a/tools/codegen/src/com/android/codegen/Main.kt b/tools/codegen/src/com/android/codegen/Main.kt
index 8fafa7c..0f932f3 100755
--- a/tools/codegen/src/com/android/codegen/Main.kt
+++ b/tools/codegen/src/com/android/codegen/Main.kt
@@ -1,5 +1,6 @@
 package com.android.codegen
 
+import com.github.javaparser.JavaParser
 import java.io.File
 
 
@@ -9,14 +10,12 @@
 
 val PRIMITIVE_TYPES = listOf("byte", "short", "int", "long", "char", "float", "double", "boolean")
 
-const val CANONICAL_BUILDER_CLASS = "Builder"
-const val GENERATED_BUILDER_CLASS = "GeneratedBuilder"
-
 val BUILTIN_SPECIAL_PARCELLINGS = listOf("Pattern")
 
 const val FLAG_BUILDER_PROTECTED_SETTERS = "--builder-protected-setters"
 const val FLAG_NO_FULL_QUALIFIERS = "--no-full-qualifiers"
 
+val JAVA_PARSER = JavaParser()
 
 /** @see [FeatureFlag] */
 val USAGE = """
@@ -66,10 +65,10 @@
       Will be called in constructor, after all the fields have been initialized.
       This is a good place to put any custom validation logic that you may have
 
-  static class $CANONICAL_BUILDER_CLASS extends $GENERATED_BUILDER_CLASS
-      If a class extending $GENERATED_BUILDER_CLASS is specified, generated builder's setters will
+  static class $CANONICAL_BUILDER_CLASS extends $BASE_BUILDER_CLASS
+      If a class extending $BASE_BUILDER_CLASS is specified, generated builder's setters will
       return the provided $CANONICAL_BUILDER_CLASS type.
-      $GENERATED_BUILDER_CLASS's constructor(s) will be package-private to encourage using $CANONICAL_BUILDER_CLASS instead
+      $BASE_BUILDER_CLASS's constructor(s) will be package-private to encourage using $CANONICAL_BUILDER_CLASS instead
       This allows you to extend the generated builder, adding or overriding any methods you may want
 
 
@@ -131,7 +130,6 @@
 
 
         // $GENERATED_WARNING_PREFIX v$CODEGEN_VERSION.
-        //   on ${currentTimestamp()}
         //
         // DO NOT MODIFY!
         //
@@ -143,14 +141,6 @@
 
         if (FeatureFlag.CONST_DEFS()) generateConstDefs()
 
-        "@$DataClassGenerated(" {
-            +"time = ${System.currentTimeMillis()}L,"
-            +"codegenVersion = \"$CODEGEN_VERSION\","
-            +"sourceFile = \"${file.relativeTo(File(System.getenv("ANDROID_BUILD_TOP")))}\","
-            +"inputSignatures = \"${getInputSignatures().joinToString("\\n")}\""
-        }
-        +"\n"
-
 
         if (FeatureFlag.CONSTRUCTOR()) {
             generateConstructor("public")
@@ -160,6 +150,7 @@
                 || FeatureFlag.PARCELABLE()) {
             generateConstructor("/* package-private */")
         }
+        if (FeatureFlag.COPY_CONSTRUCTOR()) generateCopyConstructor()
 
         if (FeatureFlag.GETTERS()) generateGetters()
         if (FeatureFlag.SETTERS()) generateSetters()
@@ -168,7 +159,6 @@
 
         if (FeatureFlag.FOR_EACH_FIELD()) generateForEachField()
 
-        if (FeatureFlag.COPY_CONSTRUCTOR()) generateCopyConstructor()
         if (FeatureFlag.WITHERS()) generateWithers()
 
         if (FeatureFlag.PARCELABLE()) generateParcelable()
@@ -178,6 +168,8 @@
 
         if (FeatureFlag.AIDL()) generateAidl(file)
 
+        generateMetadata(file)
+
         rmEmptyLine()
     }
     stringBuilder.append("\n}\n")
diff --git a/tools/codegen/src/com/android/codegen/SharedConstants.kt b/tools/codegen/src/com/android/codegen/SharedConstants.kt
index 175eea6..7d50ad1 100644
--- a/tools/codegen/src/com/android/codegen/SharedConstants.kt
+++ b/tools/codegen/src/com/android/codegen/SharedConstants.kt
@@ -1,4 +1,7 @@
 package com.android.codegen
 
 const val CODEGEN_NAME = "codegen"
-const val CODEGEN_VERSION = "1.0.0"
\ No newline at end of file
+const val CODEGEN_VERSION = "1.0.0"
+
+const val CANONICAL_BUILDER_CLASS = "Builder"
+const val BASE_BUILDER_CLASS = "BaseBuilder"
diff --git a/tools/codegen/src/com/android/codegen/Utils.kt b/tools/codegen/src/com/android/codegen/Utils.kt
index 95c9909..a1f068a 100644
--- a/tools/codegen/src/com/android/codegen/Utils.kt
+++ b/tools/codegen/src/com/android/codegen/Utils.kt
@@ -1,8 +1,10 @@
 package com.android.codegen
 
+import com.github.javaparser.ast.Modifier
 import com.github.javaparser.ast.expr.AnnotationExpr
 import com.github.javaparser.ast.expr.Expression
 import com.github.javaparser.ast.expr.SingleMemberAnnotationExpr
+import com.github.javaparser.ast.nodeTypes.NodeWithModifiers
 import java.time.Instant
 import java.time.ZoneId
 import java.time.format.DateTimeFormatter
@@ -22,6 +24,8 @@
 
 fun if_(cond: Boolean, then: String) = if (cond) then else ""
 
+fun <T> Any?.as_(): T = this as T
+
 inline infix fun Int.times(action: () -> Unit) {
     for (i in 1..this) action()
 }
@@ -73,4 +77,14 @@
 fun currentTimestamp() = DateTimeFormatter
         .ofLocalizedDateTime(/* date */ FormatStyle.MEDIUM, /* time */ FormatStyle.LONG)
         .withZone(ZoneId.systemDefault())
-        .format(Instant.now())
\ No newline at end of file
+        .format(Instant.now())
+
+val NodeWithModifiers<*>.visibility get() = accessSpecifier
+
+fun abort(msg: String): Nothing {
+    System.err.println("ERROR: $msg")
+    System.exit(1)
+    throw InternalError() // can't get here
+}
+
+fun bitAtExpr(bitIndex: Int) = "0x${java.lang.Long.toHexString(1L shl bitIndex)}"
diff --git a/tools/preload-check/Android.bp b/tools/preload-check/Android.bp
index 2488341..87b31d2 100644
--- a/tools/preload-check/Android.bp
+++ b/tools/preload-check/Android.bp
@@ -19,4 +19,5 @@
     libs: ["tradefed"],
     test_suites: ["general-tests"],
     required: ["preload-check-device"],
+    data: [":preload-check-device"],
 }
diff --git a/tools/preload-check/device/Android.bp b/tools/preload-check/device/Android.bp
index 7782b0d..f40d8ba 100644
--- a/tools/preload-check/device/Android.bp
+++ b/tools/preload-check/device/Android.bp
@@ -20,7 +20,6 @@
 
     sdk_version: "current",
     srcs: ["src/**/*.java"],
-    test_suites: ["general-tests"],
     dex_preopt: {
         enabled: false,
     },
diff --git a/tools/processors/staledataclass/src/android/processor/staledataclass/StaleDataclassProcessor.kt b/tools/processors/staledataclass/src/android/processor/staledataclass/StaleDataclassProcessor.kt
index e5ec17a..d00def6 100644
--- a/tools/processors/staledataclass/src/android/processor/staledataclass/StaleDataclassProcessor.kt
+++ b/tools/processors/staledataclass/src/android/processor/staledataclass/StaleDataclassProcessor.kt
@@ -17,6 +17,8 @@
 
 package android.processor.staledataclass
 
+import com.android.codegen.BASE_BUILDER_CLASS
+import com.android.codegen.CANONICAL_BUILDER_CLASS
 import com.android.codegen.CODEGEN_NAME
 import com.android.codegen.CODEGEN_VERSION
 import com.sun.tools.javac.code.Symbol
@@ -29,6 +31,7 @@
 import javax.lang.model.SourceVersion
 import javax.lang.model.element.AnnotationMirror
 import javax.lang.model.element.Element
+import javax.lang.model.element.ElementKind
 import javax.lang.model.element.TypeElement
 import javax.tools.Diagnostic
 
@@ -63,10 +66,14 @@
         if (dataClassAnnotation == null) {
             dataClassAnnotation = annotations.find {
                 it.qualifiedName.toString() == DATACLASS_ANNOTATION_NAME
-            }
+            } ?: return true
         }
 
-        val generatedAnnotatedElements = roundEnv.getElementsAnnotatedWith(generatedAnnotation)
+        val generatedAnnotatedElements = if (generatedAnnotation != null) {
+            roundEnv.getElementsAnnotatedWith(generatedAnnotation)
+        } else {
+            emptySet()
+        }
         generatedAnnotatedElements.forEach {
             processSingleFile(it)
         }
@@ -107,20 +114,30 @@
 
     private fun processSingleFile(elementAnnotatedWithGenerated: Element) {
 
-        val inputSignatures = elementAnnotatedWithGenerated
-                .enclosingElement
-                .enclosedElements
-                .filterNot {
-                    it.annotationMirrors.any { "Generated" in it.annotationType.toString() }
-                }.map {
-                    elemToString(it)
-                }.toSet()
+        val classElement = elementAnnotatedWithGenerated.enclosingElement
+
+        val inputSignatures = computeSignaturesForClass(classElement)
+                .plus(computeSignaturesForClass(classElement.enclosedElements.find {
+                    it.kind == ElementKind.CLASS
+                            && !isGenerated(it)
+                            && it.simpleName.toString() == BASE_BUILDER_CLASS
+                }))
+                .plus(computeSignaturesForClass(classElement.enclosedElements.find {
+                    it.kind == ElementKind.CLASS
+                            && !isGenerated(it)
+                            && it.simpleName.toString() == CANONICAL_BUILDER_CLASS
+                }))
+                .plus(classElement
+                        .annotationMirrors
+                        .find { it.annotationType.toString() == DATACLASS_ANNOTATION_NAME }
+                        .toString())
+                .toSet()
 
         val annotationParams = elementAnnotatedWithGenerated
                 .annotationMirrors
                 .find { ann -> isGeneratedAnnotation(ann) }!!
                 .elementValues
-                .map { (k, v) -> k.getSimpleName().toString() to v.getValue() }
+                .map { (k, v) -> k.simpleName.toString() to v.value }
                 .toMap()
 
         val lastGenerated = annotationParams["time"] as Long
@@ -140,7 +157,7 @@
         }
 
         val source = repoRoot!!.resolve(sourceRelative)
-        val clazz = elementAnnotatedWithGenerated.enclosingElement.toString()
+        val clazz = classElement.toString()
 
         if (inputSignatures != lastGenInputSignatures) {
             error(buildString {
@@ -157,6 +174,23 @@
         }
     }
 
+    private fun computeSignaturesForClass(classElement: Element?): List<String> {
+        if (classElement == null) return emptyList()
+        val type = classElement as TypeElement
+        return classElement
+                .enclosedElements
+                .filterNot {
+                    it.kind == ElementKind.CLASS
+                            || it.kind == ElementKind.CONSTRUCTOR
+                            || isGenerated(it)
+                }.map {
+                    elemToString(it)
+                } + "class ${classElement.simpleName} extends ${type.superclass} implements [${type.interfaces.joinToString(", ")}]"
+    }
+
+    private fun isGenerated(it: Element) =
+            it.annotationMirrors.any { "Generated" in it.annotationType.toString() }
+
     private fun error(msg: String) {
         processingEnv.messager.printMessage(Diagnostic.Kind.ERROR, msg)
     }
diff --git a/wifi/tests/runtests.sh b/wifi/tests/runtests.sh
index 219a45e..7a0dfb0 100755
--- a/wifi/tests/runtests.sh
+++ b/wifi/tests/runtests.sh
@@ -12,7 +12,7 @@
 echo "+ mmma -j32 $ANDROID_BUILD_TOP/frameworks/base/wifi/tests"
 # NOTE Don't actually run the command above since this shell doesn't inherit functions from the
 #      caller.
-make -j32 -C $ANDROID_BUILD_TOP -f build/core/main.mk MODULES-IN-frameworks-base-wifi-tests
+$ANDROID_BUILD_TOP/build/soong/soong_ui.bash --make-mode MODULES-IN-frameworks-base-wifi-tests
 
 set -x # print commands