Merge "[SettingsProvider] update ringtone cache only after setting is update" into main
diff --git a/apex/jobscheduler/service/java/com/android/server/job/GrantedUriPermissions.java b/apex/jobscheduler/service/java/com/android/server/job/GrantedUriPermissions.java
index 7f191d4..60837cb 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/GrantedUriPermissions.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/GrantedUriPermissions.java
@@ -38,6 +38,7 @@
     private final int mSourceUserId;
     private final String mTag;
     private final IBinder mPermissionOwner;
+    private final UriGrantsManagerInternal mUriGrantsManagerInternal;
     private final ArrayList<Uri> mUris = new ArrayList<>();
 
     private GrantedUriPermissions(int grantFlags, int uid, String tag)
@@ -45,13 +46,13 @@
         mGrantFlags = grantFlags;
         mSourceUserId = UserHandle.getUserId(uid);
         mTag = tag;
-        mPermissionOwner = LocalServices
-                .getService(UriGrantsManagerInternal.class).newUriPermissionOwner("job: " + tag);
+        mUriGrantsManagerInternal = LocalServices.getService(UriGrantsManagerInternal.class);
+        mPermissionOwner = mUriGrantsManagerInternal.newUriPermissionOwner("job: " + tag);
     }
 
     public void revoke() {
         for (int i = mUris.size()-1; i >= 0; i--) {
-            LocalServices.getService(UriGrantsManagerInternal.class).revokeUriPermissionFromOwner(
+            mUriGrantsManagerInternal.revokeUriPermissionFromOwner(
                     mPermissionOwner, mUris.get(i), mGrantFlags, mSourceUserId);
         }
         mUris.clear();
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 dc608e7..5bf2eb9 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
@@ -235,7 +235,9 @@
     private final Handler mHandler;
     private final Injector mInjector;
 
+    private final ActivityManagerInternal mActivityManagerInternal;
     private PowerManager mPowerManager;
+    private final UserManagerInternal mUserManagerInternal;
 
     private boolean mCurrentInteractiveState;
     private boolean mEffectiveInteractiveState;
@@ -507,6 +509,9 @@
         mInjector = injector;
         mNotificationCoordinator = new JobNotificationCoordinator();
 
+        mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
+        mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
+
         mHandler = AppSchedulingModuleThread.getHandler();
 
         mGracePeriodObserver = new GracePeriodObserver(mContext);
@@ -1253,9 +1258,7 @@
                 return false;
             case PRIVILEGED_STATE_UNDEFINED:
             default:
-                final ActivityManagerInternal activityManagerInternal =
-                        LocalServices.getService(ActivityManagerInternal.class);
-                final int procState = activityManagerInternal.getUidProcessState(uid);
+                final int procState = mActivityManagerInternal.getUidProcessState(uid);
                 if (procState == ActivityManager.PROCESS_STATE_TOP) {
                     cachedPrivilegedState.put(uid, PRIVILEGED_STATE_TOP);
                     return true;
@@ -1266,7 +1269,7 @@
                 }
 
                 final BackgroundStartPrivileges bsp =
-                        activityManagerInternal.getBackgroundStartPrivileges(uid);
+                        mActivityManagerInternal.getBackgroundStartPrivileges(uid);
                 if (DEBUG) {
                     Slog.d(TAG, "Job " + job.toShortString() + " bsp state: " + bsp);
                 }
@@ -2213,19 +2216,17 @@
     boolean shouldRunAsFgUserJob(JobStatus job) {
         if (!mShouldRestrictBgUser) return true;
         int userId = job.getSourceUserId();
-        UserManagerInternal um = LocalServices.getService(UserManagerInternal.class);
-        UserInfo userInfo = um.getUserInfo(userId);
+        UserInfo userInfo = mUserManagerInternal.getUserInfo(userId);
 
         // If the user has a parent user (e.g. a work profile of another user), the user should be
         // treated equivalent as its parent user.
         if (userInfo.profileGroupId != UserInfo.NO_PROFILE_GROUP_ID
                 && userInfo.profileGroupId != userId) {
             userId = userInfo.profileGroupId;
-            userInfo = um.getUserInfo(userId);
+            userInfo = mUserManagerInternal.getUserInfo(userId);
         }
 
-        int currentUser = LocalServices.getService(ActivityManagerInternal.class)
-                .getCurrentUserId();
+        int currentUser = mActivityManagerInternal.getCurrentUserId();
         // A user is treated as foreground user if any of the followings is true:
         // 1. The user is current user
         // 2. The user is primary user
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 f99bcf1..e7ea7c2 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -251,6 +251,9 @@
         }
     };
 
+    @VisibleForTesting
+    public static UsageStatsManagerInternal sUsageStatsManagerInternal;
+
     /** Global local for all job scheduler state. */
     final Object mLock = new Object();
     /** Master list of jobs. */
@@ -358,8 +361,8 @@
     DeviceIdleInternal mLocalDeviceIdleController;
     @VisibleForTesting
     AppStateTrackerImpl mAppStateTracker;
-    final UsageStatsManagerInternal mUsageStats;
     private final AppStandbyInternal mAppStandbyInternal;
+    private final BatteryStatsInternal mBatteryStatsInternal;
 
     /**
      * Set to true once we are allowed to run third party apps.
@@ -2416,7 +2419,7 @@
 
         // Set up the app standby bucketing tracker
         mStandbyTracker = new StandbyTracker();
-        mUsageStats = LocalServices.getService(UsageStatsManagerInternal.class);
+        sUsageStatsManagerInternal = LocalServices.getService(UsageStatsManagerInternal.class);
 
         final Categorizer quotaCategorizer = (userId, packageName, tag) -> {
             if (QUOTA_TRACKER_TIMEOUT_UIJ_TAG.equals(tag)) {
@@ -2467,6 +2470,8 @@
         mAppStandbyInternal = LocalServices.getService(AppStandbyInternal.class);
         mAppStandbyInternal.addListener(mStandbyTracker);
 
+        mBatteryStatsInternal = LocalServices.getService(BatteryStatsInternal.class);
+
         // The job store needs to call back
         publishLocalService(JobSchedulerInternal.class, new LocalService());
 
@@ -4127,7 +4132,7 @@
                 return;
             }
 
-            long sinceLast = mUsageStats.getTimeSinceLastJobRun(packageName, userId);
+            long sinceLast = sUsageStatsManagerInternal.getTimeSinceLastJobRun(packageName, userId);
             if (sinceLast > 2 * DateUtils.DAY_IN_MILLIS) {
                 // Too long ago, not worth logging
                 sinceLast = 0L;
@@ -4137,8 +4142,6 @@
                 mJobs.forEachJobForSourceUid(uid, counter);
             }
             if (counter.numDeferred() > 0 || sinceLast > 0) {
-                BatteryStatsInternal mBatteryStatsInternal = LocalServices.getService
-                        (BatteryStatsInternal.class);
                 mBatteryStatsInternal.noteJobsDeferred(uid, counter.numDeferred(), sinceLast);
                 FrameworkStatsLog.write_non_chained(
                         FrameworkStatsLog.DEFERRED_JOB_STATS_REPORTED, uid, null,
@@ -4183,10 +4186,8 @@
 
     // Static to support external callers
     public static int standbyBucketForPackage(String packageName, int userId, long elapsedNow) {
-        UsageStatsManagerInternal usageStats = LocalServices.getService(
-                UsageStatsManagerInternal.class);
-        int bucket = usageStats != null
-                ? usageStats.getAppStandbyBucket(packageName, userId, elapsedNow)
+        int bucket = sUsageStatsManagerInternal != null
+                ? sUsageStatsManagerInternal.getAppStandbyBucket(packageName, userId, elapsedNow)
                 : 0;
 
         bucket = standbyBucketToBucketIndex(bucket);
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
index e636f60..b737041 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
@@ -161,6 +161,7 @@
     private final EconomyManagerInternal mEconomyManagerInternal;
     private final JobPackageTracker mJobPackageTracker;
     private final PowerManager mPowerManager;
+    private final UsageStatsManagerInternal mUsageStatsManagerInternal;
     private PowerManager.WakeLock mWakeLock;
 
     // Execution state.
@@ -321,6 +322,7 @@
         mNotificationCoordinator = notificationCoordinator;
         mCompletedListener = service;
         mPowerManager = mContext.getSystemService(PowerManager.class);
+        mUsageStatsManagerInternal = LocalServices.getService(UsageStatsManagerInternal.class);
         mAvailable = true;
         mVerb = VERB_FINISHED;
         mPreferredUid = NO_PREFERRED_UID;
@@ -536,9 +538,8 @@
                 // Whatever.
             }
             final int jobUserId = job.getSourceUserId();
-            UsageStatsManagerInternal usageStats =
-                    LocalServices.getService(UsageStatsManagerInternal.class);
-            usageStats.setLastJobRunTime(sourcePackage, jobUserId, mExecutionStartTimeElapsed);
+            mUsageStatsManagerInternal
+                    .setLastJobRunTime(sourcePackage, jobUserId, mExecutionStartTimeElapsed);
             mAvailable = false;
             mStoppedReason = null;
             mStoppedTime = 0;
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 f429966..e0c766f 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
@@ -228,6 +228,8 @@
     /** The minimum possible update delay is 1 second. */
     public static final long MIN_TRIGGER_MAX_DELAY = 1000;
 
+    private JobSchedulerInternal mJobSchedulerInternal;
+
     final JobInfo job;
     /**
      * Uid of the package requesting this job.  This can differ from the "source"
@@ -1152,8 +1154,10 @@
      * exemptions.
      */
     public int getEffectiveStandbyBucket() {
-        final JobSchedulerInternal jsi = LocalServices.getService(JobSchedulerInternal.class);
-        final boolean isBuggy = jsi.isAppConsideredBuggy(
+        if (mJobSchedulerInternal == null) {
+            mJobSchedulerInternal = LocalServices.getService(JobSchedulerInternal.class);
+        }
+        final boolean isBuggy = mJobSchedulerInternal.isAppConsideredBuggy(
                 getUserId(), getServiceComponent().getPackageName(),
                 getTimeoutBlameUserId(), getTimeoutBlamePackageName());
 
@@ -1262,12 +1266,15 @@
      * @return true if the exemption status changed
      */
     public boolean updateMediaBackupExemptionStatus() {
-        final JobSchedulerInternal jsi = LocalServices.getService(JobSchedulerInternal.class);
+        if (mJobSchedulerInternal == null) {
+            mJobSchedulerInternal = LocalServices.getService(JobSchedulerInternal.class);
+        }
         boolean hasMediaExemption = mHasExemptedMediaUrisOnly
                 && !job.hasLateConstraint()
                 && job.getRequiredNetwork() != null
                 && getEffectivePriority() >= JobInfo.PRIORITY_DEFAULT
-                && sourcePackageName.equals(jsi.getCloudMediaProviderPackage(sourceUserId));
+                && sourcePackageName.equals(
+                        mJobSchedulerInternal.getCloudMediaProviderPackage(sourceUserId));
         if (mHasMediaBackupExemption == hasMediaExemption) {
             return false;
         }
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java b/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java
index f5487dc7..b8397d2 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java
@@ -151,6 +151,7 @@
     private final BatteryManagerInternal mBatteryManagerInternal;
     private final PackageManager mPackageManager;
     private final PackageManagerInternal mPackageManagerInternal;
+    private final UserManagerInternal mUserManagerInternal;
 
     private IAppOpsService mAppOpsService;
     private IDeviceIdleController mDeviceIdleController;
@@ -357,6 +358,7 @@
         mBatteryManagerInternal = LocalServices.getService(BatteryManagerInternal.class);
         mPackageManager = context.getPackageManager();
         mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
+        mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
         mEconomyManagerStub = new EconomyManagerStub();
         mAnalyst = new Analyst();
         mScribe = new Scribe(this, mAnalyst);
@@ -589,7 +591,7 @@
     }
 
     void onExemptionListChanged() {
-        final int[] userIds = LocalServices.getService(UserManagerInternal.class).getUserIds();
+        final int[] userIds = mUserManagerInternal.getUserIds();
         synchronized (mLock) {
             final ArraySet<String> removed = mExemptedApps;
             final ArraySet<String> added = new ArraySet<>();
@@ -979,9 +981,7 @@
     @GuardedBy("mLock")
     private void loadInstalledPackageListLocked() {
         mPkgCache.clear();
-        final UserManagerInternal userManagerInternal =
-                LocalServices.getService(UserManagerInternal.class);
-        final int[] userIds = userManagerInternal.getUserIds();
+        final int[] userIds = mUserManagerInternal.getUserIds();
         for (int userId : userIds) {
             final List<PackageInfo> pkgs =
                     mPackageManager.getInstalledPackagesAsUser(PACKAGE_QUERY_FLAGS, userId);
@@ -1097,7 +1097,7 @@
                 timeSinceUsersAdded = mScribe.getRealtimeSinceUsersAddedLocked(nowElapsed);
             }
 
-            final int[] userIds = LocalServices.getService(UserManagerInternal.class).getUserIds();
+            final int[] userIds = mUserManagerInternal.getUserIds();
             for (int userId : userIds) {
                 final long timeSinceUserAddedMs = timeSinceUsersAdded.get(userId, 0);
                 // Temporarily mark installers as VIPs so they aren't subject to credit
diff --git a/core/res/res/drawable/ic_private_profile_badge.xml b/core/res/res/drawable/ic_private_profile_badge.xml
new file mode 100644
index 0000000..28c0f8a
--- /dev/null
+++ b/core/res/res/drawable/ic_private_profile_badge.xml
@@ -0,0 +1,25 @@
+<!--
+  ~ Copyright (C) 2023 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24"
+        android:viewportHeight="24">
+        <path
+            android:pathData="M10.5,15H13.5L12.925,11.775C13.258,11.608 13.517,11.367 13.7,11.05C13.9,10.733 14,10.383 14,10C14,9.45 13.8,8.983 13.4,8.6C13.017,8.2 12.55,8 12,8C11.45,8 10.975,8.2 10.575,8.6C10.192,8.983 10,9.45 10,10C10,10.383 10.092,10.733 10.275,11.05C10.475,11.367 10.742,11.608 11.075,11.775L10.5,15ZM12,22C9.683,21.417 7.767,20.092 6.25,18.025C4.75,15.942 4,13.633 4,11.1V5L12,2L20,5V11.1C20,13.633 19.242,15.942 17.725,18.025C16.225,20.092 14.317,21.417 12,22ZM12,19.9C13.733,19.35 15.167,18.25 16.3,16.6C17.433,14.95 18,13.117 18,11.1V6.375L12,4.125L6,6.375V11.1C6,13.117 6.567,14.95 7.7,16.6C8.833,18.25 10.267,19.35 12,19.9Z"
+            android:fillColor="@android:color/system_accent1_900"/>
+</vector>
\ No newline at end of file
diff --git a/core/res/res/drawable/ic_private_profile_icon_badge.xml b/core/res/res/drawable/ic_private_profile_icon_badge.xml
new file mode 100644
index 0000000..5cb6a9d
--- /dev/null
+++ b/core/res/res/drawable/ic_private_profile_icon_badge.xml
@@ -0,0 +1,31 @@
+<!--
+  ~ Copyright (C) 2023 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="64dp"
+        android:height="64dp"
+        android:viewportWidth="64"
+        android:viewportHeight="64">
+    <group
+        android:scaleX=".66"
+        android:scaleY=".66"
+        android:translateX="42"
+        android:translateY="42">
+            <path
+                android:pathData="M10.5,15H13.5L12.925,11.775C13.258,11.608 13.517,11.367 13.7,11.05C13.9,10.733 14,10.383 14,10C14,9.45 13.8,8.983 13.4,8.6C13.017,8.2 12.55,8 12,8C11.45,8 10.975,8.2 10.575,8.6C10.192,8.983 10,9.45 10,10C10,10.383 10.092,10.733 10.275,11.05C10.475,11.367 10.742,11.608 11.075,11.775L10.5,15ZM12,22C9.683,21.417 7.767,20.092 6.25,18.025C4.75,15.942 4,13.633 4,11.1V5L12,2L20,5V11.1C20,13.633 19.242,15.942 17.725,18.025C16.225,20.092 14.317,21.417 12,22ZM12,19.9C13.733,19.35 15.167,18.25 16.3,16.6C17.433,14.95 18,13.117 18,11.1V6.375L12,4.125L6,6.375V11.1C6,13.117 6.567,14.95 7.7,16.6C8.833,18.25 10.267,19.35 12,19.9Z"
+                android:fillColor="@android:color/system_accent1_900"/>
+    </group>
+</vector>
\ No newline at end of file
diff --git a/core/res/res/drawable/stat_sys_private_profile_status.xml b/core/res/res/drawable/stat_sys_private_profile_status.xml
new file mode 100644
index 0000000..98cc88d
--- /dev/null
+++ b/core/res/res/drawable/stat_sys_private_profile_status.xml
@@ -0,0 +1,25 @@
+<!--
+  ~ Copyright (C) 2023 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="17dp"
+        android:height="17dp"
+        android:viewportWidth="24"
+        android:viewportHeight="24">
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M10.5,15H13.5L12.925,11.775C13.258,11.608 13.517,11.367 13.7,11.05C13.9,10.733 14,10.383 14,10C14,9.45 13.8,8.983 13.4,8.6C13.017,8.2 12.55,8 12,8C11.45,8 10.975,8.2 10.575,8.6C10.192,8.983 10,9.45 10,10C10,10.383 10.092,10.733 10.275,11.05C10.475,11.367 10.742,11.608 11.075,11.775L10.5,15ZM12,22C9.683,21.417 7.767,20.092 6.25,18.025C4.75,15.942 4,13.633 4,11.1V5L12,2L20,5V11.1C20,13.633 19.242,15.942 17.725,18.025C16.225,20.092 14.317,21.417 12,22ZM12,19.9C13.733,19.35 15.167,18.25 16.3,16.6C17.433,14.95 18,13.117 18,11.1V6.375L12,4.125L6,6.375V11.1C6,13.117 6.567,14.95 7.7,16.6C8.833,18.25 10.267,19.35 12,19.9Z"/>
+</vector>
\ No newline at end of file
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 207927a..591e505 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -5090,6 +5090,13 @@
     -->
     <string name="clone_profile_label_badge">Clone <xliff:g id="label" example="Messenger">%1$s</xliff:g></string>
 
+    <!--
+        Used to wrap a label for content description for a Private profile, e.g. "Private Messenger"
+        instead of Messenger when the Messenger app is installed in Private Profile.
+        [CHAR LIMIT=20]
+    -->
+    <string name="private_profile_label_badge">Private <xliff:g id="label" example="Messenger">%1$s</xliff:g></string>
+
     <!-- DO NOT TRANSLATE -->
     <string name="time_placeholder">--</string>
 
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 343818e..889901a 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1080,6 +1080,7 @@
   <java-symbol type="string" name="managed_profile_label_badge_2" />
   <java-symbol type="string" name="managed_profile_label_badge_3" />
   <java-symbol type="string" name="clone_profile_label_badge" />
+  <java-symbol type="string" name="private_profile_label_badge" />
   <java-symbol type="string" name="mediasize_unknown_portrait" />
   <java-symbol type="string" name="mediasize_unknown_landscape" />
   <java-symbol type="string" name="mediasize_iso_a0" />
@@ -1411,6 +1412,9 @@
   <java-symbol type="drawable" name="ic_qs_one_handed_mode" />
   <java-symbol type="drawable" name="ic_clone_icon_badge" />
   <java-symbol type="drawable" name="ic_clone_badge" />
+  <java-symbol type="drawable" name="ic_private_profile_icon_badge" />
+  <java-symbol type="drawable" name="ic_private_profile_badge" />
+  <java-symbol type="drawable" name="stat_sys_private_profile_status" />
 
   <java-symbol type="drawable" name="sim_light_blue" />
   <java-symbol type="drawable" name="sim_light_green" />
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 4064bb9..120d812 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -162,6 +162,7 @@
     destroyHardwareResources();
     mAnimationContext->destroy();
     mRenderThread.cacheManager().onContextStopped(this);
+    mHintSessionWrapper.destroy();
 }
 
 static void setBufferCount(ANativeWindow* window) {
@@ -195,6 +196,7 @@
 void CanvasContext::setSurface(ANativeWindow* window, bool enableTimeout) {
     ATRACE_CALL();
 
+    startHintSession();
     if (window) {
         mNativeSurface = std::make_unique<ReliableSurface>(window);
         mNativeSurface->init();
diff --git a/libs/hwui/renderthread/HintSessionWrapper.cpp b/libs/hwui/renderthread/HintSessionWrapper.cpp
index 814ac4d..1f338ee 100644
--- a/libs/hwui/renderthread/HintSessionWrapper.cpp
+++ b/libs/hwui/renderthread/HintSessionWrapper.cpp
@@ -93,8 +93,17 @@
         : mUiThreadId(uiThreadId), mRenderThreadId(renderThreadId) {}
 
 HintSessionWrapper::~HintSessionWrapper() {
+    destroy();
+}
+
+void HintSessionWrapper::destroy() {
+    if (mHintSessionFuture.valid()) {
+        mHintSession = mHintSessionFuture.get();
+    }
     if (mHintSession) {
         gAPH_closeSessionFn(mHintSession);
+        mSessionValid = true;
+        mHintSession = nullptr;
     }
 }
 
diff --git a/libs/hwui/renderthread/HintSessionWrapper.h b/libs/hwui/renderthread/HintSessionWrapper.h
index 24b8150..bdb9959 100644
--- a/libs/hwui/renderthread/HintSessionWrapper.h
+++ b/libs/hwui/renderthread/HintSessionWrapper.h
@@ -37,6 +37,7 @@
     void sendLoadResetHint();
     void sendLoadIncreaseHint();
     bool init();
+    void destroy();
 
 private:
     APerformanceHintSession* mHintSession = nullptr;
diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp
index a6e8c08f..e2b541a 100644
--- a/libs/hwui/renderthread/VulkanManager.cpp
+++ b/libs/hwui/renderthread/VulkanManager.cpp
@@ -384,25 +384,23 @@
 }
 
 void VulkanManager::initialize() {
-    std::lock_guard _lock{mInitializeLock};
+    std::call_once(mInitFlag, [&] {
+        GET_PROC(EnumerateInstanceVersion);
+        uint32_t instanceVersion;
+        LOG_ALWAYS_FATAL_IF(mEnumerateInstanceVersion(&instanceVersion));
+        LOG_ALWAYS_FATAL_IF(instanceVersion < VK_MAKE_VERSION(1, 1, 0));
 
-    if (mDevice != VK_NULL_HANDLE) {
-        return;
-    }
+        this->setupDevice(mExtensions, mPhysicalDeviceFeatures2);
 
-    GET_PROC(EnumerateInstanceVersion);
-    uint32_t instanceVersion;
-    LOG_ALWAYS_FATAL_IF(mEnumerateInstanceVersion(&instanceVersion));
-    LOG_ALWAYS_FATAL_IF(instanceVersion < VK_MAKE_VERSION(1, 1, 0));
+        mGetDeviceQueue(mDevice, mGraphicsQueueIndex, 0, &mGraphicsQueue);
+        mGetDeviceQueue(mDevice, mGraphicsQueueIndex, 1, &mAHBUploadQueue);
 
-    this->setupDevice(mExtensions, mPhysicalDeviceFeatures2);
+        if (Properties::enablePartialUpdates && Properties::useBufferAge) {
+            mSwapBehavior = SwapBehavior::BufferAge;
+        }
 
-    mGetDeviceQueue(mDevice, mGraphicsQueueIndex, 0, &mGraphicsQueue);
-    mGetDeviceQueue(mDevice, mGraphicsQueueIndex, 1, &mAHBUploadQueue);
-
-    if (Properties::enablePartialUpdates && Properties::useBufferAge) {
-        mSwapBehavior = SwapBehavior::BufferAge;
-    }
+        mInitialized = true;
+    });
 }
 
 static void onGrContextReleased(void* context) {
diff --git a/libs/hwui/renderthread/VulkanManager.h b/libs/hwui/renderthread/VulkanManager.h
index 2be1ffd..dbef7fb 100644
--- a/libs/hwui/renderthread/VulkanManager.h
+++ b/libs/hwui/renderthread/VulkanManager.h
@@ -70,7 +70,7 @@
     void initialize();
 
     // Quick check to see if the VulkanManager has been initialized.
-    bool hasVkContext() { return mDevice != VK_NULL_HANDLE; }
+    bool hasVkContext() { return mInitialized; }
 
     // Create and destroy functions for wrapping an ANativeWindow in a VulkanSurface
     VulkanSurface* createSurface(ANativeWindow* window,
@@ -204,7 +204,8 @@
     VkSemaphore mSwapSemaphore = VK_NULL_HANDLE;
     void* mDestroySemaphoreContext = nullptr;
 
-    std::mutex mInitializeLock;
+    std::once_flag mInitFlag;
+    std::atomic_bool mInitialized = false;
 };
 
 } /* namespace renderthread */
diff --git a/libs/input/PointerController.cpp b/libs/input/PointerController.cpp
index 435452c..9695e6f 100644
--- a/libs/input/PointerController.cpp
+++ b/libs/input/PointerController.cpp
@@ -290,7 +290,7 @@
     fade(Transition::GRADUAL);
 }
 
-void PointerController::onDisplayViewportsUpdated(std::vector<DisplayViewport>& viewports) {
+void PointerController::onDisplayViewportsUpdated(const std::vector<DisplayViewport>& viewports) {
     std::unordered_set<int32_t> displayIdSet;
     for (const DisplayViewport& viewport : viewports) {
         displayIdSet.insert(viewport.displayId);
diff --git a/libs/input/PointerController.h b/libs/input/PointerController.h
index c7e772d..01748a8 100644
--- a/libs/input/PointerController.h
+++ b/libs/input/PointerController.h
@@ -70,7 +70,7 @@
     void setInactivityTimeout(InactivityTimeout inactivityTimeout);
     void doInactivityTimeout();
     void reloadPointerResources();
-    void onDisplayViewportsUpdated(std::vector<DisplayViewport>& viewports);
+    void onDisplayViewportsUpdated(const std::vector<DisplayViewport>& viewports);
 
     void onDisplayInfosChangedLocked(const std::vector<gui::DisplayInfo>& displayInfos)
             REQUIRES(getLock());
diff --git a/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowUserManager.java b/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowUserManager.java
index 60d7721..78fb38f 100644
--- a/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowUserManager.java
+++ b/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowUserManager.java
@@ -16,8 +16,6 @@
 
 package com.android.settingslib.testutils.shadow;
 
-import static android.os.Build.VERSION_CODES.N_MR1;
-
 import android.annotation.UserIdInt;
 import android.content.Context;
 import android.content.pm.UserInfo;
@@ -27,7 +25,8 @@
 
 import org.robolectric.annotation.Implementation;
 import org.robolectric.annotation.Implements;
-import org.robolectric.shadows.ShadowBuild;
+import org.robolectric.versioning.AndroidVersions.NMR1;
+import org.robolectric.versioning.AndroidVersions.U;
 
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -74,7 +73,7 @@
     /**
      * @return {@code false} by default, or the value specified via {@link #setIsAdminUser(boolean)}
      */
-    @Implementation(minSdk = N_MR1)
+    @Implementation(minSdk = NMR1.SDK_INT)
     public boolean isAdminUser() {
         return getUserInfo(UserHandle.myUserId()).isAdmin();
     }
@@ -98,7 +97,7 @@
         mUserPropertiesMap.putIfAbsent(userId, userProperties);
     }
 
-    @Implementation(minSdk = ShadowBuild.UPSIDE_DOWN_CAKE)
+    @Implementation(minSdk = U.SDK_INT)
     protected UserProperties getUserProperties(UserHandle user) {
         return mUserPropertiesMap.getOrDefault(user.getIdentifier(),
             new UserProperties(new UserProperties.Builder().build()));
diff --git a/services/core/java/com/android/server/pm/UserTypeFactory.java b/services/core/java/com/android/server/pm/UserTypeFactory.java
index d5231b5..b7f9aaf 100644
--- a/services/core/java/com/android/server/pm/UserTypeFactory.java
+++ b/services/core/java/com/android/server/pm/UserTypeFactory.java
@@ -275,18 +275,18 @@
                 .setBaseType(FLAG_PROFILE)
                 .setMaxAllowedPerParent(1)
                 .setLabel(0)
-                .setIconBadge(com.android.internal.R.drawable.ic_test_icon_badge_experiment)
-                .setBadgePlain(com.android.internal.R.drawable.ic_test_badge_experiment)
-                .setBadgeNoBackground(com.android.internal.R.drawable.ic_test_badge_no_background)
-                .setStatusBarIcon(com.android.internal.R.drawable.ic_test_badge_experiment)
+                .setIconBadge(com.android.internal.R.drawable.ic_private_profile_icon_badge)
+                .setBadgePlain(com.android.internal.R.drawable.ic_private_profile_badge)
+                // Private Profile doesn't use BadgeNoBackground, so just set to BadgePlain
+                // as a placeholder.
+                .setBadgeNoBackground(com.android.internal.R.drawable.ic_private_profile_badge)
+                .setStatusBarIcon(com.android.internal.R.drawable.stat_sys_private_profile_status)
                 .setBadgeLabels(
-                        com.android.internal.R.string.managed_profile_label_badge,
-                        com.android.internal.R.string.managed_profile_label_badge_2,
-                        com.android.internal.R.string.managed_profile_label_badge_3)
+                        com.android.internal.R.string.private_profile_label_badge)
                 .setBadgeColors(
-                        com.android.internal.R.color.profile_badge_2)
+                        com.android.internal.R.color.system_accent1_900)
                 .setDarkThemeBadgeColors(
-                        com.android.internal.R.color.profile_badge_2_dark)
+                        com.android.internal.R.color.system_accent1_900)
                 .setDefaultRestrictions(getDefaultProfileRestrictions())
                 .setDefaultSecureSettings(getDefaultNonManagedProfileSecureSettings())
                 .setDefaultUserProperties(new UserProperties.Builder()
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 5ab8d36..788299c 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -262,7 +262,8 @@
 
 class NativeInputManager : public virtual InputReaderPolicyInterface,
                            public virtual InputDispatcherPolicyInterface,
-                           public virtual PointerControllerPolicyInterface {
+                           public virtual PointerControllerPolicyInterface,
+                           public virtual PointerChoreographerPolicyInterface {
 protected:
     virtual ~NativeInputManager();
 
@@ -370,6 +371,9 @@
     virtual PointerIconStyle getCustomPointerIconId();
     virtual void onPointerDisplayIdChanged(int32_t displayId, const FloatPoint& position);
 
+    /* --- PointerControllerPolicyInterface implementation --- */
+    virtual std::shared_ptr<PointerControllerInterface> createPointerController() override;
+
 private:
     sp<InputManagerInterface> mInputManager;
 
@@ -402,8 +406,12 @@
         // Sprite controller singleton, created on first use.
         std::shared_ptr<SpriteController> spriteController{};
 
+        // TODO(b/293587049): Remove when the PointerChoreographer refactoring is complete.
         // Pointer controller singleton, created and destroyed as needed.
-        std::weak_ptr<PointerController> pointerController{};
+        std::weak_ptr<PointerController> legacyPointerController{};
+
+        // The list of PointerControllers created and managed by the PointerChoreographer.
+        std::list<std::weak_ptr<PointerController>> pointerControllers{};
 
         // Input devices to be disabled
         std::set<int32_t> disabledInputDevices{};
@@ -443,6 +451,9 @@
             jmethodID method, const char* methodName,
             std::function<T(std::string)> opOnValue = [](auto&& v) { return std::move(v); });
 
+    void forEachPointerControllerLocked(std::function<void(PointerController&)> apply)
+            REQUIRES(mLock);
+
     static inline JNIEnv* jniEnv() { return AndroidRuntime::getJNIEnv(); }
 };
 
@@ -452,7 +463,7 @@
 
     mServiceObj = env->NewGlobalRef(serviceObj);
 
-    InputManager* im = new InputManager(this, *this);
+    InputManager* im = new InputManager(this, *this, *this);
     mInputManager = im;
     defaultServiceManager()->addService(String16("inputflinger"), im);
 }
@@ -465,10 +476,8 @@
 
 void NativeInputManager::dump(std::string& dump) {
     dump += "Input Manager State:\n";
-    {
-        dump += StringPrintf(INDENT "Interactive: %s\n", toString(mInteractive.load()));
-    }
-    {
+    dump += StringPrintf(INDENT "Interactive: %s\n", toString(mInteractive.load()));
+    { // acquire lock
         std::scoped_lock _l(mLock);
         dump += StringPrintf(INDENT "System UI Lights Out: %s\n",
                              toString(mLocked.systemUiLightsOut));
@@ -480,11 +489,8 @@
         dump += StringPrintf(INDENT "Pointer Capture: %s, seq=%" PRIu32 "\n",
                              mLocked.pointerCaptureRequest.enable ? "Enabled" : "Disabled",
                              mLocked.pointerCaptureRequest.seq);
-        auto pointerController = mLocked.pointerController.lock();
-        if (pointerController != nullptr) {
-            pointerController->dump(dump);
-        }
-    }
+        forEachPointerControllerLocked([&dump](PointerController& pc) { pc.dump(dump); });
+    } // release lock
     dump += "\n";
 
     mInputManager->dump(dump);
@@ -524,10 +530,9 @@
     { // acquire lock
         std::scoped_lock _l(mLock);
         mLocked.viewports = viewports;
-        std::shared_ptr<PointerController> controller = mLocked.pointerController.lock();
-        if (controller != nullptr) {
-            controller->onDisplayViewportsUpdated(mLocked.viewports);
-        }
+        forEachPointerControllerLocked([viewports = std::move(viewports)](PointerController& pc) {
+            pc.onDisplayViewportsUpdated(viewports);
+        });
     } // release lock
 
     mInputManager->getReader().requestRefreshConfiguration(
@@ -700,23 +705,51 @@
     return map;
 }
 
+void NativeInputManager::forEachPointerControllerLocked(
+        std::function<void(PointerController&)> apply) {
+    if (auto pc = mLocked.legacyPointerController.lock(); pc) {
+        apply(*pc);
+    }
+
+    auto it = mLocked.pointerControllers.begin();
+    while (it != mLocked.pointerControllers.end()) {
+        auto pc = it->lock();
+        if (!pc) {
+            it = mLocked.pointerControllers.erase(it);
+            continue;
+        }
+        apply(*pc);
+    }
+}
+
+// TODO(b/293587049): Remove the old way of obtaining PointerController when the
+//  PointerChoreographer refactoring is complete.
 std::shared_ptr<PointerControllerInterface> NativeInputManager::obtainPointerController(
         int32_t /* deviceId */) {
     ATRACE_CALL();
     std::scoped_lock _l(mLock);
 
-    std::shared_ptr<PointerController> controller = mLocked.pointerController.lock();
+    std::shared_ptr<PointerController> controller = mLocked.legacyPointerController.lock();
     if (controller == nullptr) {
         ensureSpriteControllerLocked();
 
         controller = PointerController::create(this, mLooper, *mLocked.spriteController);
-        mLocked.pointerController = controller;
+        mLocked.legacyPointerController = controller;
         updateInactivityTimeoutLocked();
     }
 
     return controller;
 }
 
+std::shared_ptr<PointerControllerInterface> NativeInputManager::createPointerController() {
+    std::scoped_lock _l(mLock);
+    ensureSpriteControllerLocked();
+    std::shared_ptr<PointerController> pc =
+            PointerController::create(this, mLooper, *mLocked.spriteController);
+    mLocked.pointerControllers.emplace_back(pc);
+    return pc;
+}
+
 void NativeInputManager::onPointerDisplayIdChanged(int32_t pointerDisplayId,
                                                    const FloatPoint& position) {
     JNIEnv* env = jniEnv();
@@ -1071,13 +1104,9 @@
 }
 
 void NativeInputManager::updateInactivityTimeoutLocked() REQUIRES(mLock) {
-    std::shared_ptr<PointerController> controller = mLocked.pointerController.lock();
-    if (controller == nullptr) {
-        return;
-    }
-
-    controller->setInactivityTimeout(mLocked.systemUiLightsOut ? InactivityTimeout::SHORT
-                                                               : InactivityTimeout::NORMAL);
+    forEachPointerControllerLocked([lightsOut = mLocked.systemUiLightsOut](PointerController& pc) {
+        pc.setInactivityTimeout(lightsOut ? InactivityTimeout::SHORT : InactivityTimeout::NORMAL);
+    });
 }
 
 void NativeInputManager::setPointerDisplayId(int32_t displayId) {
@@ -1247,7 +1276,7 @@
 
 void NativeInputManager::setPointerIconType(PointerIconStyle iconId) {
     std::scoped_lock _l(mLock);
-    std::shared_ptr<PointerController> controller = mLocked.pointerController.lock();
+    std::shared_ptr<PointerController> controller = mLocked.legacyPointerController.lock();
     if (controller != nullptr) {
         controller->updatePointerIcon(iconId);
     }
@@ -1255,15 +1284,12 @@
 
 void NativeInputManager::reloadPointerIcons() {
     std::scoped_lock _l(mLock);
-    std::shared_ptr<PointerController> controller = mLocked.pointerController.lock();
-    if (controller != nullptr) {
-        controller->reloadPointerResources();
-    }
+    forEachPointerControllerLocked([](PointerController& pc) { pc.reloadPointerResources(); });
 }
 
 void NativeInputManager::setCustomPointerIcon(const SpriteIcon& icon) {
     std::scoped_lock _l(mLock);
-    std::shared_ptr<PointerController> controller = mLocked.pointerController.lock();
+    std::shared_ptr<PointerController> controller = mLocked.legacyPointerController.lock();
     if (controller != nullptr) {
         controller->setCustomPointerIcon(icon);
     }
@@ -1656,7 +1682,7 @@
 
 FloatPoint NativeInputManager::getMouseCursorPosition() {
     std::scoped_lock _l(mLock);
-    const auto pc = mLocked.pointerController.lock();
+    const auto pc = mLocked.legacyPointerController.lock();
     if (!pc) return {AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION};
 
     return pc->getPosition();
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
index dce162c..552b59c 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
@@ -188,6 +188,7 @@
                 .when(() -> LocalServices.getService(BatteryManagerInternal.class));
         doReturn(mUsageStatsManager)
                 .when(() -> LocalServices.getService(UsageStatsManagerInternal.class));
+        JobSchedulerService.sUsageStatsManagerInternal = mUsageStatsManager;
         doReturn(mPowerAllowlistInternal)
                 .when(() -> LocalServices.getService(PowerAllowlistInternal.class));
         // Used in JobStatus.