Merge "Make testMultipleMessagesDispatched slightly less overspecified." into tm-dev
diff --git a/Android.bp b/Android.bp
index 753cefc..edaa11e3 100644
--- a/Android.bp
+++ b/Android.bp
@@ -97,6 +97,7 @@
         ":platform-compat-native-aidl",
 
         // AIDL sources from external directories
+        ":android.hardware.gnss-V2-java-source",
         ":android.hardware.graphics.common-V3-java-source",
         ":android.hardware.security.keymint-V2-java-source",
         ":android.hardware.security.secureclock-V1-java-source",
diff --git a/core/api/current.txt b/core/api/current.txt
index ec63a05..3f12b6c 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -5815,6 +5815,7 @@
   public class LocaleManager {
     method @NonNull public android.os.LocaleList getApplicationLocales();
     method @NonNull @RequiresPermission(value="android.permission.READ_APP_SPECIFIC_LOCALES", conditional=true) public android.os.LocaleList getApplicationLocales(@NonNull String);
+    method @NonNull public android.os.LocaleList getSystemLocales();
     method public void setApplicationLocales(@NonNull android.os.LocaleList);
   }
 
@@ -9736,8 +9737,8 @@
     method @Nullable public abstract android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, @Nullable String, @Nullable android.os.Handler, int);
     method @Deprecated @RequiresPermission(android.Manifest.permission.BROADCAST_STICKY) public abstract void removeStickyBroadcast(@RequiresPermission android.content.Intent);
     method @Deprecated @RequiresPermission(allOf={"android.permission.INTERACT_ACROSS_USERS", android.Manifest.permission.BROADCAST_STICKY}) public abstract void removeStickyBroadcastAsUser(@RequiresPermission android.content.Intent, android.os.UserHandle);
-    method public void revokeOwnPermissionOnKill(@NonNull String);
-    method public void revokeOwnPermissionsOnKill(@NonNull java.util.Collection<java.lang.String>);
+    method public void revokeSelfPermissionOnKill(@NonNull String);
+    method public void revokeSelfPermissionsOnKill(@NonNull java.util.Collection<java.lang.String>);
     method public abstract void revokeUriPermission(android.net.Uri, int);
     method public abstract void revokeUriPermission(String, android.net.Uri, int);
     method public abstract void sendBroadcast(@RequiresPermission android.content.Intent);
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 5df9881..d094f4b 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -5490,6 +5490,32 @@
     method @NonNull public android.location.GnssCapabilities.Builder setHasSatellitePvt(boolean);
   }
 
+  public final class GnssExcessPathInfo implements android.os.Parcelable {
+    method public int describeContents();
+    method @FloatRange(from=0.0f) public float getAttenuationDb();
+    method @FloatRange(from=0.0f) public float getExcessPathLengthMeters();
+    method @FloatRange(from=0.0f) public float getExcessPathLengthUncertaintyMeters();
+    method @NonNull public android.location.GnssReflectingPlane getReflectingPlane();
+    method public boolean hasAttenuation();
+    method public boolean hasExcessPathLength();
+    method public boolean hasExcessPathLengthUncertainty();
+    method public boolean hasReflectingPlane();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssExcessPathInfo> CREATOR;
+  }
+
+  public static final class GnssExcessPathInfo.Builder {
+    ctor public GnssExcessPathInfo.Builder();
+    method @NonNull public android.location.GnssExcessPathInfo build();
+    method @NonNull public android.location.GnssExcessPathInfo.Builder clearAttenuationDb();
+    method @NonNull public android.location.GnssExcessPathInfo.Builder clearExcessPathLengthMeters();
+    method @NonNull public android.location.GnssExcessPathInfo.Builder clearExcessPathLengthUncertaintyMeters();
+    method @NonNull public android.location.GnssExcessPathInfo.Builder setAttenuationDb(@FloatRange(from=0.0f) float);
+    method @NonNull public android.location.GnssExcessPathInfo.Builder setExcessPathLengthMeters(@FloatRange(from=0.0f) float);
+    method @NonNull public android.location.GnssExcessPathInfo.Builder setExcessPathLengthUncertaintyMeters(@FloatRange(from=0.0f) float);
+    method @NonNull public android.location.GnssExcessPathInfo.Builder setReflectingPlane(@Nullable android.location.GnssReflectingPlane);
+  }
+
   public final class GnssMeasurement implements android.os.Parcelable {
     method @Nullable public java.util.Collection<android.location.CorrelationVector> getCorrelationVectors();
     method @Nullable public android.location.SatellitePvt getSatellitePvt();
@@ -5571,15 +5597,18 @@
   public final class GnssSingleSatCorrection implements android.os.Parcelable {
     method public int describeContents();
     method @FloatRange(from=0.0f, fromInclusive=false) public float getCarrierFrequencyHz();
+    method @FloatRange(from=0.0f) public float getCombinedAttenuationDb();
     method public int getConstellationType();
     method @FloatRange(from=0.0f) public float getExcessPathLengthMeters();
     method @FloatRange(from=0.0f) public float getExcessPathLengthUncertaintyMeters();
+    method @NonNull public java.util.List<android.location.GnssExcessPathInfo> getGnssExcessPathInfoList();
     method @FloatRange(from=0.0f, to=1.0f) public float getProbabilityLineOfSight();
-    method @Nullable public android.location.GnssReflectingPlane getReflectingPlane();
+    method @Deprecated @Nullable public android.location.GnssReflectingPlane getReflectingPlane();
     method @IntRange(from=0) public int getSatelliteId();
+    method public boolean hasCombinedAttenuation();
     method public boolean hasExcessPathLength();
     method public boolean hasExcessPathLengthUncertainty();
-    method public boolean hasReflectingPlane();
+    method @Deprecated public boolean hasReflectingPlane();
     method public boolean hasValidSatelliteLineOfSight();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.location.GnssSingleSatCorrection> CREATOR;
@@ -5588,15 +5617,18 @@
   public static final class GnssSingleSatCorrection.Builder {
     ctor public GnssSingleSatCorrection.Builder();
     method @NonNull public android.location.GnssSingleSatCorrection build();
+    method @NonNull public android.location.GnssSingleSatCorrection.Builder clearCombinedAttenuationDb();
     method @NonNull public android.location.GnssSingleSatCorrection.Builder clearExcessPathLengthMeters();
     method @NonNull public android.location.GnssSingleSatCorrection.Builder clearExcessPathLengthUncertaintyMeters();
     method @NonNull public android.location.GnssSingleSatCorrection.Builder clearProbabilityLineOfSight();
     method @NonNull public android.location.GnssSingleSatCorrection.Builder setCarrierFrequencyHz(@FloatRange(from=0.0f, fromInclusive=false) float);
+    method @NonNull public android.location.GnssSingleSatCorrection.Builder setCombinedAttenuationDb(@FloatRange(from=0.0f) float);
     method @NonNull public android.location.GnssSingleSatCorrection.Builder setConstellationType(int);
     method @NonNull public android.location.GnssSingleSatCorrection.Builder setExcessPathLengthMeters(@FloatRange(from=0.0f) float);
     method @NonNull public android.location.GnssSingleSatCorrection.Builder setExcessPathLengthUncertaintyMeters(@FloatRange(from=0.0f) float);
+    method @NonNull public android.location.GnssSingleSatCorrection.Builder setGnssExcessPathInfoList(@NonNull java.util.List<android.location.GnssExcessPathInfo>);
     method @NonNull public android.location.GnssSingleSatCorrection.Builder setProbabilityLineOfSight(@FloatRange(from=0.0f, to=1.0f) float);
-    method @NonNull public android.location.GnssSingleSatCorrection.Builder setReflectingPlane(@Nullable android.location.GnssReflectingPlane);
+    method @Deprecated @NonNull public android.location.GnssSingleSatCorrection.Builder setReflectingPlane(@Nullable android.location.GnssReflectingPlane);
     method @NonNull public android.location.GnssSingleSatCorrection.Builder setSatelliteId(@IntRange(from=0) int);
   }
 
@@ -10049,9 +10081,9 @@
     method @BinderThread public void onOneTimePermissionSessionTimeout(@NonNull String);
     method @Deprecated @BinderThread public void onRestoreDelayedRuntimePermissionsBackup(@NonNull String, @NonNull android.os.UserHandle, @NonNull java.util.function.Consumer<java.lang.Boolean>);
     method @Deprecated @BinderThread public void onRestoreRuntimePermissionsBackup(@NonNull android.os.UserHandle, @NonNull java.io.InputStream, @NonNull Runnable);
-    method @BinderThread public void onRevokeOwnPermissionsOnKill(@NonNull String, @NonNull java.util.List<java.lang.String>, @NonNull Runnable);
     method @BinderThread public abstract void onRevokeRuntimePermission(@NonNull String, @NonNull String, @NonNull Runnable);
     method @BinderThread public abstract void onRevokeRuntimePermissions(@NonNull java.util.Map<java.lang.String,java.util.List<java.lang.String>>, boolean, int, @NonNull String, @NonNull java.util.function.Consumer<java.util.Map<java.lang.String,java.util.List<java.lang.String>>>);
+    method @BinderThread public void onRevokeSelfPermissionsOnKill(@NonNull String, @NonNull java.util.List<java.lang.String>, @NonNull Runnable);
     method @Deprecated @BinderThread public abstract void onSetRuntimePermissionGrantStateByDeviceAdmin(@NonNull String, @NonNull String, @NonNull String, int, @NonNull java.util.function.Consumer<java.lang.Boolean>);
     method @BinderThread public void onSetRuntimePermissionGrantStateByDeviceAdmin(@NonNull String, @NonNull android.permission.AdminPermissionControlParams, @NonNull java.util.function.Consumer<java.lang.Boolean>);
     method @BinderThread public void onStageAndApplyRuntimePermissionsBackup(@NonNull android.os.UserHandle, @NonNull java.io.InputStream, @NonNull Runnable);
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 2e8bed3..d984abe 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -300,7 +300,6 @@
   }
 
   public class LocaleManager {
-    method @Nullable public android.os.LocaleList getSystemLocales();
     method public void setSystemLocales(@NonNull android.os.LocaleList);
   }
 
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index f5eb1f6..ac46066 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -77,6 +77,7 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.os.storage.StorageManager;
+import android.permission.PermissionControllerManager;
 import android.permission.PermissionManager;
 import android.system.ErrnoException;
 import android.system.Os;
@@ -216,6 +217,12 @@
     @UnsupportedAppUsage
     private @Nullable ClassLoader mClassLoader;
 
+    /**
+     * The {@link com.android.server.wm.WindowToken} representing this instance if it is
+     * {@link #CONTEXT_TYPE_WINDOW_CONTEXT} or {@link #CONTEXT_TYPE_SYSTEM_OR_SYSTEM_UI}.
+     * If the type is {@link #CONTEXT_TYPE_ACTIVITY}, then represents the
+     * {@link android.window.WindowContainerToken} of the activity.
+     */
     private final @Nullable IBinder mToken;
 
     private final @NonNull UserHandle mUser;
@@ -2180,8 +2187,9 @@
     }
 
     @Override
-    public void revokeOwnPermissionsOnKill(@NonNull Collection<String> permissions) {
-        getSystemService(PermissionManager.class).revokeOwnPermissionsOnKill(permissions);
+    public void revokeSelfPermissionsOnKill(@NonNull Collection<String> permissions) {
+        getSystemService(PermissionControllerManager.class).revokeSelfPermissionsOnKill(
+                getPackageName(), new ArrayList<String>(permissions));
     }
 
     @Override
diff --git a/core/java/android/app/ILocaleManager.aidl b/core/java/android/app/ILocaleManager.aidl
index 348cb2d..3002c8b 100644
--- a/core/java/android/app/ILocaleManager.aidl
+++ b/core/java/android/app/ILocaleManager.aidl
@@ -40,4 +40,9 @@
       */
      LocaleList getApplicationLocales(String packageName, int userId);
 
+     /**
+       * Returns the current system locales.
+       */
+     LocaleList getSystemLocales();
+
  }
\ No newline at end of file
diff --git a/core/java/android/app/KeyguardManager.java b/core/java/android/app/KeyguardManager.java
index cedf483e..e9c29b8 100644
--- a/core/java/android/app/KeyguardManager.java
+++ b/core/java/android/app/KeyguardManager.java
@@ -1103,9 +1103,12 @@
     }
 
     /**
-     * Registers a listener to execute when the keyguard visibility changes.
+     * Registers a listener to execute when the keyguard locked state changes.
      *
-     * @param listener The listener to add to receive keyguard visibility changes.
+     * @param listener The listener to add to receive keyguard locked state changes.
+     *
+     * @see #isKeyguardLocked()
+     * @see #removeKeyguardLockedStateListener(KeyguardLockedStateListener)
      */
     @RequiresPermission(Manifest.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE)
     public void addKeyguardLockedStateListener(@NonNull @CallbackExecutor Executor executor,
@@ -1124,7 +1127,12 @@
     }
 
     /**
-     * Unregisters a listener that executes when the keyguard visibility changes.
+     * Unregisters a listener that executes when the keyguard locked state changes.
+     *
+     * @param listener The listener to remove.
+     *
+     * @see #isKeyguardLocked()
+     * @see #addKeyguardLockedStateListener(Executor, KeyguardLockedStateListener)
      */
     @RequiresPermission(Manifest.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE)
     public void removeKeyguardLockedStateListener(@NonNull KeyguardLockedStateListener listener) {
diff --git a/core/java/android/app/LocaleManager.java b/core/java/android/app/LocaleManager.java
index 522dc84..efe9e35 100644
--- a/core/java/android/app/LocaleManager.java
+++ b/core/java/android/app/LocaleManager.java
@@ -18,7 +18,6 @@
 
 import android.Manifest;
 import android.annotation.NonNull;
-import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
@@ -127,6 +126,26 @@
     }
 
     /**
+     * Returns the current system locales, ignoring app-specific overrides.
+     *
+     * <p><b>Note:</b> Apps should generally access the user's locale preferences as indicated in
+     * their in-process {@link LocaleList}s. However, in case an app-specific locale is set, this
+     * method helps cater to rare use-cases which might require specifically knowing the system
+     * locale.
+     *
+     * <p><b>Note:</b> This API is not user-aware. It returns the system locales for the foreground
+     * user.
+     */
+    @NonNull
+    public LocaleList getSystemLocales() {
+        try {
+            return mService.getSystemLocales();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Sets the current system locales to the provided value.
      *
      * @hide
@@ -142,19 +161,4 @@
         }
     }
 
-    /**
-     * Returns the current system locales for the device.
-     *
-     * @hide
-     */
-    @TestApi
-    @Nullable
-    public LocaleList getSystemLocales() {
-        try {
-            return ActivityManager.getService().getConfiguration().getLocales();
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
 }
diff --git a/core/java/android/app/usage/BroadcastResponseStats.java b/core/java/android/app/usage/BroadcastResponseStats.java
index e1d37e1..572c453 100644
--- a/core/java/android/app/usage/BroadcastResponseStats.java
+++ b/core/java/android/app/usage/BroadcastResponseStats.java
@@ -29,6 +29,8 @@
  * Class containing a collection of stats related to response events started from an app
  * after receiving a broadcast.
  *
+ * @see UsageStatsManager#queryBroadcastResponseStats(String, long)
+ * @see UsageStatsManager#clearBroadcastResponseStats(String, long)
  * @hide
  */
 @SystemApi
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 60efb4d..24b1b6a 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -6508,22 +6508,22 @@
 
 
     /**
-     * Triggers the asynchronous revocation of a permission.
+     * Triggers the asynchronous revocation of a runtime permission. If the permission is not
+     * currently granted, nothing happens (even if later granted by the user).
      *
      * @param permName The name of the permission to be revoked.
-     * @see #revokeOwnPermissionsOnKill(Collection)
+     * @see #revokeSelfPermissionsOnKill(Collection)
+     * @throws IllegalArgumentException if the permission is not a runtime permission
      */
-    public void revokeOwnPermissionOnKill(@NonNull String permName) {
-        revokeOwnPermissionsOnKill(Collections.singletonList(permName));
+    public void revokeSelfPermissionOnKill(@NonNull String permName) {
+        revokeSelfPermissionsOnKill(Collections.singletonList(permName));
     }
 
     /**
      * Triggers the revocation of one or more permissions for the calling package. A package is only
-     * able to revoke a permission under the following conditions:
-     * <ul>
-     * <li>Each permission in {@code permissions} must be granted to the calling package.
-     * <li>Each permission in {@code permissions} must be a runtime permission.
-     * </ul>
+     * able to revoke runtime permissions. If a permission is not currently granted, it is ignored
+     * and will not get revoked (even if later granted by the user). Ultimately, you should never
+     * make assumptions about a permission status as users may grant or revoke them at any time.
      * <p>
      * Background permissions which have no corresponding foreground permission still granted once
      * the revocation is effective will also be revoked.
@@ -6549,8 +6549,9 @@
      * @param permissions Collection of permissions to be revoked.
      * @see PackageManager#getGroupOfPlatformPermission(String, Executor, Consumer)
      * @see PackageManager#getPlatformPermissionsForGroup(String, Executor, Consumer)
+     * @throws IllegalArgumentException if any of the permissions is not a runtime permission
      */
-    public void revokeOwnPermissionsOnKill(@NonNull Collection<String> permissions) {
+    public void revokeSelfPermissionsOnKill(@NonNull Collection<String> permissions) {
         throw new AbstractMethodError("Must be overridden in implementing class");
     }
 
@@ -7145,8 +7146,9 @@
     }
 
     /**
-     * Returns token if the {@link Context} is a {@link android.app.WindowContext}. Returns
-     * {@code null} otherwise.
+     * Returns the {@link IBinder} representing the associated
+     * {@link com.android.server.wm.WindowToken} if the {@link Context} is a
+     * {@link android.app.WindowContext}. Returns {@code null} otherwise.
      *
      * @hide
      */
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 9adf173..4ecd776 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -1036,8 +1036,8 @@
     }
 
     @Override
-    public void revokeOwnPermissionsOnKill(@NonNull Collection<String> permissions) {
-        mBase.revokeOwnPermissionsOnKill(permissions);
+    public void revokeSelfPermissionsOnKill(@NonNull Collection<String> permissions) {
+        mBase.revokeSelfPermissionsOnKill(permissions);
     }
 
     @Override
diff --git a/core/java/android/inputmethodservice/NavigationBarController.java b/core/java/android/inputmethodservice/NavigationBarController.java
index 0f9075b..03d1151 100644
--- a/core/java/android/inputmethodservice/NavigationBarController.java
+++ b/core/java/android/inputmethodservice/NavigationBarController.java
@@ -294,8 +294,8 @@
                 dest.setTouchableInsets(
                         ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
 
-                // TODO(b/205803355): See if we can use View#OnLayoutChangeListener().
-                // TODO(b/205803355): See if we can replace DecorView#mNavigationColorViewState.view
+                // TODO(b/215443343): See if we can use View#OnLayoutChangeListener().
+                // TODO(b/215443343): See if we can replace DecorView#mNavigationColorViewState.view
                 boolean zOrderChanged = false;
                 if (decor instanceof ViewGroup) {
                     ViewGroup decorGroup = (ViewGroup) decor;
diff --git a/core/java/android/inputmethodservice/navigationbar/DeadZone.java b/core/java/android/inputmethodservice/navigationbar/DeadZone.java
index 4cfd813..382b6b0 100644
--- a/core/java/android/inputmethodservice/navigationbar/DeadZone.java
+++ b/core/java/android/inputmethodservice/navigationbar/DeadZone.java
@@ -148,7 +148,7 @@
             if (DEBUG) {
                 Log.v(TAG, this + " ACTION_DOWN: " + event.getX() + "," + event.getY());
             }
-            //TODO(b/205803355): call mNavBarController.touchAutoDim(mDisplayId); here
+            //TODO(b/215443343): call mNavBarController.touchAutoDim(mDisplayId); here
             int size = (int) getSize(event.getEventTime());
             // In the vertical orientation consume taps along the left edge.
             // In horizontal orientation consume taps along the top edge.
diff --git a/core/java/android/inputmethodservice/navigationbar/KeyButtonView.java b/core/java/android/inputmethodservice/navigationbar/KeyButtonView.java
index cfdb6ca..92d358f 100644
--- a/core/java/android/inputmethodservice/navigationbar/KeyButtonView.java
+++ b/core/java/android/inputmethodservice/navigationbar/KeyButtonView.java
@@ -89,7 +89,7 @@
     public KeyButtonView(Context context, AttributeSet attrs) {
         super(context, attrs);
 
-        // TODO(b/205803355): Figure out better place to set this.
+        // TODO(b/215443343): Figure out better place to set this.
         switch (getId()) {
             case com.android.internal.R.id.input_method_nav_back:
                 mCode = KEYCODE_BACK;
@@ -285,11 +285,11 @@
     private void sendEvent(int action, int flags, long when) {
         if (mCode == KeyEvent.KEYCODE_BACK && flags != KeyEvent.FLAG_LONG_PRESS) {
             if (action == MotionEvent.ACTION_UP) {
-                // TODO(b/205803355): Implement notifyBackAction();
+                // TODO(b/215443343): Implement notifyBackAction();
             }
         }
 
-        // TODO(b/205803355): Consolidate this logic to somewhere else.
+        // TODO(b/215443343): Consolidate this logic to somewhere else.
         if (mContext instanceof InputMethodService) {
             final int repeatCount = (flags & KeyEvent.FLAG_LONG_PRESS) != 0 ? 1 : 0;
             final KeyEvent ev = new KeyEvent(mDownTime, when, action, mCode, repeatCount,
diff --git a/core/java/android/permission/IPermissionController.aidl b/core/java/android/permission/IPermissionController.aidl
index c9dd06c..e3f02e7 100644
--- a/core/java/android/permission/IPermissionController.aidl
+++ b/core/java/android/permission/IPermissionController.aidl
@@ -59,6 +59,6 @@
     void getHibernationEligibility(
                 in String packageName,
                 in AndroidFuture callback);
-    void revokeOwnPermissionsOnKill(in String packageName, in List<String> permissions,
+    void revokeSelfPermissionsOnKill(in String packageName, in List<String> permissions,
             in AndroidFuture callback);
 }
diff --git a/core/java/android/permission/IPermissionManager.aidl b/core/java/android/permission/IPermissionManager.aidl
index 619c870..6a93b35 100644
--- a/core/java/android/permission/IPermissionManager.aidl
+++ b/core/java/android/permission/IPermissionManager.aidl
@@ -76,8 +76,6 @@
 
     List<SplitPermissionInfoParcelable> getSplitPermissions();
 
-    void revokeOwnPermissionsOnKill(String packageName, in List<String> permissions);
-
     void startOneTimePermissionSession(String packageName, int userId, long timeout,
             long revokeAfterKilledDelay, int importanceToResetTimer,
             int importanceToKeepSessionAlive);
diff --git a/core/java/android/permission/PermissionControllerManager.java b/core/java/android/permission/PermissionControllerManager.java
index a005ab4e..3c2c7f0 100644
--- a/core/java/android/permission/PermissionControllerManager.java
+++ b/core/java/android/permission/PermissionControllerManager.java
@@ -916,15 +916,15 @@
      * @param packageName The name of the package for which the permissions will be revoked.
      * @param permissions List of permissions to be revoked.
      *
-     * @see Context#revokeOwnPermissionsOnKill(java.util.Collection)
+     * @see Context#revokeSelfPermissionsOnKill(java.util.Collection)
      *
      * @hide
      */
-    public void revokeOwnPermissionsOnKill(@NonNull String packageName,
+    public void revokeSelfPermissionsOnKill(@NonNull String packageName,
             @NonNull List<String> permissions) {
         mRemoteService.postAsync(service -> {
             AndroidFuture<Void> callback = new AndroidFuture<>();
-            service.revokeOwnPermissionsOnKill(packageName, permissions, callback);
+            service.revokeSelfPermissionsOnKill(packageName, permissions, callback);
             return callback;
         }).whenComplete((result, err) -> {
             if (err != null) {
diff --git a/core/java/android/permission/PermissionControllerService.java b/core/java/android/permission/PermissionControllerService.java
index 3292e71..4efffc5a 100644
--- a/core/java/android/permission/PermissionControllerService.java
+++ b/core/java/android/permission/PermissionControllerService.java
@@ -40,6 +40,7 @@
 import android.content.Intent;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
+import android.os.Binder;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.ParcelFileDescriptor;
@@ -339,10 +340,10 @@
      * @param permissions List of permissions to be revoked.
      * @param callback Callback waiting for operation to be complete.
      *
-     * @see PermissionManager#revokeOwnPermissionsOnKill(java.util.Collection)
+     * @see android.content.Context#revokeSelfPermissionsOnKill(java.util.Collection)
      */
     @BinderThread
-    public void onRevokeOwnPermissionsOnKill(@NonNull String packageName,
+    public void onRevokeSelfPermissionsOnKill(@NonNull String packageName,
             @NonNull List<String> permissions, @NonNull Runnable callback) {
         throw new AbstractMethodError("Must be overridden in implementing class");
     }
@@ -703,13 +704,19 @@
             }
 
             @Override
-            public void revokeOwnPermissionsOnKill(@NonNull String packageName,
+            public void revokeSelfPermissionsOnKill(@NonNull String packageName,
                     @NonNull List<String> permissions, @NonNull AndroidFuture callback) {
                 try {
-                    enforceSomePermissionsGrantedToCaller(
-                            Manifest.permission.REVOKE_RUNTIME_PERMISSIONS);
                     Objects.requireNonNull(callback);
-                    onRevokeOwnPermissionsOnKill(packageName, permissions,
+
+                    final int callingUid = Binder.getCallingUid();
+                    int targetPackageUid = getPackageManager().getPackageUid(packageName,
+                            PackageManager.PackageInfoFlags.of(0));
+                    if (targetPackageUid != callingUid) {
+                        enforceSomePermissionsGrantedToCaller(
+                                Manifest.permission.REVOKE_RUNTIME_PERMISSIONS);
+                    }
+                    onRevokeSelfPermissionsOnKill(packageName, permissions,
                             () -> callback.complete(null));
                 } catch (Throwable t) {
                     callback.completeExceptionally(t);
diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java
index c509de6..7a797ce 100644
--- a/core/java/android/permission/PermissionManager.java
+++ b/core/java/android/permission/PermissionManager.java
@@ -76,7 +76,6 @@
 import com.android.internal.util.CollectionUtils;
 
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
 import java.util.Objects;
@@ -626,19 +625,6 @@
     }
 
     /**
-     * @see Context#revokeOwnPermissionsOnKill(Collection)
-     * @hide
-     */
-    public void revokeOwnPermissionsOnKill(@NonNull Collection<String> permissions) {
-        try {
-            mPermissionManager.revokeOwnPermissionsOnKill(mContext.getPackageName(),
-                    new ArrayList<String>(permissions));
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    /**
      * Gets the state flags associated with a permission.
      *
      * @param packageName the package name for which to get the flags
diff --git a/core/java/android/util/TimingsTraceLog.java b/core/java/android/util/TimingsTraceLog.java
index 066709f..48a5cea 100644
--- a/core/java/android/util/TimingsTraceLog.java
+++ b/core/java/android/util/TimingsTraceLog.java
@@ -147,7 +147,7 @@
      * Logs a duration so it can be parsed by external tools for performance reporting.
      */
     public void logDuration(String name, long timeMs) {
-        Slog.d(mTag, name + " took to complete: " + timeMs + "ms");
+        Slog.v(mTag, name + " took to complete: " + timeMs + "ms");
     }
 
     /**
diff --git a/core/java/android/view/ContentRecordingSession.java b/core/java/android/view/ContentRecordingSession.java
index db4ec11..c66c70af 100644
--- a/core/java/android/view/ContentRecordingSession.java
+++ b/core/java/android/view/ContentRecordingSession.java
@@ -66,10 +66,11 @@
     private int mContentToRecord = RECORD_CONTENT_DISPLAY;
 
     /**
-     * The window token of the layer of the hierarchy to record.
-     * The display content if {@link #getContentToRecord()} is
-     * {@link RecordContent#RECORD_CONTENT_DISPLAY}, or task if {@link #getContentToRecord()} is
-     * {@link RecordContent#RECORD_CONTENT_TASK}.
+     * The token of the layer of the hierarchy to record.
+     * If {@link #getContentToRecord()} is @link RecordContent#RECORD_CONTENT_DISPLAY}, then
+     * represents the WindowToken corresponding to the DisplayContent to record.
+     * If {@link #getContentToRecord()} is {@link RecordContent#RECORD_CONTENT_TASK}, then
+     * represents the {@link android.window.WindowContainerToken} of the Task to record.
      */
     @VisibleForTesting
     @Nullable
@@ -192,10 +193,11 @@
     }
 
     /**
-     * The window token of the layer of the hierarchy to record.
-     * The display content if {@link #getContentToRecord()} is
-     * {@link RecordContent#RECORD_CONTENT_DISPLAY}, or task if {@link #getContentToRecord()} is
-     * {@link RecordContent#RECORD_CONTENT_TASK}.
+     * {The token of the layer of the hierarchy to record.
+     * If {@link #getContentToRecord()} is @link RecordContent#RECORD_CONTENT_DISPLAY}, then
+     * represents the WindowToken corresponding to the DisplayContent to record.
+     * If {@link #getContentToRecord()} is {@link RecordContent#RECORD_CONTENT_TASK}, then
+     * represents the {@link android.window.WindowContainerToken} of the Task to record.
      */
     @DataClass.Generated.Member
     public @VisibleForTesting @Nullable IBinder getTokenToRecord() {
@@ -231,10 +233,11 @@
     }
 
     /**
-     * The window token of the layer of the hierarchy to record.
-     * The display content if {@link #getContentToRecord()} is
-     * {@link RecordContent#RECORD_CONTENT_DISPLAY}, or task if {@link #getContentToRecord()} is
-     * {@link RecordContent#RECORD_CONTENT_TASK}.
+     * {The token of the layer of the hierarchy to record.
+     * If {@link #getContentToRecord()} is @link RecordContent#RECORD_CONTENT_DISPLAY}, then
+     * represents the WindowToken corresponding to the DisplayContent to record.
+     * If {@link #getContentToRecord()} is {@link RecordContent#RECORD_CONTENT_TASK}, then
+     * represents the {@link android.window.WindowContainerToken} of the Task to record.
      */
     @DataClass.Generated.Member
     public @NonNull ContentRecordingSession setTokenToRecord(@VisibleForTesting @NonNull IBinder value) {
@@ -390,10 +393,11 @@
         }
 
         /**
-         * The window token of the layer of the hierarchy to record.
-         * The display content if {@link #getContentToRecord()} is
-         * {@link RecordContent#RECORD_CONTENT_DISPLAY}, or task if {@link #getContentToRecord()} is
-         * {@link RecordContent#RECORD_CONTENT_TASK}.
+         * {The token of the layer of the hierarchy to record.
+         * If {@link #getContentToRecord()} is @link RecordContent#RECORD_CONTENT_DISPLAY}, then
+         * represents the WindowToken corresponding to the DisplayContent to record.
+         * If {@link #getContentToRecord()} is {@link RecordContent#RECORD_CONTENT_TASK}, then
+         * represents the {@link android.window.WindowContainerToken} of the Task to record.
          */
         @DataClass.Generated.Member
         public @NonNull Builder setTokenToRecord(@VisibleForTesting @NonNull IBinder value) {
@@ -433,7 +437,7 @@
     }
 
     @DataClass.Generated(
-            time = 1644843382972L,
+            time = 1645803878639L,
             codegenVersion = "1.0.23",
             sourceFile = "frameworks/base/core/java/android/view/ContentRecordingSession.java",
             inputSignatures = "public static final  int RECORD_CONTENT_DISPLAY\npublic static final  int RECORD_CONTENT_TASK\nprivate  int mDisplayId\nprivate @android.view.ContentRecordingSession.RecordContent int mContentToRecord\nprivate @com.android.internal.annotations.VisibleForTesting @android.annotation.Nullable android.os.IBinder mTokenToRecord\npublic static  android.view.ContentRecordingSession createDisplaySession(android.os.IBinder)\npublic static  android.view.ContentRecordingSession createTaskSession(android.os.IBinder)\npublic static  boolean isValid(android.view.ContentRecordingSession)\npublic static  boolean isSameDisplay(android.view.ContentRecordingSession,android.view.ContentRecordingSession)\nclass ContentRecordingSession extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=false, genToString=true, genSetters=true, genEqualsHashCode=true)")
diff --git a/core/java/com/android/internal/os/KernelAllocationStats.java b/core/java/com/android/internal/os/KernelAllocationStats.java
index 1c3f8b0..58d51e3 100644
--- a/core/java/com/android/internal/os/KernelAllocationStats.java
+++ b/core/java/com/android/internal/os/KernelAllocationStats.java
@@ -24,21 +24,29 @@
 
     /** Process dma-buf stats. */
     public static final class ProcessDmabuf {
+        public final int uid;
+        public final String processName;
+        public final int oomScore;
+
         /** Size of buffers retained by the process. */
         public final int retainedSizeKb;
         /** Number of buffers retained by the process. */
         public final int retainedBuffersCount;
-        /** Size of buffers mapped to the address space. */
-        public final int mappedSizeKb;
-        /** Count of buffers mapped to the address space. */
-        public final int mappedBuffersCount;
+        /** Size of buffers shared with Surface Flinger. */
+        public final int surfaceFlingerSizeKb;
+        /** Count of buffers shared with Surface Flinger. */
+        public final int surfaceFlingerCount;
 
-        ProcessDmabuf(int retainedSizeKb, int retainedBuffersCount,
-                int mappedSizeKb, int mappedBuffersCount) {
+        ProcessDmabuf(int uid, String processName, int oomScore, int retainedSizeKb,
+                int retainedBuffersCount, int surfaceFlingerSizeKb,
+                int surfaceFlingerCount) {
+            this.uid = uid;
+            this.processName = processName;
+            this.oomScore = oomScore;
             this.retainedSizeKb = retainedSizeKb;
             this.retainedBuffersCount = retainedBuffersCount;
-            this.mappedSizeKb = mappedSizeKb;
-            this.mappedBuffersCount = mappedBuffersCount;
+            this.surfaceFlingerSizeKb = surfaceFlingerSizeKb;
+            this.surfaceFlingerCount = surfaceFlingerCount;
         }
     }
 
@@ -47,7 +55,7 @@
      * stats could not be read.
      */
     @Nullable
-    public static native ProcessDmabuf getDmabufAllocations(int pid);
+    public static native ProcessDmabuf[] getDmabufAllocations();
 
     /** Pid to gpu memory size. */
     public static final class ProcessGpuMem {
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 3a76745..a1be884 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -272,6 +272,7 @@
                 "libinput",
                 "libcamera_client",
                 "libcamera_metadata",
+                "libprocinfo",
                 "libsqlite",
                 "libEGL",
                 "libGLESv1_CM",
diff --git a/core/jni/com_android_internal_os_KernelAllocationStats.cpp b/core/jni/com_android_internal_os_KernelAllocationStats.cpp
index e0a24430..5b10497 100644
--- a/core/jni/com_android_internal_os_KernelAllocationStats.cpp
+++ b/core/jni/com_android_internal_os_KernelAllocationStats.cpp
@@ -13,12 +13,19 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
 #include <dmabufinfo/dmabufinfo.h>
 #include <jni.h>
 #include <meminfo/sysmeminfo.h>
+#include <procinfo/process.h>
 
 #include "core_jni_helpers.h"
 
+using DmaBuffer = ::android::dmabufinfo::DmaBuffer;
+using android::base::ReadFileToString;
+using android::base::StringPrintf;
+
 namespace {
 static jclass gProcessDmabufClazz;
 static jmethodID gProcessDmabufCtor;
@@ -28,30 +35,127 @@
 
 namespace android {
 
-static jobject KernelAllocationStats_getDmabufAllocations(JNIEnv *env, jobject, jint pid) {
-    std::vector<dmabufinfo::DmaBuffer> buffers;
-    if (!dmabufinfo::ReadDmaBufMapRefs(pid, &buffers)) {
+struct PidDmaInfo {
+    uid_t uid;
+    std::string cmdline;
+    int oomScoreAdj;
+};
+
+static jobjectArray KernelAllocationStats_getDmabufAllocations(JNIEnv *env, jobject) {
+    std::vector<DmaBuffer> buffers;
+
+    if (!dmabufinfo::ReadDmaBufs(&buffers)) {
         return nullptr;
     }
-    jint mappedSize = 0;
-    jint mappedCount = buffers.size();
-    for (const auto &buffer : buffers) {
-        mappedSize += buffer.size();
-    }
-    mappedSize /= 1024;
 
-    jint retainedSize = -1;
-    jint retainedCount = -1;
-    if (dmabufinfo::ReadDmaBufFdRefs(pid, &buffers)) {
-        retainedCount = buffers.size();
-        retainedSize = 0;
-        for (const auto &buffer : buffers) {
-            retainedSize += buffer.size();
+    // Create a reverse map from pid to dmabufs
+    // Store dmabuf inodes & sizes for later processing.
+    std::unordered_map<pid_t, std::set<ino_t>> pidToInodes;
+    std::unordered_map<ino_t, long> inodeToSize;
+    for (auto &buf : buffers) {
+        for (auto pid : buf.pids()) {
+            pidToInodes[pid].insert(buf.inode());
         }
-        retainedSize /= 1024;
+        inodeToSize[buf.inode()] = buf.size();
     }
-    return env->NewObject(gProcessDmabufClazz, gProcessDmabufCtor, retainedSize, retainedCount,
-                          mappedSize, mappedCount);
+
+    pid_t surfaceFlingerPid = -1;
+    // The set of all inodes that are being retained by SurfaceFlinger. Buffers
+    // shared between another process and SF will appear in this set.
+    std::set<ino_t> surfaceFlingerBufferInodes;
+    // The set of all inodes that are being retained by any process other
+    // than SurfaceFlinger. Buffers shared between another process and SF will
+    // appear in this set.
+    std::set<ino_t> otherProcessBufferInodes;
+
+    // Find SurfaceFlinger pid & get cmdlines, oomScoreAdj, etc for each pid
+    // holding any DMA buffers.
+    std::unordered_map<pid_t, PidDmaInfo> pidDmaInfos;
+    for (const auto &pidToInodeEntry : pidToInodes) {
+        pid_t pid = pidToInodeEntry.first;
+
+        android::procinfo::ProcessInfo processInfo;
+        if (!android::procinfo::GetProcessInfo(pid, &processInfo)) {
+            continue;
+        }
+
+        std::string cmdline;
+        if (!ReadFileToString(StringPrintf("/proc/%d/cmdline", pid), &cmdline)) {
+            continue;
+        }
+
+        // cmdline strings are null-delimited, so we split on \0 here
+        if (cmdline.substr(0, cmdline.find('\0')) == "/system/bin/surfaceflinger") {
+            if (surfaceFlingerPid == -1) {
+                surfaceFlingerPid = pid;
+                surfaceFlingerBufferInodes = pidToInodes[pid];
+            } else {
+                LOG(ERROR) << "getDmabufAllocations found multiple SF processes; pid1: " << pid
+                           << ", pid2:" << surfaceFlingerPid;
+                surfaceFlingerPid = -2; // Used as a sentinel value below
+            }
+        } else {
+            otherProcessBufferInodes.insert(pidToInodes[pid].begin(), pidToInodes[pid].end());
+        }
+
+        std::string oomScoreAdjStr;
+        if (!ReadFileToString(StringPrintf("/proc/%d/oom_score_adj", pid), &oomScoreAdjStr)) {
+            continue;
+        }
+
+        pidDmaInfos[pid] = PidDmaInfo{.uid = processInfo.uid,
+                                      .cmdline = cmdline,
+                                      .oomScoreAdj = atoi(oomScoreAdjStr.c_str())};
+    }
+
+    if (surfaceFlingerPid < 0) {
+        LOG(ERROR) << "getDmabufAllocations could not identify SurfaceFlinger "
+                   << "process via /proc/pid/cmdline";
+    }
+
+    jobjectArray ret = env->NewObjectArray(pidDmaInfos.size(), gProcessDmabufClazz, NULL);
+    int retArrayIndex = 0;
+    for (const auto &pidDmaInfosEntry : pidDmaInfos) {
+        pid_t pid = pidDmaInfosEntry.first;
+
+        // For all processes apart from SurfaceFlinger, this set will store the
+        // dmabuf inodes that are shared with SF. For SF, it will store the inodes
+        // that are shared with any other process.
+        std::set<ino_t> sharedBuffers;
+        if (pid == surfaceFlingerPid) {
+            set_intersection(surfaceFlingerBufferInodes.begin(), surfaceFlingerBufferInodes.end(),
+                             otherProcessBufferInodes.begin(), otherProcessBufferInodes.end(),
+                             std::inserter(sharedBuffers, sharedBuffers.end()));
+        } else if (surfaceFlingerPid > 0) {
+            set_intersection(pidToInodes[pid].begin(), pidToInodes[pid].end(),
+                             surfaceFlingerBufferInodes.begin(), surfaceFlingerBufferInodes.end(),
+                             std::inserter(sharedBuffers, sharedBuffers.begin()));
+        } // If surfaceFlingerPid < 0; it means we failed to identify it, and
+        // the SF-related fields below should be left empty.
+
+        long totalSize = 0;
+        long sharedBuffersSize = 0;
+        for (const auto &inode : pidToInodes[pid]) {
+            totalSize += inodeToSize[inode];
+            if (sharedBuffers.count(inode)) {
+                sharedBuffersSize += inodeToSize[inode];
+            }
+        }
+
+        jobject obj = env->NewObject(gProcessDmabufClazz, gProcessDmabufCtor,
+                                     /* uid */ pidDmaInfos[pid].uid,
+                                     /* process name */
+                                     env->NewStringUTF(pidDmaInfos[pid].cmdline.c_str()),
+                                     /* oomscore */ pidDmaInfos[pid].oomScoreAdj,
+                                     /* retainedSize */ totalSize / 1024,
+                                     /* retainedCount */ pidToInodes[pid].size(),
+                                     /* sharedWithSurfaceFlinger size */ sharedBuffersSize / 1024,
+                                     /* sharedWithSurfaceFlinger count */ sharedBuffers.size());
+
+        env->SetObjectArrayElement(ret, retArrayIndex++, obj);
+    }
+
+    return ret;
 }
 
 static jobject KernelAllocationStats_getGpuAllocations(JNIEnv *env) {
@@ -74,7 +178,7 @@
 }
 
 static const JNINativeMethod methods[] = {
-        {"getDmabufAllocations", "(I)Lcom/android/internal/os/KernelAllocationStats$ProcessDmabuf;",
+        {"getDmabufAllocations", "()[Lcom/android/internal/os/KernelAllocationStats$ProcessDmabuf;",
          (void *)KernelAllocationStats_getDmabufAllocations},
         {"getGpuAllocations", "()[Lcom/android/internal/os/KernelAllocationStats$ProcessGpuMem;",
          (void *)KernelAllocationStats_getGpuAllocations},
@@ -86,7 +190,8 @@
     jclass clazz =
             FindClassOrDie(env, "com/android/internal/os/KernelAllocationStats$ProcessDmabuf");
     gProcessDmabufClazz = MakeGlobalRefOrDie(env, clazz);
-    gProcessDmabufCtor = GetMethodIDOrDie(env, gProcessDmabufClazz, "<init>", "(IIII)V");
+    gProcessDmabufCtor =
+            GetMethodIDOrDie(env, gProcessDmabufClazz, "<init>", "(ILjava/lang/String;IIIII)V");
 
     clazz = FindClassOrDie(env, "com/android/internal/os/KernelAllocationStats$ProcessGpuMem");
     gProcessGpuMemClazz = MakeGlobalRefOrDie(env, clazz);
@@ -94,4 +199,4 @@
     return res;
 }
 
-} // namespace android
+} // namespace android
\ No newline at end of file
diff --git a/core/tests/mockingcoretests/src/android/util/TimingsTraceLogTest.java b/core/tests/mockingcoretests/src/android/util/TimingsTraceLogTest.java
index 5dc44d2..8de9196 100644
--- a/core/tests/mockingcoretests/src/android/util/TimingsTraceLogTest.java
+++ b/core/tests/mockingcoretests/src/android/util/TimingsTraceLogTest.java
@@ -123,7 +123,7 @@
     public void testLogDuration() throws Exception {
         TimingsTraceLog log = new TimingsTraceLog(TAG, TRACE_TAG_APP, 10);
         log.logDuration("logro", 42);
-        verify((MockedVoidMethod) () -> Slog.d(eq(TAG), contains("logro took to complete: 42ms")));
+        verify((MockedVoidMethod) () -> Slog.v(eq(TAG), contains("logro took to complete: 42ms")));
     }
 
     @Test
@@ -134,7 +134,7 @@
 
         verify((MockedVoidMethod) () -> Trace.traceBegin(TRACE_TAG_APP, "test"));
         verify((MockedVoidMethod) () -> Trace.traceEnd(TRACE_TAG_APP));
-        verify((MockedVoidMethod) () -> Slog.d(eq(TAG), matches("test took to complete: \\dms")));
+        verify((MockedVoidMethod) () -> Slog.v(eq(TAG), matches("test took to complete: \\dms")));
     }
 
     @Test
@@ -149,8 +149,8 @@
         verify((MockedVoidMethod) () -> Trace.traceBegin(TRACE_TAG_APP, "L2"));
         verify((MockedVoidMethod) () -> Trace.traceEnd(TRACE_TAG_APP), times(2)); // L1 and L2
 
-        verify((MockedVoidMethod) () -> Slog.d(eq(TAG), matches("L2 took to complete: \\d+ms")));
-        verify((MockedVoidMethod) () -> Slog.d(eq(TAG), matches("L1 took to complete: \\d+ms")));
+        verify((MockedVoidMethod) () -> Slog.v(eq(TAG), matches("L2 took to complete: \\d+ms")));
+        verify((MockedVoidMethod) () -> Slog.v(eq(TAG), matches("L1 took to complete: \\d+ms")));
     }
 
     @Test
@@ -170,9 +170,9 @@
         verify((MockedVoidMethod) () -> Trace.traceBegin(TRACE_TAG_APP, "L3"));
         verify((MockedVoidMethod) () -> Trace.traceEnd(TRACE_TAG_APP), times(3));
 
-        verify((MockedVoidMethod) () -> Slog.d(eq(TAG), matches("L2 took to complete: \\d+ms")));
-        verify((MockedVoidMethod) () -> Slog.d(eq(TAG), matches("L1 took to complete: \\d+ms")));
-        verify((MockedVoidMethod) () -> Slog.d(eq(TAG), matches("L3 took to complete: \\d+ms")),
+        verify((MockedVoidMethod) () -> Slog.v(eq(TAG), matches("L2 took to complete: \\d+ms")));
+        verify((MockedVoidMethod) () -> Slog.v(eq(TAG), matches("L1 took to complete: \\d+ms")));
+        verify((MockedVoidMethod) () -> Slog.v(eq(TAG), matches("L3 took to complete: \\d+ms")),
                 never());
 
         verify((MockedVoidMethod) () -> Slog.w(TAG, "not tracing duration of 'L3' "
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index e898f57..4449c48 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -2257,6 +2257,12 @@
       "group": "WM_DEBUG_WINDOW_TRANSITIONS",
       "at": "com\/android\/server\/wm\/TransitionController.java"
     },
+    "264036181": {
+      "message": "Unable to retrieve task to start recording for display %d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONTENT_RECORDING",
+      "at": "com\/android\/server\/wm\/ContentRecorder.java"
+    },
     "269576220": {
       "message": "Resuming rotation after drag",
       "level": "DEBUG",
@@ -2761,6 +2767,12 @@
       "group": "WM_DEBUG_WALLPAPER",
       "at": "com\/android\/server\/wm\/WallpaperWindowToken.java"
     },
+    "736003885": {
+      "message": "Unable to retrieve the task token to start recording for display %d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONTENT_RECORDING",
+      "at": "com\/android\/server\/wm\/ContentRecorder.java"
+    },
     "736692676": {
       "message": "Config is relaunching %s",
       "level": "VERBOSE",
@@ -2791,6 +2803,12 @@
       "group": "WM_DEBUG_RECENTS_ANIMATIONS",
       "at": "com\/android\/server\/wm\/RecentsAnimation.java"
     },
+    "778774915": {
+      "message": "Unable to record task since feature is disabled %d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONTENT_RECORDING",
+      "at": "com\/android\/server\/wm\/ContentRecorder.java"
+    },
     "781471998": {
       "message": "moveWindowTokenToDisplay: Cannot move to the original display for token: %s",
       "level": "WARN",
diff --git a/libs/hwui/HardwareBitmapUploader.cpp b/libs/hwui/HardwareBitmapUploader.cpp
index dd272cd..c24cabb 100644
--- a/libs/hwui/HardwareBitmapUploader.cpp
+++ b/libs/hwui/HardwareBitmapUploader.cpp
@@ -310,6 +310,11 @@
     return has101012Support;
 }
 
+bool HardwareBitmapUploader::hasAlpha8Support() {
+    static bool hasAlpha8Support = checkSupport(AHARDWAREBUFFER_FORMAT_R8_UNORM);
+    return hasAlpha8Support;
+}
+
 static FormatInfo determineFormat(const SkBitmap& skBitmap, bool usingGL) {
     FormatInfo formatInfo;
     switch (skBitmap.info().colorType()) {
@@ -363,6 +368,13 @@
             }
             formatInfo.format = GL_RGBA;
             break;
+        case kAlpha_8_SkColorType:
+            formatInfo.isSupported = HardwareBitmapUploader::hasAlpha8Support();
+            formatInfo.bufferFormat = AHARDWAREBUFFER_FORMAT_R8_UNORM;
+            formatInfo.format = GL_R8;
+            formatInfo.type = GL_UNSIGNED_BYTE;
+            formatInfo.vkFormat = VK_FORMAT_R8_UNORM;
+            break;
         default:
             ALOGW("unable to create hardware bitmap of colortype: %d", skBitmap.info().colorType());
             formatInfo.valid = false;
diff --git a/libs/hwui/HardwareBitmapUploader.h b/libs/hwui/HardwareBitmapUploader.h
index 34f43cd..81057a2 100644
--- a/libs/hwui/HardwareBitmapUploader.h
+++ b/libs/hwui/HardwareBitmapUploader.h
@@ -30,11 +30,13 @@
 #ifdef __ANDROID__
     static bool hasFP16Support();
     static bool has1010102Support();
+    static bool hasAlpha8Support();
 #else
     static bool hasFP16Support() {
         return true;
     }
     static bool has1010102Support() { return true; }
+    static bool hasAlpha8Support() { return true; }
 #endif
 };
 
diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp
index 1a89cfd..67f4758 100644
--- a/libs/hwui/hwui/Bitmap.cpp
+++ b/libs/hwui/hwui/Bitmap.cpp
@@ -104,6 +104,10 @@
 
 sk_sp<Bitmap> Bitmap::allocateHardwareBitmap(const SkBitmap& bitmap) {
 #ifdef __ANDROID__ // Layoutlib does not support hardware acceleration
+    if (bitmap.colorType() == kAlpha_8_SkColorType &&
+        !uirenderer::HardwareBitmapUploader::hasAlpha8Support()) {
+        return nullptr;
+    }
     return uirenderer::HardwareBitmapUploader::allocateHardwareBitmap(bitmap);
 #else
     return Bitmap::allocateHeapBitmap(bitmap.info());
diff --git a/location/java/android/location/GnssExcessPathInfo.java b/location/java/android/location/GnssExcessPathInfo.java
new file mode 100644
index 0000000..72b2374
--- /dev/null
+++ b/location/java/android/location/GnssExcessPathInfo.java
@@ -0,0 +1,375 @@
+/*
+ * Copyright (C) 2022 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.location;
+
+import static android.hardware.gnss.measurement_corrections.SingleSatCorrection.ExcessPathInfo.EXCESS_PATH_INFO_HAS_ATTENUATION;
+import static android.hardware.gnss.measurement_corrections.SingleSatCorrection.ExcessPathInfo.EXCESS_PATH_INFO_HAS_EXCESS_PATH_LENGTH;
+import static android.hardware.gnss.measurement_corrections.SingleSatCorrection.ExcessPathInfo.EXCESS_PATH_INFO_HAS_EXCESS_PATH_LENGTH_UNC;
+import static android.hardware.gnss.measurement_corrections.SingleSatCorrection.ExcessPathInfo.EXCESS_PATH_INFO_HAS_REFLECTING_PLANE;
+
+import android.annotation.FloatRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.Objects;
+
+/**
+ * Contains the info of an excess path signal caused by reflection
+ *
+ * @hide
+ */
+@SystemApi
+public final class GnssExcessPathInfo implements Parcelable {
+
+    private static final int HAS_EXCESS_PATH_LENGTH_MASK = EXCESS_PATH_INFO_HAS_EXCESS_PATH_LENGTH;
+    private static final int HAS_EXCESS_PATH_LENGTH_UNC_MASK =
+            EXCESS_PATH_INFO_HAS_EXCESS_PATH_LENGTH_UNC;
+    private static final int HAS_REFLECTING_PLANE_MASK = EXCESS_PATH_INFO_HAS_REFLECTING_PLANE;
+    private static final int HAS_ATTENUATION_MASK = EXCESS_PATH_INFO_HAS_ATTENUATION;
+
+    /* A bitmask of fields present in this object (see HAS_* constants defined above) */
+    private final int mFlags;
+    private final float mExcessPathLengthMeters;
+    private final float mExcessPathLengthUncertaintyMeters;
+    @Nullable
+    private final GnssReflectingPlane mReflectingPlane;
+    private final float mAttenuationDb;
+
+    private GnssExcessPathInfo(
+            int flags,
+            float excessPathLengthMeters,
+            float excessPathLengthUncertaintyMeters,
+            @Nullable GnssReflectingPlane reflectingPlane,
+            float attenuationDb) {
+        mFlags = flags;
+        mExcessPathLengthMeters = excessPathLengthMeters;
+        mExcessPathLengthUncertaintyMeters = excessPathLengthUncertaintyMeters;
+        mReflectingPlane = reflectingPlane;
+        mAttenuationDb = attenuationDb;
+    }
+
+    /**
+     * Gets a bitmask of fields present in this object.
+     *
+     * <p>This API exists for JNI since it is easier for JNI to get one integer flag than looking up
+     * several has* methods.
+     * @hide
+     */
+    public int getFlags() {
+        return mFlags;
+    }
+
+    /** Returns {@code true} if {@link #getExcessPathLengthMeters()} is valid. */
+    public boolean hasExcessPathLength() {
+        return (mFlags & HAS_EXCESS_PATH_LENGTH_MASK) != 0;
+    }
+
+    /**
+     * Returns the excess path length to be subtracted from pseudorange before using it in
+     * calculating location.
+     *
+     * <p>{@link #hasExcessPathLength()} must be true when calling this method. Otherwise, an
+     * {@link UnsupportedOperationException} will be thrown.
+     */
+    @FloatRange(from = 0.0f)
+    public float getExcessPathLengthMeters() {
+        if (!hasExcessPathLength()) {
+            throw new UnsupportedOperationException(
+                    "getExcessPathLengthMeters() is not supported when hasExcessPathLength() is "
+                            + "false");
+        }
+        return mExcessPathLengthMeters;
+    }
+
+    /** Returns {@code true} if {@link #getExcessPathLengthUncertaintyMeters()} is valid. */
+    public boolean hasExcessPathLengthUncertainty() {
+        return (mFlags & HAS_EXCESS_PATH_LENGTH_UNC_MASK) != 0;
+    }
+
+    /**
+     * Returns the error estimate (1-sigma) for the excess path length estimate.
+     *
+     * <p>{@link #hasExcessPathLengthUncertainty()} must be true when calling this method.
+     * Otherwise, an {@link UnsupportedOperationException} will be thrown.
+     */
+    @FloatRange(from = 0.0f)
+    public float getExcessPathLengthUncertaintyMeters() {
+        if (!hasExcessPathLengthUncertainty()) {
+            throw new UnsupportedOperationException(
+                    "getExcessPathLengthUncertaintyMeters() is not supported when "
+                            + "hasExcessPathLengthUncertainty() is false");
+        }
+        return mExcessPathLengthUncertaintyMeters;
+    }
+
+    /**
+     * Returns {@code true} if {@link #getReflectingPlane()} is valid.
+     *
+     * <p>Returns false if the satellite signal goes through multiple reflections or if reflection
+     * plane serving is not supported.
+     */
+    public boolean hasReflectingPlane() {
+        return (mFlags & HAS_REFLECTING_PLANE_MASK) != 0;
+    }
+
+    /**
+     * Returns the reflecting plane characteristics at which the signal has bounced.
+     *
+     * <p>{@link #hasReflectingPlane()} must be true when calling this method. Otherwise, an
+     * {@link UnsupportedOperationException} will be thrown.
+     */
+    @NonNull
+    public GnssReflectingPlane getReflectingPlane() {
+        if (!hasReflectingPlane()) {
+            throw new UnsupportedOperationException(
+                    "getReflectingPlane() is not supported when hasReflectingPlane() is false");
+        }
+        return mReflectingPlane;
+    }
+
+    /** Returns {@code true} if {@link #getAttenuationDb()} is valid. */
+    public boolean hasAttenuation() {
+        return (mFlags & HAS_ATTENUATION_MASK) != 0;
+    }
+
+    /**
+     * Returns the expected reduction of signal strength of this path in non-negative dB.
+     *
+     * <p>{@link #hasAttenuation()} must be true when calling this method. Otherwise, an
+     * {@link UnsupportedOperationException} will be thrown.
+     */
+    @FloatRange(from = 0.0f)
+    public float getAttenuationDb() {
+        if (!hasAttenuation()) {
+            throw new UnsupportedOperationException(
+                    "getAttenuationDb() is not supported when hasAttenuation() is false");
+        }
+        return mAttenuationDb;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel parcel, int parcelFlags) {
+        parcel.writeInt(mFlags);
+        if (hasExcessPathLength()) {
+            parcel.writeFloat(mExcessPathLengthMeters);
+        }
+        if (hasExcessPathLengthUncertainty()) {
+            parcel.writeFloat(mExcessPathLengthUncertaintyMeters);
+        }
+        if (hasReflectingPlane()) {
+            mReflectingPlane.writeToParcel(parcel, parcelFlags);
+        }
+        if (hasAttenuation()) {
+            parcel.writeFloat(mAttenuationDb);
+        }
+    }
+
+    public static final @NonNull Creator<GnssExcessPathInfo> CREATOR =
+            new Creator<GnssExcessPathInfo>() {
+                @Override
+                @NonNull
+                public GnssExcessPathInfo createFromParcel(@NonNull Parcel parcel) {
+                    int flags = parcel.readInt();
+                    float excessPathLengthMeters =
+                            (flags & HAS_EXCESS_PATH_LENGTH_MASK) != 0
+                                    ? parcel.readFloat() : 0;
+                    float excessPathLengthUncertaintyMeters =
+                            (flags & HAS_EXCESS_PATH_LENGTH_UNC_MASK) != 0
+                                    ? parcel.readFloat() : 0;
+                    GnssReflectingPlane reflectingPlane =
+                            (flags & HAS_REFLECTING_PLANE_MASK) != 0
+                                    ? GnssReflectingPlane.CREATOR.createFromParcel(parcel) : null;
+                    float attenuationDb =
+                            (flags & HAS_ATTENUATION_MASK) != 0
+                                    ? parcel.readFloat() : 0;
+                    return new GnssExcessPathInfo(flags, excessPathLengthMeters,
+                            excessPathLengthUncertaintyMeters, reflectingPlane, attenuationDb);
+                }
+
+                @Override
+                public GnssExcessPathInfo[] newArray(int i) {
+                    return new GnssExcessPathInfo[i];
+                }
+            };
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj instanceof GnssExcessPathInfo) {
+            GnssExcessPathInfo that = (GnssExcessPathInfo) obj;
+            return this.mFlags == that.mFlags
+                    && (!hasExcessPathLength() || Float.compare(this.mExcessPathLengthMeters,
+                    that.mExcessPathLengthMeters) == 0)
+                    && (!hasExcessPathLengthUncertainty() || Float.compare(
+                    this.mExcessPathLengthUncertaintyMeters,
+                    that.mExcessPathLengthUncertaintyMeters) == 0)
+                    && (!hasReflectingPlane() || Objects.equals(this.mReflectingPlane,
+                    that.mReflectingPlane))
+                    && (!hasAttenuation() || Float.compare(this.mAttenuationDb,
+                    that.mAttenuationDb) == 0);
+        }
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mFlags,
+                mExcessPathLengthMeters,
+                mExcessPathLengthUncertaintyMeters,
+                mReflectingPlane,
+                mAttenuationDb);
+    }
+
+    @NonNull
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder("GnssExcessPathInfo[");
+        if (hasExcessPathLength()) {
+            builder.append(" ExcessPathLengthMeters=").append(mExcessPathLengthMeters);
+        }
+        if (hasExcessPathLengthUncertainty()) {
+            builder.append(" ExcessPathLengthUncertaintyMeters=").append(
+                    mExcessPathLengthUncertaintyMeters);
+        }
+        if (hasReflectingPlane()) {
+            builder.append(" ReflectingPlane=").append(mReflectingPlane);
+        }
+        if (hasAttenuation()) {
+            builder.append(" AttenuationDb=").append(mAttenuationDb);
+        }
+        builder.append(']');
+        return builder.toString();
+    }
+
+    /** Builder for {@link GnssExcessPathInfo}. */
+    public static final class Builder {
+        private int mFlags;
+        private float mExcessPathLengthMeters;
+        private float mExcessPathLengthUncertaintyMeters;
+        @Nullable
+        private GnssReflectingPlane mReflectingPlane;
+        private float mAttenuationDb;
+
+        /** Constructor for {@link Builder}. */
+        public Builder() {}
+
+        /**
+         * Sets the excess path length to be subtracted from pseudorange before using it in
+         * calculating location.
+         */
+        @NonNull
+        public Builder setExcessPathLengthMeters(
+                @FloatRange(from = 0.0f) float excessPathLengthMeters) {
+            Preconditions.checkArgumentInRange(excessPathLengthMeters, 0, Float.MAX_VALUE,
+                    "excessPathLengthMeters");
+            mExcessPathLengthMeters = excessPathLengthMeters;
+            mFlags |= HAS_EXCESS_PATH_LENGTH_MASK;
+            return this;
+        }
+
+        /**
+         * Clears the excess path length.
+         *
+         * <p>This is to negate {@link #setExcessPathLengthMeters} call.
+         */
+        @NonNull
+        public Builder clearExcessPathLengthMeters() {
+            mExcessPathLengthMeters = 0;
+            mFlags &= ~HAS_EXCESS_PATH_LENGTH_MASK;
+            return this;
+        }
+
+        /** Sets the error estimate (1-sigma) for the excess path length estimate */
+        @NonNull
+        public Builder setExcessPathLengthUncertaintyMeters(
+                @FloatRange(from = 0.0f) float excessPathLengthUncertaintyMeters) {
+            Preconditions.checkArgumentInRange(excessPathLengthUncertaintyMeters, 0,
+                    Float.MAX_VALUE, "excessPathLengthUncertaintyMeters");
+            mExcessPathLengthUncertaintyMeters = excessPathLengthUncertaintyMeters;
+            mFlags |= HAS_EXCESS_PATH_LENGTH_UNC_MASK;
+            return this;
+        }
+
+        /**
+         * Clears the error estimate (1-sigma) for the excess path length estimate
+         *
+         * <p>This is to negate {@link #setExcessPathLengthUncertaintyMeters} call.
+         */
+        @NonNull
+        public Builder clearExcessPathLengthUncertaintyMeters() {
+            mExcessPathLengthUncertaintyMeters = 0;
+            mFlags &= ~HAS_EXCESS_PATH_LENGTH_UNC_MASK;
+            return this;
+        }
+
+        /** Sets the reflecting plane information */
+        @NonNull
+        public Builder setReflectingPlane(@Nullable GnssReflectingPlane reflectingPlane) {
+            mReflectingPlane = reflectingPlane;
+            if (reflectingPlane != null) {
+                mFlags |= HAS_REFLECTING_PLANE_MASK;
+            } else {
+                mFlags &= ~HAS_REFLECTING_PLANE_MASK;
+            }
+            return this;
+        }
+
+        /**
+         * Sets the attenuation value in dB.
+         */
+        @NonNull
+        public Builder setAttenuationDb(@FloatRange(from = 0.0f) float attenuationDb) {
+            Preconditions.checkArgumentInRange(attenuationDb, 0, Float.MAX_VALUE,
+                    "attenuationDb");
+            mAttenuationDb = attenuationDb;
+            mFlags |= HAS_ATTENUATION_MASK;
+            return this;
+        }
+
+        /**
+         * Clears the attenuation value in dB.
+         *
+         * <p>This is to negate {@link #setAttenuationDb(float)} call.
+         */
+        @NonNull
+        public Builder clearAttenuationDb() {
+            mAttenuationDb = 0;
+            mFlags &= ~HAS_ATTENUATION_MASK;
+            return this;
+        }
+
+        /** Builds a {@link GnssExcessPathInfo} instance as specified by this builder. */
+        @NonNull
+        public GnssExcessPathInfo build() {
+            return new GnssExcessPathInfo(
+                    mFlags,
+                    mExcessPathLengthMeters,
+                    mExcessPathLengthUncertaintyMeters,
+                    mReflectingPlane,
+                    mAttenuationDb);
+        }
+    }
+}
diff --git a/location/java/android/location/GnssReflectingPlane.java b/location/java/android/location/GnssReflectingPlane.java
index 1acdd1e..115cbec 100644
--- a/location/java/android/location/GnssReflectingPlane.java
+++ b/location/java/android/location/GnssReflectingPlane.java
@@ -22,9 +22,14 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import java.util.Objects;
+
 /**
  * Holds the characteristics of the reflecting plane that a satellite signal has bounced from.
  *
+ * <p>Starting with Android T, this class supports {@link #equals} and {@link #hashCode}, which
+ * are not supported before that.
+ *
  * @hide
  */
 @SystemApi
@@ -107,18 +112,6 @@
                 }
             };
 
-    @NonNull
-    @Override
-    public String toString() {
-        final String format = "   %-29s = %s\n";
-        StringBuilder builder = new StringBuilder("ReflectingPlane:\n");
-        builder.append(String.format(format, "LatitudeDegrees = ", mLatitudeDegrees));
-        builder.append(String.format(format, "LongitudeDegrees = ", mLongitudeDegrees));
-        builder.append(String.format(format, "AltitudeMeters = ", mAltitudeMeters));
-        builder.append(String.format(format, "AzimuthDegrees = ", mAzimuthDegrees));
-        return builder.toString();
-    }
-
     @Override
     public void writeToParcel(@NonNull Parcel parcel, int flags) {
         parcel.writeDouble(mLatitudeDegrees);
@@ -127,6 +120,35 @@
         parcel.writeDouble(mAzimuthDegrees);
     }
 
+    @NonNull
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder("ReflectingPlane[");
+        builder.append(" LatitudeDegrees=").append(mLatitudeDegrees);
+        builder.append(" LongitudeDegrees=").append(mLongitudeDegrees);
+        builder.append(" AltitudeMeters=").append(mAltitudeMeters);
+        builder.append(" AzimuthDegrees=").append(mAzimuthDegrees);
+        builder.append(']');
+        return builder.toString();
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj instanceof GnssReflectingPlane) {
+            GnssReflectingPlane that = (GnssReflectingPlane) obj;
+            return Double.compare(this.mLatitudeDegrees, that.mLatitudeDegrees) == 0
+                    && Double.compare(this.mLongitudeDegrees, that.mLongitudeDegrees) == 0
+                    && Double.compare(this.mAltitudeMeters, that.mAltitudeMeters) == 0
+                    && Double.compare(this.mAzimuthDegrees, that.mAzimuthDegrees) == 0;
+        }
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mLatitudeDegrees, mLatitudeDegrees, mAltitudeMeters, mAzimuthDegrees);
+    }
+
     /** Builder for {@link GnssReflectingPlane} */
     public static final class Builder {
         /** For documentation, see corresponding fields in {@link GnssReflectingPlane}. */
diff --git a/location/java/android/location/GnssSingleSatCorrection.java b/location/java/android/location/GnssSingleSatCorrection.java
index 262630b..a7fce0a 100644
--- a/location/java/android/location/GnssSingleSatCorrection.java
+++ b/location/java/android/location/GnssSingleSatCorrection.java
@@ -16,6 +16,11 @@
 
 package android.location;
 
+import static android.hardware.gnss.measurement_corrections.SingleSatCorrection.SINGLE_SAT_CORRECTION_HAS_COMBINED_ATTENUATION;
+import static android.hardware.gnss.measurement_corrections.SingleSatCorrection.SINGLE_SAT_CORRECTION_HAS_COMBINED_EXCESS_PATH_LENGTH;
+import static android.hardware.gnss.measurement_corrections.SingleSatCorrection.SINGLE_SAT_CORRECTION_HAS_COMBINED_EXCESS_PATH_LENGTH_UNC;
+import static android.hardware.gnss.measurement_corrections.SingleSatCorrection.SINGLE_SAT_CORRECTION_HAS_SAT_IS_LOS_PROBABILITY;
+
 import android.annotation.FloatRange;
 import android.annotation.IntRange;
 import android.annotation.NonNull;
@@ -26,6 +31,8 @@
 
 import com.android.internal.util.Preconditions;
 
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Objects;
 
 /**
@@ -36,106 +43,47 @@
 @SystemApi
 public final class GnssSingleSatCorrection implements Parcelable {
 
-    /**
-     * Bit mask for {@link #mSingleSatCorrectionFlags} indicating the presence of {@link
-     * #mProbSatIsLos}.
-     *
-     * @hide
-     */
-    public static final int HAS_PROB_SAT_IS_LOS_MASK = 1 << 0;
+    private static final int HAS_PROB_SAT_IS_LOS_MASK =
+            SINGLE_SAT_CORRECTION_HAS_SAT_IS_LOS_PROBABILITY;
+    private static final int HAS_COMBINED_EXCESS_PATH_LENGTH_MASK =
+            SINGLE_SAT_CORRECTION_HAS_COMBINED_EXCESS_PATH_LENGTH;
+    private static final int HAS_COMBINED_EXCESS_PATH_LENGTH_UNC_MASK =
+            SINGLE_SAT_CORRECTION_HAS_COMBINED_EXCESS_PATH_LENGTH_UNC;
+    private static final int HAS_COMBINED_ATTENUATION_MASK =
+            SINGLE_SAT_CORRECTION_HAS_COMBINED_ATTENUATION;
 
-    /**
-     * Bit mask for {@link #mSingleSatCorrectionFlags} indicating the presence of {@link
-     * #mExcessPathLengthMeters}.
-     *
-     * @hide
-     */
-    public static final int HAS_EXCESS_PATH_LENGTH_MASK = 1 << 1;
-
-    /**
-     * Bit mask for {@link #mSingleSatCorrectionFlags} indicating the presence of {@link
-     * #mExcessPathLengthUncertaintyMeters}.
-     *
-     * @hide
-     */
-    public static final int HAS_EXCESS_PATH_LENGTH_UNC_MASK = 1 << 2;
-
-    /**
-     * Bit mask for {@link #mSingleSatCorrectionFlags} indicating the presence of {@link
-     * #mReflectingPlane}.
-     *
-     * @hide
-     */
-    public static final int HAS_REFLECTING_PLANE_MASK = 1 << 3;
-
-    /** A bitmask of fields present in this object (see HAS_* constants defined above) */
+    /* A bitmask of fields present in this object (see HAS_* constants defined above). */
     private final int mSingleSatCorrectionFlags;
 
-    /** Defines the constellation of the given satellite as defined in {@link GnssStatus}. */
-    @GnssStatus.ConstellationType
     private final int mConstellationType;
-
-    /**
-     * Satellite vehicle ID number
-     *
-     * <p>Interpretation depends on {@link GnssStatus#getSvid(int)}.
-     */
-    @IntRange(from = 0)
     private final int mSatId;
-
-    /**
-     * Carrier frequency of the signal to be corrected, for example it can be the GPS center
-     * frequency for L1 = 1,575,420,000 Hz, varying GLO channels, etc.
-     *
-     * <p>For an L1, L5 receiver tracking a satellite on L1 and L5 at the same time, two correction
-     * objects will be reported for this same satellite, in one of the correction objects, all the
-     * values related to L1 will be filled, and in the other all of the values related to L5 will be
-     * filled.
-     */
-    @FloatRange(from = 0.0f,  fromInclusive = false)
     private final float mCarrierFrequencyHz;
-
-    /**
-     * The probability that the satellite is estimated to be in Line-of-Sight condition at the given
-     * location.
-     */
-    @FloatRange(from = 0.0f, to = 1.0f)
     private final float mProbSatIsLos;
+    private final float mCombinedExcessPathLengthMeters;
+    private final float mCombinedExcessPathLengthUncertaintyMeters;
+    private final float mCombinedAttenuationDb;
 
-    /**
-     * Excess path length to be subtracted from pseudorange before using it in calculating location.
-     */
-    @FloatRange(from = 0.0f)
-    private final float mExcessPathLengthMeters;
-
-    /** Error estimate (1-sigma) for the Excess path length estimate */
-    @FloatRange(from = 0.0f)
-    private final float mExcessPathLengthUncertaintyMeters;
-
-    /**
-     * Defines the reflecting plane location and azimuth information
-     *
-     * <p>The flag HAS_REFLECTING_PLANE will be used to set this value to invalid if the satellite
-     * signal goes through multiple reflections or if reflection plane serving is not supported.
-     */
-    @Nullable
-    private final GnssReflectingPlane mReflectingPlane;
+    @NonNull
+    private final List<GnssExcessPathInfo> mGnssExcessPathInfoList;
 
     private GnssSingleSatCorrection(int singleSatCorrectionFlags, int constellationType, int satId,
             float carrierFrequencyHz, float probSatIsLos, float excessPathLengthMeters,
-            float excessPathLengthUncertaintyMeters, GnssReflectingPlane reflectingPlane) {
+            float excessPathLengthUncertaintyMeters,
+            float combinedAttenuationDb,
+            @NonNull List<GnssExcessPathInfo> gnssExcessPathInfoList) {
         mSingleSatCorrectionFlags = singleSatCorrectionFlags;
         mConstellationType = constellationType;
         mSatId = satId;
         mCarrierFrequencyHz = carrierFrequencyHz;
         mProbSatIsLos = probSatIsLos;
-        mExcessPathLengthMeters = excessPathLengthMeters;
-        mExcessPathLengthUncertaintyMeters = excessPathLengthUncertaintyMeters;
-        mReflectingPlane = reflectingPlane;
+        mCombinedExcessPathLengthMeters = excessPathLengthMeters;
+        mCombinedExcessPathLengthUncertaintyMeters = excessPathLengthUncertaintyMeters;
+        mCombinedAttenuationDb = combinedAttenuationDb;
+        mGnssExcessPathInfoList = gnssExcessPathInfoList;
     }
 
     /**
-     * Gets a bitmask of fields present in this object
+     * Gets a bitmask of fields present in this object.
      *
      * @hide
      */
@@ -193,29 +141,46 @@
     }
 
     /**
-     * Returns the Excess path length to be subtracted from pseudorange before using it in
+     * Returns the combined excess path length to be subtracted from pseudorange before using it in
      * calculating location.
      */
     @FloatRange(from = 0.0f)
     public float getExcessPathLengthMeters() {
-        return mExcessPathLengthMeters;
+        return mCombinedExcessPathLengthMeters;
     }
 
-    /** Returns the error estimate (1-sigma) for the Excess path length estimate */
+    /** Returns the error estimate (1-sigma) for the combined excess path length estimate. */
     @FloatRange(from = 0.0f)
     public float getExcessPathLengthUncertaintyMeters() {
-        return mExcessPathLengthUncertaintyMeters;
+        return mCombinedExcessPathLengthUncertaintyMeters;
     }
 
     /**
-     * Returns the reflecting plane characteristics at which the signal has bounced
+     * Returns the combined expected reduction of signal strength for this satellite in
+     * non-negative dB.
+     */
+    @FloatRange(from = 0.0f)
+    public float getCombinedAttenuationDb() {
+        return mCombinedAttenuationDb;
+    }
+
+    /**
+     * Returns the reflecting plane characteristics at which the signal has bounced.
      *
-     * <p>The flag HAS_REFLECTING_PLANE will be used to set this value to invalid if the satellite
-     * signal goes through multiple reflections or if reflection plane serving is not supported
+     * @deprecated Combined excess path does not have a reflecting plane.
      */
     @Nullable
+    @Deprecated
     public GnssReflectingPlane getReflectingPlane() {
-        return mReflectingPlane;
+        return null;
+    }
+
+    /**
+     * Returns the list of {@link GnssExcessPathInfo} associated with this satellite signal.
+     */
+    @NonNull
+    public List<GnssExcessPathInfo> getGnssExcessPathInfoList() {
+        return mGnssExcessPathInfoList;
     }
 
     /** Returns {@code true} if {@link #getProbabilityLineOfSight()} is valid. */
@@ -225,17 +190,27 @@
 
     /** Returns {@code true} if {@link #getExcessPathLengthMeters()} is valid. */
     public boolean hasExcessPathLength() {
-        return (mSingleSatCorrectionFlags & HAS_EXCESS_PATH_LENGTH_MASK) != 0;
+        return (mSingleSatCorrectionFlags & HAS_COMBINED_EXCESS_PATH_LENGTH_MASK) != 0;
     }
 
     /** Returns {@code true} if {@link #getExcessPathLengthUncertaintyMeters()} is valid. */
     public boolean hasExcessPathLengthUncertainty() {
-        return (mSingleSatCorrectionFlags & HAS_EXCESS_PATH_LENGTH_UNC_MASK) != 0;
+        return (mSingleSatCorrectionFlags & HAS_COMBINED_EXCESS_PATH_LENGTH_UNC_MASK) != 0;
     }
 
-    /** Returns {@code true} if {@link #getReflectingPlane()} is valid. */
+    /**
+     * Returns {@code true} if {@link #getReflectingPlane()} is valid.
+     *
+     * @deprecated Combined excess path does not have a reflecting plane.
+     */
+    @Deprecated
     public boolean hasReflectingPlane() {
-        return (mSingleSatCorrectionFlags & HAS_REFLECTING_PLANE_MASK) != 0;
+        return false;
+    }
+
+    /** Returns {@code true} if {@link #getCombinedAttenuationDb()} is valid. */
+    public boolean hasCombinedAttenuation() {
+        return (mSingleSatCorrectionFlags & HAS_COMBINED_ATTENUATION_MASK) != 0;
     }
 
     @Override
@@ -253,14 +228,15 @@
             parcel.writeFloat(mProbSatIsLos);
         }
         if (hasExcessPathLength()) {
-            parcel.writeFloat(mExcessPathLengthMeters);
+            parcel.writeFloat(mCombinedExcessPathLengthMeters);
         }
         if (hasExcessPathLengthUncertainty()) {
-            parcel.writeFloat(mExcessPathLengthUncertaintyMeters);
+            parcel.writeFloat(mCombinedExcessPathLengthUncertaintyMeters);
         }
-        if (hasReflectingPlane()) {
-            mReflectingPlane.writeToParcel(parcel, flags);
+        if (hasCombinedAttenuation()) {
+            parcel.writeFloat(mCombinedAttenuationDb);
         }
+        parcel.writeTypedList(mGnssExcessPathInfoList);
     }
 
     public static final Creator<GnssSingleSatCorrection> CREATOR =
@@ -274,18 +250,21 @@
                     float carrierFrequencyHz = parcel.readFloat();
                     float probSatIsLos = (singleSatCorrectionFlags & HAS_PROB_SAT_IS_LOS_MASK) != 0
                             ? parcel.readFloat() : 0;
-                    float excessPathLengthMeters =
-                            (singleSatCorrectionFlags & HAS_EXCESS_PATH_LENGTH_MASK) != 0
+                    float combinedExcessPathLengthMeters =
+                            (singleSatCorrectionFlags & HAS_COMBINED_EXCESS_PATH_LENGTH_MASK) != 0
                                     ? parcel.readFloat() : 0;
-                    float excessPathLengthUncertaintyMeters =
-                            (singleSatCorrectionFlags & HAS_EXCESS_PATH_LENGTH_UNC_MASK) != 0
+                    float combinedExcessPathLengthUncertaintyMeters =
+                            (singleSatCorrectionFlags & HAS_COMBINED_EXCESS_PATH_LENGTH_UNC_MASK)
+                                    != 0 ? parcel.readFloat() : 0;
+                    float combinedAttenuationDb =
+                            (singleSatCorrectionFlags & HAS_COMBINED_ATTENUATION_MASK) != 0
                                     ? parcel.readFloat() : 0;
-                    GnssReflectingPlane reflectingPlane =
-                            (singleSatCorrectionFlags & HAS_REFLECTING_PLANE_MASK) != 0
-                                    ? GnssReflectingPlane.CREATOR.createFromParcel(parcel) : null;
+                    List<GnssExcessPathInfo> gnssExcessPathInfoList = parcel.createTypedArrayList(
+                            GnssExcessPathInfo.CREATOR);
                     return new GnssSingleSatCorrection(singleSatCorrectionFlags, constellationType,
-                            satId, carrierFrequencyHz, probSatIsLos, excessPathLengthMeters,
-                            excessPathLengthUncertaintyMeters, reflectingPlane);
+                            satId, carrierFrequencyHz, probSatIsLos, combinedExcessPathLengthMeters,
+                            combinedExcessPathLengthUncertaintyMeters, combinedAttenuationDb,
+                            gnssExcessPathInfoList);
                 }
 
                 @Override
@@ -296,56 +275,24 @@
 
     @Override
     public boolean equals(Object obj) {
-        if (this == obj) {
-            return true;
+        if (obj instanceof GnssSingleSatCorrection) {
+            GnssSingleSatCorrection that = (GnssSingleSatCorrection) obj;
+            return this.mSingleSatCorrectionFlags == that.mSingleSatCorrectionFlags
+                    && this.mConstellationType == that.mConstellationType
+                    && this.mSatId == that.mSatId
+                    && Float.compare(mCarrierFrequencyHz, that.mCarrierFrequencyHz) == 0
+                    && (!hasValidSatelliteLineOfSight() || Float.compare(mProbSatIsLos,
+                    that.mProbSatIsLos) == 0)
+                    && (!hasExcessPathLength() || Float.compare(mCombinedExcessPathLengthMeters,
+                    that.mCombinedExcessPathLengthMeters) == 0)
+                    && (!hasExcessPathLengthUncertainty() || Float.compare(
+                    mCombinedExcessPathLengthUncertaintyMeters,
+                    that.mCombinedExcessPathLengthUncertaintyMeters) == 0)
+                    && (!hasCombinedAttenuation() || Float.compare(mCombinedAttenuationDb,
+                    that.mCombinedAttenuationDb) == 0)
+                    && mGnssExcessPathInfoList.equals(that.mGnssExcessPathInfoList);
         }
-        if (!(obj instanceof GnssSingleSatCorrection)) {
-            return false;
-        }
-
-        GnssSingleSatCorrection other = (GnssSingleSatCorrection) obj;
-        if (mConstellationType != other.mConstellationType) {
-            return false;
-        }
-        if (mSatId != other.mSatId) {
-            return false;
-        }
-        if (Float.compare(mCarrierFrequencyHz, other.mCarrierFrequencyHz) != 0) {
-            return false;
-        }
-
-        if (hasValidSatelliteLineOfSight() != other.hasValidSatelliteLineOfSight()) {
-            return false;
-        }
-        if (hasValidSatelliteLineOfSight()
-                && Float.compare(mProbSatIsLos, other.mProbSatIsLos) != 0) {
-            return false;
-        }
-
-        if (hasExcessPathLength() != other.hasExcessPathLength()) {
-            return false;
-        }
-        if (hasExcessPathLength()
-                && Float.compare(mExcessPathLengthMeters, other.mExcessPathLengthMeters) != 0) {
-            return false;
-        }
-
-        if (hasExcessPathLengthUncertainty() != other.hasExcessPathLengthUncertainty()) {
-            return false;
-        }
-        if (hasExcessPathLengthUncertainty() && Float.compare(mExcessPathLengthUncertaintyMeters,
-                other.mExcessPathLengthUncertaintyMeters) != 0) {
-            return false;
-        }
-
-        if (hasReflectingPlane() != other.hasReflectingPlane()) {
-            return false;
-        }
-        if (hasReflectingPlane()
-                && !mReflectingPlane.equals(other.mReflectingPlane)) {
-            return false;
-        }
-        return true;
+        return false;
     }
 
     @Override
@@ -355,9 +302,10 @@
                 mSatId,
                 mCarrierFrequencyHz,
                 mProbSatIsLos,
-                mExcessPathLengthMeters,
-                mExcessPathLengthUncertaintyMeters,
-                mReflectingPlane);
+                mCombinedExcessPathLengthMeters,
+                mCombinedExcessPathLengthUncertaintyMeters,
+                mCombinedAttenuationDb,
+                mGnssExcessPathInfoList);
     }
 
     @NonNull
@@ -371,14 +319,19 @@
             builder.append(" ProbSatIsLos=").append(mProbSatIsLos);
         }
         if (hasExcessPathLength()) {
-            builder.append(" ExcessPathLengthMeters=").append(mExcessPathLengthMeters);
+            builder.append(" CombinedExcessPathLengthMeters=").append(
+                    mCombinedExcessPathLengthMeters);
         }
         if (hasExcessPathLengthUncertainty()) {
-            builder.append(" ExcessPathLengthUncertaintyMeters=").append(
-                    mExcessPathLengthUncertaintyMeters);
+            builder.append(" CombinedExcessPathLengthUncertaintyMeters=").append(
+                    mCombinedExcessPathLengthUncertaintyMeters);
         }
-        if (hasReflectingPlane()) {
-            builder.append(" ReflectingPlane=").append(mReflectingPlane);
+        if (hasCombinedAttenuation()) {
+            builder.append(" CombinedAttenuationDb=").append(
+                    mCombinedAttenuationDb);
+        }
+        if (!mGnssExcessPathInfoList.isEmpty()) {
+            builder.append(' ').append(mGnssExcessPathInfoList.toString());
         }
         builder.append(']');
         return builder.toString();
@@ -386,21 +339,16 @@
 
     /** Builder for {@link GnssSingleSatCorrection} */
     public static final class Builder {
-
-        /**
-         * For documentation of below fields, see corresponding fields in {@link
-         * GnssSingleSatCorrection}.
-         */
         private int mSingleSatCorrectionFlags;
-
         private int mConstellationType;
         private int mSatId;
         private float mCarrierFrequencyHz;
         private float mProbSatIsLos;
-        private float mExcessPathLengthMeters;
-        private float mExcessPathLengthUncertaintyMeters;
-        @Nullable
-        private GnssReflectingPlane mReflectingPlane;
+        private float mCombinedExcessPathLengthMeters;
+        private float mCombinedExcessPathLengthUncertaintyMeters;
+        private float mCombinedAttenuationDb;
+        @NonNull
+        private List<GnssExcessPathInfo> mGnssExcessInfoList = new ArrayList<>();
 
         /** Sets the constellation type. */
         @NonNull public Builder setConstellationType(
@@ -409,18 +357,18 @@
             return this;
         }
 
-        /** Sets the Satellite ID defined in the ICD of the given constellation. */
+        /** Sets the satellite ID defined in the ICD of the given constellation. */
         @NonNull public Builder setSatelliteId(@IntRange(from = 0) int satId) {
             Preconditions.checkArgumentNonnegative(satId, "satId should be non-negative.");
             mSatId = satId;
             return this;
         }
 
-        /** Sets the Carrier frequency in Hz. */
+        /** Sets the carrier frequency in Hz. */
         @NonNull public Builder setCarrierFrequencyHz(
                 @FloatRange(from = 0.0f,  fromInclusive = false) float carrierFrequencyHz) {
-            Preconditions.checkArgument(
-                    carrierFrequencyHz >= 0, "carrierFrequencyHz should be non-negative.");
+            Preconditions.checkArgumentInRange(
+                    carrierFrequencyHz, 0, Float.MAX_VALUE, "carrierFrequencyHz");
             mCarrierFrequencyHz = carrierFrequencyHz;
             return this;
         }
@@ -450,58 +398,90 @@
         }
 
         /**
-         * Sets the Excess path length to be subtracted from pseudorange before using it in
+         * Sets the combined excess path length to be subtracted from pseudorange before using it in
          * calculating location.
          */
-        @NonNull public Builder setExcessPathLengthMeters(
-                @FloatRange(from = 0.0f) float excessPathLengthMeters) {
-            Preconditions.checkArgument(excessPathLengthMeters >= 0,
-                    "excessPathLengthMeters should be non-negative.");
-            mExcessPathLengthMeters = excessPathLengthMeters;
-            mSingleSatCorrectionFlags |= HAS_EXCESS_PATH_LENGTH_MASK;
+        @NonNull
+        public Builder setExcessPathLengthMeters(
+                @FloatRange(from = 0.0f) float combinedExcessPathLengthMeters) {
+            Preconditions.checkArgumentInRange(combinedExcessPathLengthMeters, 0, Float.MAX_VALUE,
+                    "excessPathLengthMeters");
+            mCombinedExcessPathLengthMeters = combinedExcessPathLengthMeters;
+            mSingleSatCorrectionFlags |= HAS_COMBINED_EXCESS_PATH_LENGTH_MASK;
             return this;
         }
 
         /**
-         * Clears the Excess path length.
+         * Clears the combined excess path length.
          *
          * <p>This is to negate {@link #setExcessPathLengthMeters} call.
          */
         @NonNull public Builder clearExcessPathLengthMeters() {
-            mExcessPathLengthMeters = 0;
-            mSingleSatCorrectionFlags &= ~HAS_EXCESS_PATH_LENGTH_MASK;
+            mCombinedExcessPathLengthMeters = 0;
+            mSingleSatCorrectionFlags &= ~HAS_COMBINED_EXCESS_PATH_LENGTH_MASK;
             return this;
         }
 
-        /** Sets the error estimate (1-sigma) for the Excess path length estimate */
+        /** Sets the error estimate (1-sigma) for the combined excess path length estimate. */
         @NonNull public Builder setExcessPathLengthUncertaintyMeters(
-                @FloatRange(from = 0.0f) float excessPathLengthUncertaintyMeters) {
-            Preconditions.checkArgument(excessPathLengthUncertaintyMeters >= 0,
-                    "excessPathLengthUncertaintyMeters should be non-negative.");
-            mExcessPathLengthUncertaintyMeters = excessPathLengthUncertaintyMeters;
-            mSingleSatCorrectionFlags |= HAS_EXCESS_PATH_LENGTH_UNC_MASK;
+                @FloatRange(from = 0.0f) float combinedExcessPathLengthUncertaintyMeters) {
+            Preconditions.checkArgumentInRange(combinedExcessPathLengthUncertaintyMeters, 0,
+                    Float.MAX_VALUE, "excessPathLengthUncertaintyMeters");
+            mCombinedExcessPathLengthUncertaintyMeters = combinedExcessPathLengthUncertaintyMeters;
+            mSingleSatCorrectionFlags |= HAS_COMBINED_EXCESS_PATH_LENGTH_UNC_MASK;
             return this;
         }
 
         /**
-         * Clears the error estimate (1-sigma) for the Excess path length estimate
+         * Clears the error estimate (1-sigma) for the combined excess path length estimate.
          *
          * <p>This is to negate {@link #setExcessPathLengthUncertaintyMeters} call.
          */
         @NonNull public Builder clearExcessPathLengthUncertaintyMeters() {
-            mExcessPathLengthUncertaintyMeters = 0;
-            mSingleSatCorrectionFlags &= ~HAS_EXCESS_PATH_LENGTH_UNC_MASK;
+            mCombinedExcessPathLengthUncertaintyMeters = 0;
+            mSingleSatCorrectionFlags &= ~HAS_COMBINED_EXCESS_PATH_LENGTH_UNC_MASK;
             return this;
         }
 
-        /** Sets the reflecting plane information */
+        /**
+         * Sets the combined attenuation in Db.
+         */
+        @NonNull public Builder setCombinedAttenuationDb(
+                @FloatRange(from = 0.0f) float combinedAttenuationDb) {
+            Preconditions.checkArgumentInRange(combinedAttenuationDb, 0, Float.MAX_VALUE,
+                    "combinedAttenuationDb");
+            mCombinedAttenuationDb = combinedAttenuationDb;
+            mSingleSatCorrectionFlags |= HAS_COMBINED_ATTENUATION_MASK;
+            return this;
+        }
+
+        /**
+         * Clears the combined attenuation.
+         *
+         * <p>This is to negate {@link #setCombinedAttenuationDb} call.
+         */
+        @NonNull public Builder clearCombinedAttenuationDb() {
+            mCombinedAttenuationDb = 0;
+            mSingleSatCorrectionFlags &= ~HAS_COMBINED_ATTENUATION_MASK;
+            return this;
+        }
+
+        /**
+         * Sets the reflecting plane information.
+         *
+         * @deprecated Combined excess path does not have a reflecting plane.
+         */
+        @Deprecated
         @NonNull public Builder setReflectingPlane(@Nullable GnssReflectingPlane reflectingPlane) {
-            mReflectingPlane = reflectingPlane;
-            if (reflectingPlane != null) {
-                mSingleSatCorrectionFlags |= HAS_REFLECTING_PLANE_MASK;
-            } else {
-                mSingleSatCorrectionFlags &= ~HAS_REFLECTING_PLANE_MASK;
-            }
+            return this;
+        }
+
+        /**
+         * Sets the collection of {@link GnssExcessPathInfo}.
+         */
+        @NonNull
+        public Builder setGnssExcessPathInfoList(@NonNull List<GnssExcessPathInfo> infoList) {
+            mGnssExcessInfoList = new ArrayList<>(infoList);
             return this;
         }
 
@@ -512,9 +492,10 @@
                     mSatId,
                     mCarrierFrequencyHz,
                     mProbSatIsLos,
-                    mExcessPathLengthMeters,
-                    mExcessPathLengthUncertaintyMeters,
-                    mReflectingPlane);
+                    mCombinedExcessPathLengthMeters,
+                    mCombinedExcessPathLengthUncertaintyMeters,
+                    mCombinedAttenuationDb,
+                    mGnssExcessInfoList);
         }
     }
 }
diff --git a/media/java/android/media/projection/IMediaProjection.aidl b/media/java/android/media/projection/IMediaProjection.aidl
index 19fc052..b136d5b 100644
--- a/media/java/android/media/projection/IMediaProjection.aidl
+++ b/media/java/android/media/projection/IMediaProjection.aidl
@@ -17,6 +17,7 @@
 package android.media.projection;
 
 import android.media.projection.IMediaProjectionCallback;
+import android.window.WindowContainerToken;
 
 /** {@hide} */
 interface IMediaProjection {
@@ -28,4 +29,16 @@
     int applyVirtualDisplayFlags(int flags);
     void registerCallback(IMediaProjectionCallback callback);
     void unregisterCallback(IMediaProjectionCallback callback);
+
+    /**
+     * Returns the {@link android.window.WindowContainerToken} identifying the task to record, or
+     * {@code null} if there is none.
+     */
+    WindowContainerToken getTaskRecordingWindowContainerToken();
+
+    /**
+     * Updates the {@link android.window.WindowContainerToken} identifying the task to record, or
+     * {@code null} if there is none.
+     */
+    void setTaskRecordingWindowContainerToken(in WindowContainerToken token);
 }
diff --git a/media/java/android/media/projection/MediaProjection.java b/media/java/android/media/projection/MediaProjection.java
index 4dde5e8..b5f9593 100644
--- a/media/java/android/media/projection/MediaProjection.java
+++ b/media/java/android/media/projection/MediaProjection.java
@@ -25,13 +25,14 @@
 import android.hardware.display.VirtualDisplay;
 import android.hardware.display.VirtualDisplayConfig;
 import android.os.Handler;
-import android.os.IBinder;
 import android.os.RemoteException;
 import android.util.ArrayMap;
 import android.util.Log;
 import android.view.ContentRecordingSession;
+import android.view.IWindowManager;
 import android.view.Surface;
 import android.view.WindowManagerGlobal;
+import android.window.WindowContainerToken;
 
 import java.util.Map;
 
@@ -171,16 +172,34 @@
             @NonNull VirtualDisplayConfig.Builder virtualDisplayConfig,
             @Nullable VirtualDisplay.Callback callback, @Nullable Handler handler) {
         try {
-            final Context windowContext = mContext.createWindowContext(
-                    mContext.getDisplayNoVerify(),
-                    TYPE_APPLICATION, null /* options */);
-            final IBinder windowContextToken = windowContext.getWindowContextToken();
+            final IWindowManager wmService = WindowManagerGlobal.getWindowManagerService();
+            final WindowContainerToken taskWindowContainerToken =
+                    mImpl.getTaskRecordingWindowContainerToken();
+            Context windowContext = null;
+            ContentRecordingSession session;
+            if (taskWindowContainerToken == null) {
+                windowContext = mContext.createWindowContext(mContext.getDisplayNoVerify(),
+                        TYPE_APPLICATION, null /* options */);
+                session = ContentRecordingSession.createDisplaySession(
+                        windowContext.getWindowContextToken());
+            } else {
+                session = ContentRecordingSession.createTaskSession(
+                        taskWindowContainerToken.asBinder());
+            }
             virtualDisplayConfig.setWindowManagerMirroring(true);
             final DisplayManager dm = mContext.getSystemService(DisplayManager.class);
             final VirtualDisplay virtualDisplay = dm.createVirtualDisplay(this,
-                    virtualDisplayConfig.build(),
-                    callback, handler, windowContext);
-            setSession(windowContextToken, virtualDisplay);
+                    virtualDisplayConfig.build(), callback, handler, windowContext);
+            if (virtualDisplay == null) {
+                // Since WM handling a new display and DM creating a new VirtualDisplay is async,
+                // WM may have tried to start task recording and encountered an error that required
+                // stopping recording entirely. The VirtualDisplay would then be null when the
+                // MediaProjection is no longer active.
+                return null;
+            }
+            session.setDisplayId(virtualDisplay.getDisplay().getDisplayId());
+            // Successfully set up, so save the current session details.
+            wmService.setContentRecordingSession(session);
             return virtualDisplay;
         } catch (RemoteException e) {
             // Can not capture if WMS is not accessible, so bail out.
@@ -189,28 +208,6 @@
     }
 
     /**
-     * Updates the {@link ContentRecordingSession} describing the recording taking place on this
-     * {@link VirtualDisplay}.
-     *
-     * @throws RemoteException if updating the session on the server failed.
-     */
-    private void setSession(@NonNull IBinder windowContextToken,
-            @Nullable VirtualDisplay virtualDisplay)
-            throws RemoteException {
-        if (virtualDisplay == null) {
-            // Not able to set up a new VirtualDisplay.
-            return;
-        }
-        // Identify the VirtualDisplay that will be hosting the recording.
-        ContentRecordingSession session = ContentRecordingSession.createDisplaySession(
-                windowContextToken);
-        session.setDisplayId(virtualDisplay.getDisplay().getDisplayId());
-        // TODO(b/216625226) handle task recording.
-        // Successfully set up, so save the current session details.
-        WindowManagerGlobal.getWindowManagerService().setContentRecordingSession(session);
-    }
-
-    /**
      * Stops projection.
      */
     public void stop() {
diff --git a/packages/SettingsLib/SettingsTheme/res/color-v31/settingslib_text_color_primary.xml b/packages/SettingsLib/SettingsTheme/res/color-v31/settingslib_text_color_primary.xml
new file mode 100644
index 0000000..221d2db
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/color-v31/settingslib_text_color_primary.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_enabled="false"
+        android:alpha="?android:attr/disabledAlpha"
+        android:color="@color/settingslib_text_color_primary_device_default"/>
+    <item android:color="@color/settingslib_text_color_primary_device_default"/>
+</selector>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-v31/styles.xml b/packages/SettingsLib/SettingsTheme/res/values-v31/styles.xml
index 9d39911..cba1a9c 100644
--- a/packages/SettingsLib/SettingsTheme/res/values-v31/styles.xml
+++ b/packages/SettingsLib/SettingsTheme/res/values-v31/styles.xml
@@ -17,7 +17,7 @@
 <resources>
     <style name="TextAppearance.PreferenceTitle.SettingsLib"
            parent="@android:style/TextAppearance.Material.Subhead">
-        <item name="android:textColor">@color/settingslib_text_color_primary_device_default</item>
+        <item name="android:textColor">@color/settingslib_text_color_primary</item>
         <item name="android:fontFamily">@string/settingslib_config_headlineFontFamily</item>
         <item name="android:textSize">20sp</item>
     </style>
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
index a27b9cd..b811c51 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
@@ -116,7 +116,7 @@
     }
 
     fun showRipple(biometricSourceType: BiometricSourceType?) {
-        if (!keyguardUpdateMonitor.isKeyguardVisible ||
+        if (!(keyguardUpdateMonitor.isKeyguardVisible || keyguardUpdateMonitor.isDreaming) ||
             keyguardUpdateMonitor.userNeedsStrongAuth()) {
             return
         }
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
index 7a4dee2..d472aee 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
@@ -812,7 +812,7 @@
     @TransformationType
     fun calculateTransformationType(): Int {
         if (isTransitioningToFullShade) {
-            if (inSplitShade) {
+            if (inSplitShade && areGuidedTransitionHostsVisible()) {
                 return TRANSFORMATION_TYPE_TRANSITION
             }
             return TRANSFORMATION_TYPE_FADE
@@ -829,6 +829,11 @@
         return TRANSFORMATION_TYPE_TRANSITION
     }
 
+    private fun areGuidedTransitionHostsVisible(): Boolean {
+        return getHost(previousLocation)?.visible == true &&
+                getHost(desiredLocation)?.visible == true
+    }
+
     /**
      * @return the current transformation progress if we're in a guided transformation and -1
      * otherwise
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt
index 7fbb0f1..02aa1f2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt
@@ -25,7 +25,7 @@
     @JvmOverloads
     fun getAnimatorController(
         notification: ExpandableNotificationRow,
-        onFinishAnimationCallback: Runnable = Runnable {}
+        onFinishAnimationCallback: Runnable? = null
     ): NotificationLaunchAnimatorController {
         return NotificationLaunchAnimatorController(
             notificationShadeWindowViewController,
@@ -49,7 +49,7 @@
     private val headsUpManager: HeadsUpManagerPhone,
     private val notification: ExpandableNotificationRow,
     private val jankMonitor: InteractionJankMonitor,
-    private val onFinishAnimationCallback: Runnable
+    private val onFinishAnimationCallback: Runnable?
 ) : ActivityLaunchAnimator.Controller {
 
     companion object {
@@ -123,7 +123,7 @@
 
         if (!willAnimate) {
             removeHun(animate = true)
-            onFinishAnimationCallback.run()
+            onFinishAnimationCallback?.run()
         }
     }
 
@@ -142,7 +142,7 @@
         notificationShadeWindowViewController.setExpandAnimationRunning(false)
         notificationEntry.isExpandAnimationRunning = false
         removeHun(animate = true)
-        onFinishAnimationCallback.run()
+        onFinishAnimationCallback?.run()
     }
 
     override fun onLaunchAnimationStart(isExpandingFullyAbove: Boolean) {
@@ -162,7 +162,7 @@
         notificationListContainer.setExpandingNotification(null)
         applyParams(null)
         removeHun(animate = false)
-        onFinishAnimationCallback.run()
+        onFinishAnimationCallback?.run()
     }
 
     private fun applyParams(params: ExpandAnimationParameters?) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
index 637e4be..6fe92fa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
@@ -397,15 +397,25 @@
             mMainThreadHandler.post(() -> {
                 final Runnable removeNotification = () -> {
                     mOnUserInteractionCallback.onDismiss(entry, REASON_CLICK, summaryToRemove);
+                    if (!animate) {
+                        // If we're animating, this would be invoked after the activity launch
+                        // animation completes. Since we're not animating, the launch already
+                        // happened synchronously, so we notify the launch is complete here after
+                        // onDismiss.
+                        mLaunchEventsEmitter.notifyFinishLaunchNotifActivity(entry);
+                    }
                 };
                 if (mPresenter.isCollapsing()) {
-                    // To avoid lags we're only performing the remove
-                    // after the shade is collapsed
+                    // To avoid lags we're only performing the remove after the shade is collapsed
                     mShadeController.addPostCollapseAction(removeNotification);
                 } else {
                     removeNotification.run();
                 }
             });
+        } else if (!canBubble && !animate) {
+            // Not animating, this is the end of the launch flow (see above comment for more info).
+            mMainThreadHandler.post(
+                    () -> mLaunchEventsEmitter.notifyFinishLaunchNotifActivity(entry));
         }
 
         mIsCollapsingToShowActivityOverLockscreen = false;
@@ -481,8 +491,9 @@
             boolean isActivityIntent) {
         mLogger.logStartNotificationIntent(entry.getKey(), intent);
         try {
-            Runnable onFinishAnimationCallback =
-                    () -> mLaunchEventsEmitter.notifyFinishLaunchNotifActivity(entry);
+            Runnable onFinishAnimationCallback = animate
+                    ? () -> mLaunchEventsEmitter.notifyFinishLaunchNotifActivity(entry)
+                    : null;
             ActivityLaunchAnimator.Controller animationController =
                     new StatusBarLaunchAnimatorController(
                             mNotificationAnimationProvider
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt
index ec2c1de..a95da62 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt
@@ -114,12 +114,13 @@
     }
 
     @Test
-    fun testFingerprintTrigger_Ripple() {
+    fun testFingerprintTrigger_KeyguardVisible_Ripple() {
         // GIVEN fp exists, keyguard is visible, user doesn't need strong auth
         val fpsLocation = PointF(5f, 5f)
         `when`(authController.fingerprintSensorLocation).thenReturn(fpsLocation)
         controller.onViewAttached()
         `when`(keyguardUpdateMonitor.isKeyguardVisible).thenReturn(true)
+        `when`(keyguardUpdateMonitor.isDreaming).thenReturn(false)
         `when`(keyguardUpdateMonitor.userNeedsStrongAuth()).thenReturn(false)
 
         // WHEN fingerprint authenticated
@@ -136,7 +137,30 @@
     }
 
     @Test
-    fun testFingerprintTrigger_KeyguardNotVisible_NoRipple() {
+    fun testFingerprintTrigger_Dreaming_Ripple() {
+        // GIVEN fp exists, keyguard is visible, user doesn't need strong auth
+        val fpsLocation = PointF(5f, 5f)
+        `when`(authController.fingerprintSensorLocation).thenReturn(fpsLocation)
+        controller.onViewAttached()
+        `when`(keyguardUpdateMonitor.isKeyguardVisible).thenReturn(false)
+        `when`(keyguardUpdateMonitor.isDreaming).thenReturn(true)
+        `when`(keyguardUpdateMonitor.userNeedsStrongAuth()).thenReturn(false)
+
+        // WHEN fingerprint authenticated
+        val captor = ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback::class.java)
+        verify(keyguardUpdateMonitor).registerCallback(captor.capture())
+        captor.value.onBiometricAuthenticated(
+                0 /* userId */,
+                BiometricSourceType.FINGERPRINT /* type */,
+                false /* isStrongBiometric */)
+
+        // THEN update sensor location and show ripple
+        verify(rippleView).setFingerprintSensorLocation(fpsLocation, -1f)
+        verify(rippleView).startUnlockedRipple(any())
+    }
+
+    @Test
+    fun testFingerprintTrigger_KeyguardNotVisible_NotDreaming_NoRipple() {
         // GIVEN fp exists & user doesn't need strong auth
         val fpsLocation = PointF(5f, 5f)
         `when`(authController.udfpsSensorLocation).thenReturn(fpsLocation)
@@ -145,6 +169,7 @@
 
         // WHEN keyguard is NOT visible & fingerprint authenticated
         `when`(keyguardUpdateMonitor.isKeyguardVisible).thenReturn(false)
+        `when`(keyguardUpdateMonitor.isDreaming).thenReturn(false)
         val captor = ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback::class.java)
         verify(keyguardUpdateMonitor).registerCallback(captor.capture())
         captor.value.onBiometricAuthenticated(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt
index 8e201b5..203eb47 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt
@@ -223,6 +223,18 @@
     }
 
     @Test
+    fun calculateTransformationType_onLockSplitShade_goingToFullShade_mediaInvisible_returnsFade() {
+        enableSplitShade()
+        goToLockscreen()
+        expandQS()
+        whenever(lockHost.visible).thenReturn(false)
+        mediaHiearchyManager.setTransitionToFullShadeAmount(10000f)
+
+        val transformType = mediaHiearchyManager.calculateTransformationType()
+        assertThat(transformType).isEqualTo(MediaHierarchyManager.TRANSFORMATION_TYPE_FADE)
+    }
+
+    @Test
     fun calculateTransformationType_onLockShade_inSplitShade_notExpanding_returnsFade() {
         enableSplitShade()
         goToLockscreen()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
index d48ce8c..fa867e2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
@@ -447,4 +447,15 @@
         controllerCaptor.getValue().onIntentStarted(false);
         verify(listener).onFinishLaunchNotifActivity(mNotificationRow.getEntry());
     }
+
+    @Test
+    public void testNotifActivityStarterEventSourceFinishEvent_postPanelCollapse_noAnimate() {
+        NotifActivityLaunchEvents.Listener listener =
+                mock(NotifActivityLaunchEvents.Listener.class);
+        mLaunchEventsEmitter.registerListener(listener);
+        when(mCentralSurfaces.shouldAnimateLaunch(anyBoolean())).thenReturn(false);
+        mNotificationActivityStarter
+                .onNotificationClicked(mNotificationRow.getEntry().getSbn(), mNotificationRow);
+        verify(listener).onFinishLaunchNotifActivity(mNotificationRow.getEntry());
+    }
 }
diff --git a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
index 1131fa8..4fdc88d 100644
--- a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
+++ b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
@@ -561,8 +561,18 @@
             // We were asked to fetch Bluetooth data.
             final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
             if (adapter != null) {
-                bluetoothReceiver = new SynchronousResultReceiver("bluetooth");
-                adapter.requestControllerActivityEnergyInfo(bluetoothReceiver);
+                SynchronousResultReceiver resultReceiver =
+                        new SynchronousResultReceiver("bluetooth");
+                adapter.requestControllerActivityEnergyInfo(
+                        Runnable::run,
+                        info -> {
+                            Bundle bundle = new Bundle();
+                            bundle.putParcelable(BatteryStats.RESULT_RECEIVER_CONTROLLER_KEY,
+                                    info);
+                            resultReceiver.send(0, bundle);
+                        }
+                );
+                bluetoothReceiver = resultReceiver;
             }
         }
 
diff --git a/services/core/java/com/android/server/audio/SpatializerHelper.java b/services/core/java/com/android/server/audio/SpatializerHelper.java
index 4a853e1..f0f04e2 100644
--- a/services/core/java/com/android/server/audio/SpatializerHelper.java
+++ b/services/core/java/com/android/server/audio/SpatializerHelper.java
@@ -139,6 +139,7 @@
     private @Nullable SpatializerCallback mSpatCallback;
     private @Nullable SpatializerHeadTrackingCallback mSpatHeadTrackingCallback;
     private @Nullable HelperDynamicSensorCallback mDynSensorCallback;
+    private boolean mIsHeadTrackingSupported = false;
 
     // default attributes and format that determine basic availability of spatialization
     private static final AudioAttributes DEFAULT_ATTRIBUTES = new AudioAttributes.Builder()
@@ -813,8 +814,9 @@
             mSpat = AudioSystem.getSpatializer(mSpatCallback);
             try {
                 mSpat.setLevel((byte)  Spatializer.SPATIALIZER_IMMERSIVE_LEVEL_MULTICHANNEL);
+                mIsHeadTrackingSupported = mSpat.isHeadTrackingSupported();
                 //TODO: register heatracking callback only when sensors are registered
-                if (mSpat.isHeadTrackingSupported()) {
+                if (mIsHeadTrackingSupported) {
                     mSpat.registerHeadTrackingCallback(mSpatHeadTrackingCallback);
                 }
             } catch (RemoteException e) {
@@ -832,12 +834,15 @@
         if (mSpat != null) {
             mSpatCallback = null;
             try {
-                mSpat.registerHeadTrackingCallback(null);
+                if (mIsHeadTrackingSupported) {
+                    mSpat.registerHeadTrackingCallback(null);
+                }
                 mHeadTrackerAvailable = false;
                 mSpat.release();
             } catch (RemoteException e) {
                 Log.e(TAG, "Can't set release spatializer cleanly", e);
             }
+            mIsHeadTrackingSupported = false;
             mSpat = null;
         }
     }
@@ -1124,7 +1129,7 @@
                 }
                 break;
         }
-        return true;
+        return mIsHeadTrackingSupported;
     }
 
     private void dispatchActualHeadTrackingMode(int newMode) {
@@ -1314,13 +1319,8 @@
             Log.e(TAG, "not " + action + " sensors, null spatializer");
             return;
         }
-        try {
-            if (!mSpat.isHeadTrackingSupported()) {
-                Log.e(TAG, "not " + action + " sensors, spatializer doesn't support headtracking");
-                return;
-            }
-        } catch (RemoteException e) {
-            Log.e(TAG, "not " + action + " sensors, error querying headtracking", e);
+        if (!mIsHeadTrackingSupported) {
+            Log.e(TAG, "not " + action + " sensors, spatializer doesn't support headtracking");
             return;
         }
         int headHandle = -1;
diff --git a/services/core/java/com/android/server/display/ColorFade.java b/services/core/java/com/android/server/display/ColorFade.java
index 7cb2921..cb04ddf 100644
--- a/services/core/java/com/android/server/display/ColorFade.java
+++ b/services/core/java/com/android/server/display/ColorFade.java
@@ -156,9 +156,15 @@
 
         mMode = mode;
 
+        DisplayInfo displayInfo = mDisplayManagerInternal.getDisplayInfo(mDisplayId);
+        if (displayInfo == null) {
+            // displayInfo can be null if the associated display has been removed. There
+            // is a delay between the display being removed and ColorFade being dismissed.
+            return false;
+        }
+
         // Get the display size and layer stack.
         // This is not expected to change while the color fade surface is showing.
-        DisplayInfo displayInfo = mDisplayManagerInternal.getDisplayInfo(mDisplayId);
         mDisplayLayerStack = displayInfo.layerStack;
         mDisplayWidth = displayInfo.getNaturalWidth();
         mDisplayHeight = displayInfo.getNaturalHeight();
diff --git a/services/core/java/com/android/server/locales/LocaleManagerService.java b/services/core/java/com/android/server/locales/LocaleManagerService.java
index 176c08c..924db6a 100644
--- a/services/core/java/com/android/server/locales/LocaleManagerService.java
+++ b/services/core/java/com/android/server/locales/LocaleManagerService.java
@@ -22,12 +22,14 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
+import android.app.ActivityManager;
 import android.app.ActivityManagerInternal;
 import android.app.ILocaleManager;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManagerInternal;
+import android.content.res.Configuration;
 import android.os.Binder;
 import android.os.HandlerThread;
 import android.os.LocaleList;
@@ -154,6 +156,12 @@
         }
 
         @Override
+        @NonNull
+        public LocaleList getSystemLocales() throws RemoteException {
+            return LocaleManagerService.this.getSystemLocales();
+        }
+
+        @Override
         public void onShellCommand(FileDescriptor in, FileDescriptor out,
                 FileDescriptor err, String[] args, ShellCallback callback,
                 ResultReceiver resultReceiver) {
@@ -426,6 +434,32 @@
         return null;
     }
 
+    /**
+     * Returns the current system locales.
+     */
+    @NonNull
+    public LocaleList getSystemLocales() throws RemoteException {
+        final long token = Binder.clearCallingIdentity();
+        try {
+            return getSystemLocalesUnchecked();
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
+    @NonNull
+    private LocaleList getSystemLocalesUnchecked() throws RemoteException {
+        LocaleList systemLocales = null;
+        Configuration conf = ActivityManager.getService().getConfiguration();
+        if (conf != null) {
+            systemLocales = conf.getLocales();
+        }
+        if (systemLocales == null) {
+            systemLocales = LocaleList.getEmptyLocaleList();
+        }
+        return systemLocales;
+    }
+
     private void logMetric(@NonNull AppLocaleChangedAtomRecord atomRecordForMetrics) {
         FrameworkStatsLog.write(FrameworkStatsLog.APPLICATION_LOCALES_CHANGED,
                 atomRecordForMetrics.mCallingUid,
diff --git a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
index 3ce8e46..1937852 100644
--- a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
+++ b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
@@ -45,6 +45,7 @@
 import android.os.UserHandle;
 import android.util.ArrayMap;
 import android.util.Slog;
+import android.window.WindowContainerToken;
 
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.DumpUtils;
@@ -410,6 +411,7 @@
         private IBinder mToken;
         private IBinder.DeathRecipient mDeathEater;
         private boolean mRestoreSystemAlertWindow;
+        private WindowContainerToken mTaskRecordingWindowContainerToken = null;
 
         MediaProjection(int type, int uid, String packageName, int targetSdkVersion,
                 boolean isPrivileged) {
@@ -568,7 +570,7 @@
             }
         }
 
-        @Override
+        @Override // Binder call
         public void registerCallback(IMediaProjectionCallback callback) {
             if (callback == null) {
                 throw new IllegalArgumentException("callback must not be null");
@@ -576,7 +578,7 @@
             mCallbackDelegate.add(callback);
         }
 
-        @Override
+        @Override // Binder call
         public void unregisterCallback(IMediaProjectionCallback callback) {
             if (callback == null) {
                 throw new IllegalArgumentException("callback must not be null");
@@ -584,6 +586,17 @@
             mCallbackDelegate.remove(callback);
         }
 
+        @Override // Binder call
+        public void setTaskRecordingWindowContainerToken(WindowContainerToken token) {
+            // TODO(b/221417940) set the task id to record from sysui, for the package chosen.
+            mTaskRecordingWindowContainerToken = token;
+        }
+
+        @Override // Binder call
+        public WindowContainerToken getTaskRecordingWindowContainerToken() {
+            return mTaskRecordingWindowContainerToken;
+        }
+
         public MediaProjectionInfo getProjectionInfo() {
             return new MediaProjectionInfo(packageName, userHandle);
         }
diff --git a/services/core/java/com/android/server/pm/BackgroundDexOptService.java b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
index 9ff4aab..d26a1ac 100644
--- a/services/core/java/com/android/server/pm/BackgroundDexOptService.java
+++ b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
@@ -253,7 +253,8 @@
      *
      * <p>This is only for shell command and only root or shell user can use this.
      *
-     * @param packageNames dex optimize the passed packages or all packages if null
+     * @param packageNames dex optimize the passed packages in the given order, or all packages in
+     *         the default order if null
      *
      * @return true if dex optimization is complete. false if the task is cancelled or if there was
      *         an error.
@@ -268,11 +269,11 @@
                 resetStatesForNewDexOptRunLocked(Thread.currentThread());
             }
             PackageManagerService pm = mInjector.getPackageManagerService();
-            ArraySet<String> packagesToOptimize;
+            List<String> packagesToOptimize;
             if (packageNames == null) {
                 packagesToOptimize = mDexOptHelper.getOptimizablePackages(pm.snapshotComputer());
             } else {
-                packagesToOptimize = new ArraySet<>(packageNames);
+                packagesToOptimize = packageNames;
             }
             return runIdleOptimization(pm, packagesToOptimize, /* isPostBootUpdate= */ false);
         } finally {
@@ -335,7 +336,7 @@
             return false;
         }
 
-        ArraySet<String> pkgs = mDexOptHelper.getOptimizablePackages(pm.snapshotComputer());
+        List<String> pkgs = mDexOptHelper.getOptimizablePackages(pm.snapshotComputer());
         if (pkgs.isEmpty()) {
             Slog.i(TAG, "No packages to optimize");
             markPostBootUpdateCompleted(params);
@@ -525,7 +526,7 @@
     }
 
     /** Returns true if completed */
-    private boolean runIdleOptimization(PackageManagerService pm, ArraySet<String> pkgs,
+    private boolean runIdleOptimization(PackageManagerService pm, List<String> pkgs,
             boolean isPostBootUpdate) {
         synchronized (mLock) {
             mLastExecutionStartTimeMs = SystemClock.elapsedRealtime();
@@ -581,10 +582,9 @@
     }
 
     @Status
-    private int idleOptimizePackages(PackageManagerService pm, ArraySet<String> pkgs,
+    private int idleOptimizePackages(PackageManagerService pm, List<String> pkgs,
             long lowStorageThreshold, boolean isPostBootUpdate) {
         ArraySet<String> updatedPackages = new ArraySet<>();
-        ArraySet<String> updatedPackagesDueToSecondaryDex = new ArraySet<>();
 
         try {
             boolean supportSecondaryDex = mInjector.supportSecondaryDex();
@@ -640,25 +640,12 @@
                         }
                     }
 
-                    pkgs = new ArraySet<>(pkgs);
+                    pkgs = new ArrayList<>(pkgs);
                     pkgs.removeAll(unusedPackages);
                 }
             }
 
-            @Status int primaryResult = optimizePackages(pkgs, lowStorageThreshold,
-                    /*isForPrimaryDex=*/ true, updatedPackages, isPostBootUpdate);
-            if (primaryResult != STATUS_OK) {
-                return primaryResult;
-            }
-
-            if (!supportSecondaryDex) {
-                return STATUS_OK;
-            }
-
-            @Status int secondaryResult = optimizePackages(pkgs, lowStorageThreshold,
-                    /*isForPrimaryDex*/ false, updatedPackagesDueToSecondaryDex,
-                    isPostBootUpdate);
-            return secondaryResult;
+            return optimizePackages(pkgs, lowStorageThreshold, updatedPackages, isPostBootUpdate);
         } finally {
             // Always let the pinner service know about changes.
             notifyPinService(updatedPackages);
@@ -670,8 +657,10 @@
     }
 
     @Status
-    private int optimizePackages(ArraySet<String> pkgs, long lowStorageThreshold,
-            boolean isForPrimaryDex, ArraySet<String> updatedPackages, boolean isPostBootUpdate) {
+    private int optimizePackages(List<String> pkgs, long lowStorageThreshold,
+            ArraySet<String> updatedPackages, boolean isPostBootUpdate) {
+        boolean supportSecondaryDex = mInjector.supportSecondaryDex();
+
         for (String pkg : pkgs) {
             int abortCode = abortIdleOptimizations(lowStorageThreshold);
             if (abortCode != STATUS_OK) {
@@ -679,11 +668,23 @@
                 return abortCode;
             }
 
-            @DexOptResult int result = optimizePackage(pkg, isForPrimaryDex, isPostBootUpdate);
-            if (result == PackageDexOptimizer.DEX_OPT_PERFORMED) {
+            @DexOptResult int primaryResult =
+                    optimizePackage(pkg, true /* isForPrimaryDex */, isPostBootUpdate);
+            if (primaryResult == PackageDexOptimizer.DEX_OPT_PERFORMED) {
                 updatedPackages.add(pkg);
-            } else if (result != PackageDexOptimizer.DEX_OPT_SKIPPED) {
-                return convertPackageDexOptimizerStatusToInternal(result);
+            } else if (primaryResult != PackageDexOptimizer.DEX_OPT_SKIPPED) {
+                return convertPackageDexOptimizerStatusToInternal(primaryResult);
+            }
+
+            if (!supportSecondaryDex) {
+                continue;
+            }
+
+            @DexOptResult int secondaryResult =
+                    optimizePackage(pkg, false /* isForPrimaryDex */, isPostBootUpdate);
+            if (secondaryResult != PackageDexOptimizer.DEX_OPT_PERFORMED
+                    && secondaryResult != PackageDexOptimizer.DEX_OPT_SKIPPED) {
+                return convertPackageDexOptimizerStatusToInternal(secondaryResult);
             }
         }
         return STATUS_OK;
diff --git a/services/core/java/com/android/server/pm/DexOptHelper.java b/services/core/java/com/android/server/pm/DexOptHelper.java
index 50b2e23..bb2ba5c 100644
--- a/services/core/java/com/android/server/pm/DexOptHelper.java
+++ b/services/core/java/com/android/server/pm/DexOptHelper.java
@@ -293,8 +293,8 @@
         MetricsLogger.histogram(mPm.mContext, "opt_dialog_time_s", elapsedTimeSeconds);
     }
 
-    public ArraySet<String> getOptimizablePackages(@NonNull Computer snapshot) {
-        ArraySet<String> pkgs = new ArraySet<>();
+    public List<String> getOptimizablePackages(@NonNull Computer snapshot) {
+        ArrayList<String> pkgs = new ArrayList<>();
         mPm.forEachPackageState(snapshot, packageState -> {
             final AndroidPackage pkg = packageState.getPkg();
             if (pkg != null && mPm.mPackageDexOptimizer.canOptimizePackage(pkg)) {
diff --git a/services/core/java/com/android/server/pm/InitAndSystemPackageHelper.java b/services/core/java/com/android/server/pm/InitAppsHelper.java
similarity index 65%
rename from services/core/java/com/android/server/pm/InitAndSystemPackageHelper.java
rename to services/core/java/com/android/server/pm/InitAppsHelper.java
index 91750de..15f26e7 100644
--- a/services/core/java/com/android/server/pm/InitAndSystemPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InitAppsHelper.java
@@ -32,6 +32,7 @@
 import static com.android.server.pm.PackageManagerService.TAG;
 import static com.android.server.pm.pkg.parsing.ParsingPackageUtils.PARSE_CHECK_MAX_SDK_VERSION;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.pm.parsing.ApkLiteParseUtils;
 import android.os.Environment;
@@ -61,14 +62,24 @@
  * further cleanup and eventually all the installation/scanning related logic will go to another
  * class.
  */
-final class InitAndSystemPackageHelper {
+final class InitAppsHelper {
     private final PackageManagerService mPm;
-
     private final List<ScanPartition> mDirsToScanAsSystem;
     private final int mScanFlags;
     private final int mSystemParseFlags;
     private final int mSystemScanFlags;
     private final InstallPackageHelper mInstallPackageHelper;
+    private final ApexManager mApexManager;
+    private final ExecutorService mExecutorService;
+    /* Tracks how long system scan took */
+    private long mSystemScanTime;
+    /* Track of the number of cached system apps */
+    private int mCachedSystemApps;
+    /* Track of the number of system apps */
+    private int mSystemPackagesCount;
+    private final boolean mIsDeviceUpgrading;
+    private final boolean mIsOnlyCoreApps;
+    private final List<ScanPartition> mSystemPartitions;
 
     /**
      * Tracks new system packages [received in an OTA] that we expect to
@@ -76,21 +87,33 @@
      * are package location.
      */
     private final ArrayMap<String, File> mExpectingBetter = new ArrayMap<>();
+    /* Tracks of any system packages that no longer exist that needs to be pruned. */
+    private final List<String> mPossiblyDeletedUpdatedSystemApps = new ArrayList<>();
+    // Tracks of stub packages that must either be replaced with full versions in the /data
+    // partition or be disabled.
+    private final List<String> mStubSystemApps = new ArrayList<>();
 
     // TODO(b/198166813): remove PMS dependency
-    InitAndSystemPackageHelper(PackageManagerService pm) {
+    InitAppsHelper(PackageManagerService pm, ApexManager apexManager,
+            InstallPackageHelper installPackageHelper,
+            List<ScanPartition> systemPartitions) {
         mPm = pm;
-        mInstallPackageHelper = new InstallPackageHelper(pm);
+        mApexManager = apexManager;
+        mInstallPackageHelper = installPackageHelper;
+        mSystemPartitions = systemPartitions;
         mDirsToScanAsSystem = getSystemScanPartitions();
+        mIsDeviceUpgrading = mPm.isDeviceUpgrading();
+        mIsOnlyCoreApps = mPm.isOnlyCoreApps();
         // Set flag to monitor and not change apk file paths when scanning install directories.
         int scanFlags = SCAN_BOOTING | SCAN_INITIAL;
-        if (mPm.isDeviceUpgrading() || mPm.isFirstBoot()) {
+        if (mIsDeviceUpgrading || mPm.isFirstBoot()) {
             mScanFlags = scanFlags | SCAN_FIRST_BOOT_OR_UPGRADE;
         } else {
             mScanFlags = scanFlags;
         }
         mSystemParseFlags = mPm.getDefParseFlags() | ParsingPackageUtils.PARSE_IS_SYSTEM_DIR;
         mSystemScanFlags = scanFlags | SCAN_AS_SYSTEM;
+        mExecutorService = ParallelPackageParser.makeExecutorService();
     }
 
     private List<File> getFrameworkResApkSplitFiles() {
@@ -118,7 +141,7 @@
 
     private List<ScanPartition> getSystemScanPartitions() {
         final List<ScanPartition> scanPartitions = new ArrayList<>();
-        scanPartitions.addAll(mPm.mInjector.getSystemPartitions());
+        scanPartitions.addAll(mSystemPartitions);
         scanPartitions.addAll(getApexScanPartitions());
         Slog.d(TAG, "Directories scanned as system partitions: " + scanPartitions);
         return scanPartitions;
@@ -126,8 +149,7 @@
 
     private List<ScanPartition> getApexScanPartitions() {
         final List<ScanPartition> scanPartitions = new ArrayList<>();
-        final List<ApexManager.ActiveApexInfo> activeApexInfos =
-                mPm.mApexManager.getActiveApexInfos();
+        final List<ApexManager.ActiveApexInfo> activeApexInfos = mApexManager.getActiveApexInfos();
         for (int i = 0; i < activeApexInfos.size(); i++) {
             final ScanPartition scanPartition = resolveApexToScanPartition(activeApexInfos.get(i));
             if (scanPartition != null) {
@@ -144,117 +166,134 @@
             if (apexInfo.preInstalledApexPath.getAbsolutePath().equals(
                     sp.getFolder().getAbsolutePath())
                     || apexInfo.preInstalledApexPath.getAbsolutePath().startsWith(
-                        sp.getFolder().getAbsolutePath() + File.separator)) {
+                    sp.getFolder().getAbsolutePath() + File.separator)) {
                 return new ScanPartition(apexInfo.apexDirectory, sp, SCAN_AS_APK_IN_APEX);
             }
         }
         return null;
     }
 
-    public OverlayConfig initPackages(
-            WatchedArrayMap<String, PackageSetting> packageSettings, int[] userIds,
-            long startTime) {
-        PackageParser2 packageParser = mPm.mInjector.getScanningCachingPackageParser();
-
-        ExecutorService executorService = ParallelPackageParser.makeExecutorService();
+    /**
+     * Install apps from system dirs.
+     */
+    @GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
+    public OverlayConfig initSystemApps(PackageParser2 packageParser,
+            WatchedArrayMap<String, PackageSetting> packageSettings,
+            int[] userIds, long startTime) {
         // Prepare apex package info before scanning APKs, this information is needed when
         // scanning apk in apex.
-        mPm.mApexManager.scanApexPackagesTraced(packageParser, executorService);
+        mApexManager.scanApexPackagesTraced(packageParser, mExecutorService);
 
-        scanSystemDirs(packageParser, executorService);
+        scanSystemDirs(packageParser, mExecutorService);
         // Parse overlay configuration files to set default enable state, mutability, and
         // priority of system overlays.
         final ArrayMap<String, File> apkInApexPreInstalledPaths = new ArrayMap<>();
-        for (ApexManager.ActiveApexInfo apexInfo : mPm.mApexManager.getActiveApexInfos()) {
-            for (String packageName : mPm.mApexManager.getApksInApex(apexInfo.apexModuleName)) {
+        for (ApexManager.ActiveApexInfo apexInfo : mApexManager.getActiveApexInfos()) {
+            for (String packageName : mApexManager.getApksInApex(apexInfo.apexModuleName)) {
                 apkInApexPreInstalledPaths.put(packageName, apexInfo.preInstalledApexPath);
             }
         }
-        OverlayConfig overlayConfig = OverlayConfig.initializeSystemInstance(
+        final OverlayConfig overlayConfig = OverlayConfig.initializeSystemInstance(
                 consumer -> mPm.forEachPackage(mPm.snapshotComputer(),
                         pkg -> consumer.accept(pkg, pkg.isSystem(),
-                          apkInApexPreInstalledPaths.get(pkg.getPackageName()))));
-        // Prune any system packages that no longer exist.
-        final List<String> possiblyDeletedUpdatedSystemApps = new ArrayList<>();
-        // Stub packages must either be replaced with full versions in the /data
-        // partition or be disabled.
-        final List<String> stubSystemApps = new ArrayList<>();
+                                apkInApexPreInstalledPaths.get(pkg.getPackageName()))));
 
-        if (!mPm.isOnlyCoreApps()) {
+        if (!mIsOnlyCoreApps) {
             // do this first before mucking with mPackages for the "expecting better" case
-            updateStubSystemAppsList(stubSystemApps);
+            updateStubSystemAppsList(mStubSystemApps);
             mInstallPackageHelper.prepareSystemPackageCleanUp(packageSettings,
-                    possiblyDeletedUpdatedSystemApps, mExpectingBetter, userIds);
+                    mPossiblyDeletedUpdatedSystemApps, mExpectingBetter, userIds);
         }
 
-        final int cachedSystemApps = PackageCacher.sCachedPackageReadCount.get();
+        logSystemAppsScanningTime(startTime);
+        return overlayConfig;
+    }
+
+    @GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
+    private void logSystemAppsScanningTime(long startTime) {
+        mCachedSystemApps = PackageCacher.sCachedPackageReadCount.get();
 
         // Remove any shared userIDs that have no associated packages
         mPm.mSettings.pruneSharedUsersLPw();
-        final long systemScanTime = SystemClock.uptimeMillis() - startTime;
-        final int systemPackagesCount = mPm.mPackages.size();
-        Slog.i(TAG, "Finished scanning system apps. Time: " + systemScanTime
-                + " ms, packageCount: " + systemPackagesCount
+        mSystemScanTime = SystemClock.uptimeMillis() - startTime;
+        mSystemPackagesCount = mPm.mPackages.size();
+        Slog.i(TAG, "Finished scanning system apps. Time: " + mSystemScanTime
+                + " ms, packageCount: " + mSystemPackagesCount
                 + " , timePerPackage: "
-                + (systemPackagesCount == 0 ? 0 : systemScanTime / systemPackagesCount)
-                + " , cached: " + cachedSystemApps);
-        if (mPm.isDeviceUpgrading() && systemPackagesCount > 0) {
+                + (mSystemPackagesCount == 0 ? 0 : mSystemScanTime / mSystemPackagesCount)
+                + " , cached: " + mCachedSystemApps);
+        if (mIsDeviceUpgrading && mSystemPackagesCount > 0) {
             //CHECKSTYLE:OFF IndentationCheck
             FrameworkStatsLog.write(FrameworkStatsLog.BOOT_TIME_EVENT_DURATION_REPORTED,
                     BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_SYSTEM_APP_AVG_SCAN_TIME,
-                    systemScanTime / systemPackagesCount);
+                    mSystemScanTime / mSystemPackagesCount);
             //CHECKSTYLE:ON IndentationCheck
         }
+    }
 
-        if (!mPm.isOnlyCoreApps()) {
+    /**
+     * Install apps/updates from data dir and fix system apps that are affected.
+     */
+    @GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
+    public void initNonSystemApps(PackageParser2 packageParser, @NonNull int[] userIds,
+            long startTime) {
+        if (!mIsOnlyCoreApps) {
             EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
                     SystemClock.uptimeMillis());
             scanDirTracedLI(mPm.getAppInstallDir(), /* frameworkSplits= */ null, 0,
-                    mScanFlags | SCAN_REQUIRE_KNOWN, 0,
-                    packageParser, executorService);
-
+                    mScanFlags | SCAN_REQUIRE_KNOWN,
+                    packageParser, mExecutorService);
         }
 
-        List<Runnable> unfinishedTasks = executorService.shutdownNow();
+        List<Runnable> unfinishedTasks = mExecutorService.shutdownNow();
         if (!unfinishedTasks.isEmpty()) {
             throw new IllegalStateException("Not all tasks finished before calling close: "
                     + unfinishedTasks);
         }
-
-        if (!mPm.isOnlyCoreApps()) {
-            mInstallPackageHelper.cleanupDisabledPackageSettings(possiblyDeletedUpdatedSystemApps,
-                    userIds, mScanFlags);
-            mInstallPackageHelper.checkExistingBetterPackages(mExpectingBetter,
-                    stubSystemApps, mSystemScanFlags, mSystemParseFlags);
-
-            // Uncompress and install any stubbed system applications.
-            // This must be done last to ensure all stubs are replaced or disabled.
-            mInstallPackageHelper.installSystemStubPackages(stubSystemApps, mScanFlags);
-
-            final int cachedNonSystemApps = PackageCacher.sCachedPackageReadCount.get()
-                    - cachedSystemApps;
-
-            final long dataScanTime = SystemClock.uptimeMillis() - systemScanTime - startTime;
-            final int dataPackagesCount = mPm.mPackages.size() - systemPackagesCount;
-            Slog.i(TAG, "Finished scanning non-system apps. Time: " + dataScanTime
-                    + " ms, packageCount: " + dataPackagesCount
-                    + " , timePerPackage: "
-                    + (dataPackagesCount == 0 ? 0 : dataScanTime / dataPackagesCount)
-                    + " , cached: " + cachedNonSystemApps);
-            if (mPm.isDeviceUpgrading() && dataPackagesCount > 0) {
-                //CHECKSTYLE:OFF IndentationCheck
-                FrameworkStatsLog.write(
-                        FrameworkStatsLog.BOOT_TIME_EVENT_DURATION_REPORTED,
-                        BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_DATA_APP_AVG_SCAN_TIME,
-                        dataScanTime / dataPackagesCount);
-                //CHECKSTYLE:OFF IndentationCheck
-            }
+        if (!mIsOnlyCoreApps) {
+            fixSystemPackages(userIds);
+            logNonSystemAppScanningTime(startTime);
         }
         mExpectingBetter.clear();
-
         mPm.mSettings.pruneRenamedPackagesLPw();
-        packageParser.close();
-        return overlayConfig;
+    }
+
+    /**
+     * Clean up system packages now that some system package updates have been installed from
+     * the data dir. Also install system stub packages as the last step.
+     */
+    @GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
+    private void fixSystemPackages(@NonNull int[] userIds) {
+        mInstallPackageHelper.cleanupDisabledPackageSettings(mPossiblyDeletedUpdatedSystemApps,
+                userIds, mScanFlags);
+        mInstallPackageHelper.checkExistingBetterPackages(mExpectingBetter,
+                mStubSystemApps, mSystemScanFlags, mSystemParseFlags);
+
+        // Uncompress and install any stubbed system applications.
+        // This must be done last to ensure all stubs are replaced or disabled.
+        mInstallPackageHelper.installSystemStubPackages(mStubSystemApps, mScanFlags);
+    }
+
+    @GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
+    private void logNonSystemAppScanningTime(long startTime) {
+        final int cachedNonSystemApps = PackageCacher.sCachedPackageReadCount.get()
+                - mCachedSystemApps;
+
+        final long dataScanTime = SystemClock.uptimeMillis() - mSystemScanTime - startTime;
+        final int dataPackagesCount = mPm.mPackages.size() - mSystemPackagesCount;
+        Slog.i(TAG, "Finished scanning non-system apps. Time: " + dataScanTime
+                + " ms, packageCount: " + dataPackagesCount
+                + " , timePerPackage: "
+                + (dataPackagesCount == 0 ? 0 : dataScanTime / dataPackagesCount)
+                + " , cached: " + cachedNonSystemApps);
+        if (mIsDeviceUpgrading && dataPackagesCount > 0) {
+            //CHECKSTYLE:OFF IndentationCheck
+            FrameworkStatsLog.write(
+                    FrameworkStatsLog.BOOT_TIME_EVENT_DURATION_REPORTED,
+                    BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_DATA_APP_AVG_SCAN_TIME,
+                    dataScanTime / dataPackagesCount);
+            //CHECKSTYLE:OFF IndentationCheck
+        }
     }
 
     /**
@@ -274,13 +313,13 @@
                 continue;
             }
             scanDirTracedLI(partition.getOverlayFolder(), /* frameworkSplits= */ null,
-                    mSystemParseFlags, mSystemScanFlags | partition.scanFlag, 0,
+                    mSystemParseFlags, mSystemScanFlags | partition.scanFlag,
                     packageParser, executorService);
         }
 
         scanDirTracedLI(frameworkDir, null,
                 mSystemParseFlags,
-                mSystemScanFlags | SCAN_NO_DEX | SCAN_AS_PRIVILEGED, 0,
+                mSystemScanFlags | SCAN_NO_DEX | SCAN_AS_PRIVILEGED,
                 packageParser, executorService);
         if (!mPm.mPackages.containsKey("android")) {
             throw new IllegalStateException(
@@ -292,11 +331,11 @@
             if (partition.getPrivAppFolder() != null) {
                 scanDirTracedLI(partition.getPrivAppFolder(), /* frameworkSplits= */ null,
                         mSystemParseFlags,
-                        mSystemScanFlags | SCAN_AS_PRIVILEGED | partition.scanFlag, 0,
+                        mSystemScanFlags | SCAN_AS_PRIVILEGED | partition.scanFlag,
                         packageParser, executorService);
             }
             scanDirTracedLI(partition.getAppFolder(), /* frameworkSplits= */ null,
-                    mSystemParseFlags, mSystemScanFlags | partition.scanFlag, 0,
+                    mSystemParseFlags, mSystemScanFlags | partition.scanFlag,
                     packageParser, executorService);
         }
     }
@@ -315,7 +354,7 @@
     @GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
     private void scanDirTracedLI(File scanDir, List<File> frameworkSplits,
             int parseFlags, int scanFlags,
-            long currentTime, PackageParser2 packageParser, ExecutorService executorService) {
+            PackageParser2 packageParser, ExecutorService executorService) {
         Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanDir [" + scanDir.getAbsolutePath() + "]");
         try {
             if ((scanFlags & SCAN_AS_APK_IN_APEX) != 0) {
@@ -323,7 +362,7 @@
                 parseFlags |= PARSE_CHECK_MAX_SDK_VERSION;
             }
             mInstallPackageHelper.installPackagesFromDir(scanDir, frameworkSplits, parseFlags,
-                    scanFlags, currentTime, packageParser, executorService);
+                    scanFlags, packageParser, executorService);
         } finally {
             Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
         }
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index b39b24f..870a11a 100644
--- a/services/core/java/com/android/server/pm/InstallPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -3062,7 +3062,7 @@
         final RemovePackageHelper removePackageHelper = new RemovePackageHelper(mPm);
         removePackageHelper.removePackageLI(stubPkg, true /*chatty*/);
         try {
-            return scanSystemPackageTracedLI(scanFile, parseFlags, scanFlags, 0, null);
+            return scanSystemPackageTracedLI(scanFile, parseFlags, scanFlags, null);
         } catch (PackageManagerException e) {
             Slog.w(TAG, "Failed to install compressed system package:" + stubPkg.getPackageName(),
                     e);
@@ -3194,7 +3194,7 @@
                         | ParsingPackageUtils.PARSE_IS_SYSTEM_DIR;
         @PackageManagerService.ScanFlags int scanFlags = mPm.getSystemPackageScanFlags(codePath);
         final AndroidPackage pkg = scanSystemPackageTracedLI(
-                        codePath, parseFlags, scanFlags, 0 /*currentTime*/, null);
+                codePath, parseFlags, scanFlags, null);
 
         PackageSetting pkgSetting = mPm.mSettings.getPackageLPr(pkg.getPackageName());
 
@@ -3368,7 +3368,7 @@
                 mRemovePackageHelper.removePackageLI(pkg, true);
                 try {
                     final File codePath = new File(pkg.getPath());
-                    scanSystemPackageTracedLI(codePath, 0, scanFlags, 0, null);
+                    scanSystemPackageTracedLI(codePath, 0, scanFlags, null);
                 } catch (PackageManagerException e) {
                     Slog.e(TAG, "Failed to parse updated, ex-system package: "
                             + e.getMessage());
@@ -3389,7 +3389,7 @@
 
     @GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
     public void installPackagesFromDir(File scanDir, List<File> frameworkSplits, int parseFlags,
-            int scanFlags, long currentTime, PackageParser2 packageParser,
+            int scanFlags, PackageParser2 packageParser,
             ExecutorService executorService) {
         final File[] files = scanDir.listFiles();
         if (ArrayUtils.isEmpty(files)) {
@@ -3432,7 +3432,7 @@
                             parseResult.parsedPackage);
                 }
                 try {
-                    addForInitLI(parseResult.parsedPackage, parseFlags, scanFlags, currentTime,
+                    addForInitLI(parseResult.parsedPackage, parseFlags, scanFlags,
                             null);
                 } catch (PackageManagerException e) {
                     errorCode = e.error;
@@ -3495,7 +3495,7 @@
 
             try {
                 final AndroidPackage newPkg = scanSystemPackageTracedLI(
-                        scanFile, reparseFlags, rescanFlags, 0, null);
+                        scanFile, reparseFlags, rescanFlags, null);
                 // We rescanned a stub, add it to the list of stubbed system packages
                 if (newPkg.isStub()) {
                     stubSystemApps.add(packageName);
@@ -3509,14 +3509,14 @@
 
     /**
      *  Traces a package scan.
-     *  @see #scanSystemPackageLI(File, int, int, long, UserHandle)
+     *  @see #scanSystemPackageLI(File, int, int, UserHandle)
      */
     @GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
     public AndroidPackage scanSystemPackageTracedLI(File scanFile, final int parseFlags,
-            int scanFlags, long currentTime, UserHandle user) throws PackageManagerException {
+            int scanFlags, UserHandle user) throws PackageManagerException {
         Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanPackage [" + scanFile.toString() + "]");
         try {
-            return scanSystemPackageLI(scanFile, parseFlags, scanFlags, currentTime, user);
+            return scanSystemPackageLI(scanFile, parseFlags, scanFlags, user);
         } finally {
             Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
         }
@@ -3528,7 +3528,7 @@
      */
     @GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
     private AndroidPackage scanSystemPackageLI(File scanFile, int parseFlags, int scanFlags,
-            long currentTime, UserHandle user) throws PackageManagerException {
+            UserHandle user) throws PackageManagerException {
         if (DEBUG_INSTALL) Slog.d(TAG, "Parsing: " + scanFile);
 
         Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage");
@@ -3544,7 +3544,7 @@
             PackageManagerService.renameStaticSharedLibraryPackage(parsedPackage);
         }
 
-        return addForInitLI(parsedPackage, parseFlags, scanFlags, currentTime, user);
+        return addForInitLI(parsedPackage, parseFlags, scanFlags, user);
     }
 
     /**
@@ -3563,11 +3563,11 @@
     @GuardedBy({"mPm.mLock", "mPm.mInstallLock"})
     private AndroidPackage addForInitLI(ParsedPackage parsedPackage,
             @ParsingPackageUtils.ParseFlags int parseFlags,
-            @PackageManagerService.ScanFlags int scanFlags, long currentTime,
+            @PackageManagerService.ScanFlags int scanFlags,
             @Nullable UserHandle user) throws PackageManagerException {
 
         final Pair<ScanResult, Boolean> scanResultPair = scanSystemPackageLI(
-                parsedPackage, parseFlags, scanFlags, currentTime, user);
+                parsedPackage, parseFlags, scanFlags, user);
         final ScanResult scanResult = scanResultPair.first;
         boolean shouldHideSystemApp = scanResultPair.second;
         if (scanResult.mSuccess) {
@@ -3762,7 +3762,7 @@
 
     private Pair<ScanResult, Boolean> scanSystemPackageLI(ParsedPackage parsedPackage,
             @ParsingPackageUtils.ParseFlags int parseFlags,
-            @PackageManagerService.ScanFlags int scanFlags, long currentTime,
+            @PackageManagerService.ScanFlags int scanFlags,
             @Nullable UserHandle user) throws PackageManagerException {
         final boolean scanSystemPartition =
                 (parseFlags & ParsingPackageUtils.PARSE_IS_SYSTEM_DIR) != 0;
@@ -3950,7 +3950,7 @@
         }
 
         final ScanResult scanResult = scanPackageNewLI(parsedPackage, parseFlags,
-                scanFlags | SCAN_UPDATE_SIGNATURE, currentTime, user, null);
+                scanFlags | SCAN_UPDATE_SIGNATURE, 0 /* currentTime */, user, null);
         return new Pair<>(scanResult, shouldHideSystemApp);
     }
 
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index eaecb17..b1b05be 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -229,7 +229,6 @@
 import com.android.server.pm.verify.domain.DomainVerificationManagerInternal;
 import com.android.server.pm.verify.domain.DomainVerificationService;
 import com.android.server.pm.verify.domain.proxy.DomainVerificationProxy;
-import com.android.server.pm.verify.domain.proxy.DomainVerificationProxyV1;
 import com.android.server.sdksandbox.SdkSandboxManagerLocal;
 import com.android.server.storage.DeviceStorageMonitorInternal;
 import com.android.server.utils.SnapshotCache;
@@ -936,7 +935,7 @@
     private final BroadcastHelper mBroadcastHelper;
     private final RemovePackageHelper mRemovePackageHelper;
     private final DeletePackageHelper mDeletePackageHelper;
-    private final InitAndSystemPackageHelper mInitAndSystemPackageHelper;
+    private final InitAppsHelper mInitAppsHelper;
     private final AppDataHelper mAppDataHelper;
     private final InstallPackageHelper mInstallPackageHelper;
     private final PreferredActivityHelper mPreferredActivityHelper;
@@ -1671,7 +1670,7 @@
         mAppDataHelper = testParams.appDataHelper;
         mInstallPackageHelper = testParams.installPackageHelper;
         mRemovePackageHelper = testParams.removePackageHelper;
-        mInitAndSystemPackageHelper = testParams.initAndSystemPackageHelper;
+        mInitAppsHelper = testParams.initAndSystemPackageHelper;
         mDeletePackageHelper = testParams.deletePackageHelper;
         mPreferredActivityHelper = testParams.preferredActivityHelper;
         mResolveIntentHelper = testParams.resolveIntentHelper;
@@ -1821,7 +1820,8 @@
         mAppDataHelper = new AppDataHelper(this);
         mInstallPackageHelper = new InstallPackageHelper(this, mAppDataHelper);
         mRemovePackageHelper = new RemovePackageHelper(this, mAppDataHelper);
-        mInitAndSystemPackageHelper = new InitAndSystemPackageHelper(this);
+        mInitAppsHelper = new InitAppsHelper(this, mApexManager, mInstallPackageHelper,
+                mInjector.getSystemPartitions());
         mDeletePackageHelper = new DeletePackageHelper(this, mRemovePackageHelper,
                 mAppDataHelper);
         mSharedLibraries.setDeletePackageHelper(mDeletePackageHelper);
@@ -1956,8 +1956,11 @@
                     mIsEngBuild, mIsUserDebugBuild, mIncrementalVersion);
 
             final int[] userIds = mUserManager.getUserIds();
-            mOverlayConfig = mInitAndSystemPackageHelper.initPackages(packageSettings,
-                    userIds, startTime);
+            PackageParser2 packageParser = mInjector.getScanningCachingPackageParser();
+            mOverlayConfig = mInitAppsHelper.initSystemApps(packageParser, packageSettings, userIds,
+                    startTime);
+            mInitAppsHelper.initNonSystemApps(packageParser, userIds, startTime);
+            packageParser.close();
 
             // Resolve the storage manager.
             mStorageManagerPackage = getStorageManagerPackageName(computer);
@@ -7030,7 +7033,7 @@
     }
 
     boolean isExpectingBetter(String packageName) {
-        return mInitAndSystemPackageHelper.isExpectingBetter(packageName);
+        return mInitAppsHelper.isExpectingBetter(packageName);
     }
 
     int getDefParseFlags() {
@@ -7129,13 +7132,12 @@
     }
 
     boolean isOverlayMutable(String packageName) {
-        return (mOverlayConfig != null ? mOverlayConfig
-                : OverlayConfig.getSystemInstance()).isMutable(packageName);
+        return mOverlayConfig.isMutable(packageName);
     }
 
     @ScanFlags int getSystemPackageScanFlags(File codePath) {
         List<ScanPartition> dirsToScanAsSystem =
-                mInitAndSystemPackageHelper.getDirsToScanAsSystem();
+                mInitAppsHelper.getDirsToScanAsSystem();
         @PackageManagerService.ScanFlags int scanFlags = SCAN_AS_SYSTEM;
         for (int i = dirsToScanAsSystem.size() - 1; i >= 0; i--) {
             ScanPartition partition = dirsToScanAsSystem.get(i);
@@ -7153,7 +7155,7 @@
     Pair<Integer, Integer> getSystemPackageRescanFlagsAndReparseFlags(File scanFile,
             int systemScanFlags, int systemParseFlags) {
         List<ScanPartition> dirsToScanAsSystem =
-                mInitAndSystemPackageHelper.getDirsToScanAsSystem();
+                mInitAppsHelper.getDirsToScanAsSystem();
         @ParsingPackageUtils.ParseFlags int reparseFlags = 0;
         @PackageManagerService.ScanFlags int rescanFlags = 0;
         for (int i1 = dirsToScanAsSystem.size() - 1; i1 >= 0; i1--) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java b/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java
index 5bdda0b..e466fe2 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java
@@ -109,7 +109,7 @@
     public AppDataHelper appDataHelper;
     public InstallPackageHelper installPackageHelper;
     public RemovePackageHelper removePackageHelper;
-    public InitAndSystemPackageHelper initAndSystemPackageHelper;
+    public InitAppsHelper initAndSystemPackageHelper;
     public DeletePackageHelper deletePackageHelper;
     public PreferredActivityHelper preferredActivityHelper;
     public ResolveIntentHelper resolveIntentHelper;
diff --git a/services/core/java/com/android/server/pm/StorageEventHelper.java b/services/core/java/com/android/server/pm/StorageEventHelper.java
index df19d3e..a991ed3 100644
--- a/services/core/java/com/android/server/pm/StorageEventHelper.java
+++ b/services/core/java/com/android/server/pm/StorageEventHelper.java
@@ -151,7 +151,7 @@
                 final AndroidPackage pkg;
                 try {
                     pkg = installPackageHelper.scanSystemPackageTracedLI(
-                            ps.getPath(), parseFlags, SCAN_INITIAL, 0, null);
+                            ps.getPath(), parseFlags, SCAN_INITIAL, null);
                     loaded.add(pkg);
 
                 } catch (PackageManagerException e) {
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 34b7ad4..70053bd 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -5409,6 +5409,21 @@
         (new Shell()).exec(this, in, out, err, args, callback, resultReceiver);
     }
 
+    private static final String PREFIX_HELP_COMMAND = "  ";
+    private static final String PREFIX_HELP_DESCRIPTION = "    ";
+    private static final String PREFIX_HELP_DESCRIPTION_EXTRA_LINES = "      ";
+
+    private static final String CMD_HELP = "help";
+    private static final String CMD_LIST = "list";
+    private static final String CMD_REPORT_SYSTEM_USER_PACKAGE_ALLOWLIST_PROBLEMS =
+            "report-system-user-package-whitelist-problems";
+
+    private static final String ARG_V = "-v";
+    private static final String ARG_VERBOSE = "--verbose";
+    private static final String ARG_ALL = "--all";
+    private static final String ARG_CRITICAL_ONLY = "--critical-only";
+    private static final String ARG_MODE = "--mode";
+
     private int onShellCommand(Shell shell, String cmd) {
         if (cmd == null) {
             return shell.handleDefaultCommands(cmd);
@@ -5417,9 +5432,9 @@
         final PrintWriter pw = shell.getOutPrintWriter();
         try {
             switch(cmd) {
-                case "list":
+                case CMD_LIST:
                     return runList(pw, shell);
-                case "report-system-user-package-whitelist-problems":
+                case CMD_REPORT_SYSTEM_USER_PACKAGE_ALLOWLIST_PROBLEMS:
                     return runReportPackageWhitelistProblems(pw, shell);
                 default:
                     return shell.handleDefaultCommands(cmd);
@@ -5436,10 +5451,10 @@
         String opt;
         while ((opt = shell.getNextOption()) != null) {
             switch (opt) {
-                case "-v":
+                case ARG_V:
                     verbose = true;
                     break;
-                case "--all":
+                case ARG_ALL:
                     all = true;
                     break;
                 default:
@@ -5520,14 +5535,14 @@
         String opt;
         while ((opt = shell.getNextOption()) != null) {
             switch (opt) {
-                case "-v":
-                case "--verbose":
+                case ARG_V:
+                case ARG_VERBOSE:
                     verbose = true;
                     break;
-                case "--critical-only":
+                case ARG_CRITICAL_ONLY:
                     criticalOnly = true;
                     break;
-                case "--mode":
+                case ARG_MODE:
                     mode = Integer.parseInt(shell.getNextArgRequired());
                     break;
                 default:
@@ -6248,20 +6263,28 @@
         @Override
         public void onHelp() {
             final PrintWriter pw = getOutPrintWriter();
-            pw.println("User manager (user) commands:");
-            pw.println("  help");
-            pw.println("    Prints this help text.");
-            pw.println("");
-            pw.println("  list [-v] [-all]");
-            pw.println("    Prints all users on the system.");
-            pw.println("  report-system-user-package-whitelist-problems [-v | --verbose] "
-                    + "[--critical-only] [--mode MODE]");
-            pw.println("    Reports all issues on user-type package whitelist XML files. Options:");
-            pw.println("    -v | --verbose : shows extra info, like number of issues");
-            pw.println("    --critical-only: show only critical issues, excluding warnings");
-            pw.println("    --mode MODE: shows what errors would be if device used mode MODE (where"
-                    + " MODE is the whitelist mode integer as defined by "
-                    + "config_userTypePackageWhitelistMode)");
+            pw.printf("User manager (user) commands:\n");
+
+            pw.printf("%s%s\n", PREFIX_HELP_COMMAND, CMD_HELP);
+            pw.printf("%sPrints this help text.\n\n", PREFIX_HELP_DESCRIPTION);
+
+            pw.printf("%s%s [%s] [%s]\n", PREFIX_HELP_COMMAND, CMD_LIST, ARG_V, ARG_ALL);
+            pw.printf("%sPrints all users on the system.\n\n", PREFIX_HELP_DESCRIPTION);
+
+            pw.printf("%s%s [%s | %s] [%s] [%s MODE]\n", PREFIX_HELP_COMMAND,
+                    CMD_REPORT_SYSTEM_USER_PACKAGE_ALLOWLIST_PROBLEMS,
+                    ARG_V, ARG_VERBOSE, ARG_CRITICAL_ONLY, ARG_MODE);
+
+            pw.printf("%sReports all issues on user-type package allowlist XML files. Options:\n",
+                    PREFIX_HELP_DESCRIPTION);
+            pw.printf("%s%s | %s: shows extra info, like number of issues\n",
+                    PREFIX_HELP_DESCRIPTION, ARG_V, ARG_VERBOSE);
+            pw.printf("%s%s: show only critical issues, excluding warnings\n",
+                    PREFIX_HELP_DESCRIPTION, ARG_CRITICAL_ONLY);
+            pw.printf("%s%s MODE: shows what errors would be if device used mode MODE\n"
+                    + "%s(where MODE is the allowlist mode integer as defined by "
+                    + "config_userTypePackageWhitelistMode)\n\n",
+                    PREFIX_HELP_DESCRIPTION, ARG_MODE, PREFIX_HELP_DESCRIPTION_EXTRA_LINES);
         }
     }
 
diff --git a/services/core/java/com/android/server/pm/permission/OneTimePermissionUserManager.java b/services/core/java/com/android/server/pm/permission/OneTimePermissionUserManager.java
index 46fde4b..6060233 100644
--- a/services/core/java/com/android/server/pm/permission/OneTimePermissionUserManager.java
+++ b/services/core/java/com/android/server/pm/permission/OneTimePermissionUserManager.java
@@ -272,6 +272,10 @@
                 mHandler.removeCallbacksAndMessages(mToken);
 
                 if (importance > IMPORTANCE_CACHED) {
+                    if (mRevokeAfterKilledDelay == 0) {
+                        onPackageInactiveLocked();
+                        return;
+                    }
                     // Delay revocation in case app is restarting
                     mHandler.postDelayed(() -> {
                         int imp = mActivityManager.getUidImportance(mUid);
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 71554ee..5a05134b 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -562,12 +562,6 @@
     }
 
     @Override
-    public void revokeOwnPermissionsOnKill(@NonNull String packageName,
-            @NonNull List<String> permissions) {
-        mPermissionManagerServiceImpl.revokeOwnPermissionsOnKill(packageName, permissions);
-    }
-
-    @Override
     public boolean shouldShowRequestPermissionRationale(String packageName, String permissionName,
             int userId) {
         return mPermissionManagerServiceImpl.shouldShowRequestPermissionRationale(packageName,
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
index d060930..009d155 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
@@ -1597,25 +1597,6 @@
         }
     }
 
-    @Override
-    public void revokeOwnPermissionsOnKill(String packageName, List<String> permissions) {
-        final int callingUid = Binder.getCallingUid();
-        int callingUserId = UserHandle.getUserId(callingUid);
-        int targetPackageUid = mPackageManagerInt.getPackageUid(packageName, 0, callingUserId);
-        if (targetPackageUid != callingUid) {
-            throw new SecurityException("uid " + callingUid
-                    + " cannot revoke permissions for package " + packageName + " with uid "
-                    + targetPackageUid);
-        }
-        for (String permName : permissions) {
-            if (!checkCallingOrSelfPermission(permName)) {
-                throw new SecurityException("uid " + callingUid + " cannot revoke permission "
-                        + permName + " because it does not hold that permission");
-            }
-        }
-        mPermissionControllerManager.revokeOwnPermissionsOnKill(packageName, permissions);
-    }
-
     private boolean mayManageRolePermission(int uid) {
         final PackageManager packageManager = mContext.getPackageManager();
         final String[] packageNames = packageManager.getPackagesForUid(uid);
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java
index 3e28320..3771f03 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java
@@ -327,28 +327,6 @@
     void revokePostNotificationPermissionWithoutKillForTest(String packageName, int userId);
 
     /**
-     * Triggers the revocation of one or more permissions for a package, under the following
-     * conditions:
-     * <ul>
-     * <li>The package {@code packageName} must be under the same UID as the calling process
-     *   (typically, the target package is the calling package).
-     * <li>Each permission in {@code permissions} must be granted to the package
-     * {@code packageName}.
-     * <li>Each permission in {@code permissions} must be a runtime permission.
-     * </ul>
-     * <p>
-     * Background permissions which have no corresponding foreground permission still granted once
-     * the revocation is effective will also be revoked.
-     * <p>
-     * This revocation happens asynchronously and kills all processes running in the same UID as
-     * {@code packageName}. It will be triggered once it is safe to do so.
-     *
-     * @param packageName The name of the package for which the permissions will be revoked.
-     * @param permissions List of permissions to be revoked.
-     */
-    void revokeOwnPermissionsOnKill(String packageName, List<String> permissions);
-
-    /**
      * Get whether you should show UI with rationale for requesting a permission. You should do this
      * only if you do not have the permission and the context in which the permission is requested
      * does not clearly communicate to the user what would be the benefit from grating this
diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
index 2e60f13..526dccb 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -1633,7 +1633,14 @@
         if (adapter != null) {
             SynchronousResultReceiver bluetoothReceiver =
                     new SynchronousResultReceiver("bluetooth");
-            adapter.requestControllerActivityEnergyInfo(bluetoothReceiver);
+            adapter.requestControllerActivityEnergyInfo(
+                    Runnable::run,
+                    info -> {
+                        Bundle bundle = new Bundle();
+                        bundle.putParcelable(BatteryStats.RESULT_RECEIVER_CONTROLLER_KEY, info);
+                        bluetoothReceiver.send(0, bundle);
+                    }
+            );
             return awaitControllerInfo(bluetoothReceiver);
         } else {
             Slog.e(TAG, "Failed to get bluetooth adapter!");
@@ -2338,51 +2345,25 @@
     }
 
     int pullProcessDmabufMemory(int atomTag, List<StatsEvent> pulledData) {
-        List<ProcessMemoryState> managedProcessList =
-                LocalServices.getService(ActivityManagerInternal.class)
-                        .getMemoryStateForProcesses();
-        for (ProcessMemoryState process : managedProcessList) {
-            KernelAllocationStats.ProcessDmabuf proc =
-                    KernelAllocationStats.getDmabufAllocations(process.pid);
-            if (proc == null || (proc.retainedBuffersCount <= 0 && proc.mappedBuffersCount <= 0)) {
-                continue;
-            }
-            pulledData.add(
-                    FrameworkStatsLog.buildStatsEvent(
-                            atomTag,
-                            process.uid,
-                            process.processName,
-                            process.oomScore,
-                            proc.retainedSizeKb,
-                            proc.retainedBuffersCount,
-                            proc.mappedSizeKb,
-                            proc.mappedBuffersCount));
+        KernelAllocationStats.ProcessDmabuf[] procBufs =
+                KernelAllocationStats.getDmabufAllocations();
+
+        if (procBufs == null) {
+            return StatsManager.PULL_SKIP;
         }
-        SparseArray<String> processCmdlines = getProcessCmdlines();
-        managedProcessList.forEach(managedProcess -> processCmdlines.delete(managedProcess.pid));
-        int size = processCmdlines.size();
-        for (int i = 0; i < size; ++i) {
-            int pid = processCmdlines.keyAt(i);
-            int uid = getUidForPid(pid);
-            // ignore root processes (unlikely to be interesting)
-            if (uid <= 0) {
-                continue;
-            }
-            KernelAllocationStats.ProcessDmabuf proc =
-                    KernelAllocationStats.getDmabufAllocations(pid);
-            if (proc == null || (proc.retainedBuffersCount <= 0 && proc.mappedBuffersCount <= 0)) {
-                continue;
-            }
-            pulledData.add(
-                    FrameworkStatsLog.buildStatsEvent(
-                            atomTag,
-                            uid,
-                            processCmdlines.valueAt(i),
-                            -1001 /*Placeholder for native processes, OOM_SCORE_ADJ_MIN - 1.*/,
-                            proc.retainedSizeKb,
-                            proc.retainedBuffersCount,
-                            proc.mappedSizeKb,
-                            proc.mappedBuffersCount));
+        for (KernelAllocationStats.ProcessDmabuf procBuf : procBufs) {
+            pulledData.add(FrameworkStatsLog.buildStatsEvent(
+                    atomTag,
+                    procBuf.uid,
+                    procBuf.processName,
+                    procBuf.oomScore,
+                    procBuf.retainedSizeKb,
+                    procBuf.retainedBuffersCount,
+                    0, /* mapped_dmabuf_kb - deprecated */
+                    0, /* mapped_dmabuf_count - deprecated */
+                    procBuf.surfaceFlingerSizeKb,
+                    procBuf.surfaceFlingerCount
+            ));
         }
         return StatsManager.PULL_SUCCESS;
     }
diff --git a/services/core/java/com/android/server/utils/TimingsTraceAndSlog.java b/services/core/java/com/android/server/utils/TimingsTraceAndSlog.java
index 397acfa..b45c962 100644
--- a/services/core/java/com/android/server/utils/TimingsTraceAndSlog.java
+++ b/services/core/java/com/android/server/utils/TimingsTraceAndSlog.java
@@ -88,7 +88,7 @@
 
     @Override
     public void traceBegin(@NonNull String name) {
-        Slog.i(mTag, name);
+        Slog.d(mTag, name);
         super.traceBegin(name);
     }
 
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 883ce99..bfe1f30 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -5603,19 +5603,8 @@
                     "makeInvisible", true /* beforeStopping */);
             // Defer telling the client it is hidden if it can enter Pip and isn't current paused,
             // stopped or stopping. This gives it a chance to enter Pip in onPause().
-            // TODO: There is still a question surrounding activities in multi-window mode that want
-            // to enter Pip after they are paused, but are still visible. I they should be okay to
-            // enter Pip in those cases, but not "auto-Pip" which is what this condition covers and
-            // the current contract for "auto-Pip" is that the app should enter it before onPause
-            // returns. Just need to confirm this reasoning makes sense.
             final boolean deferHidingClient = canEnterPictureInPicture
                     && !isState(STARTED, STOPPING, STOPPED, PAUSED);
-            if (!mTransitionController.isShellTransitionsEnabled()
-                    && deferHidingClient && pictureInPictureArgs.isAutoEnterEnabled()) {
-                // Go ahead and just put the activity in pip if it supports auto-pip.
-                mAtmService.enterPictureInPictureMode(this, pictureInPictureArgs);
-                return;
-            }
             setDeferHidingClient(deferHidingClient);
             setVisibility(false);
 
diff --git a/services/core/java/com/android/server/wm/ContentRecorder.java b/services/core/java/com/android/server/wm/ContentRecorder.java
index 07a0c37..87523f4 100644
--- a/services/core/java/com/android/server/wm/ContentRecorder.java
+++ b/services/core/java/com/android/server/wm/ContentRecorder.java
@@ -17,6 +17,7 @@
 package com.android.server.wm;
 
 import static android.view.ContentRecordingSession.RECORD_CONTENT_DISPLAY;
+import static android.view.ContentRecordingSession.RECORD_CONTENT_TASK;
 
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONTENT_RECORDING;
 
@@ -26,6 +27,7 @@
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.os.IBinder;
+import android.provider.DeviceConfig;
 import android.view.ContentRecordingSession;
 import android.view.Display;
 import android.view.SurfaceControl;
@@ -39,6 +41,11 @@
 final class ContentRecorder {
 
     /**
+     * The key for accessing the device config that controls if task recording is supported.
+     */
+    @VisibleForTesting static final String KEY_RECORD_TASK_FEATURE = "record_task_content";
+
+    /**
      * The display content this class is handling recording for.
      */
     @NonNull
@@ -48,7 +55,7 @@
      * The session for content recording, or null if this DisplayContent is not being used for
      * recording.
      */
-    @VisibleForTesting private ContentRecordingSession mContentRecordingSession = null;
+    private ContentRecordingSession mContentRecordingSession = null;
 
     /**
      * The WindowContainer for the level of the hierarchy to record.
@@ -187,6 +194,8 @@
             mDisplayContent.mWmService.mTransactionFactory.get().remove(mRecordedSurface).apply();
             mRecordedSurface = null;
             clearContentRecordingSession();
+            // Do not need to force remove the VirtualDisplay; this is handled by the media
+            // projection service.
         }
     }
 
@@ -215,46 +224,12 @@
             return;
         }
 
-        final int contentToRecord = mContentRecordingSession.getContentToRecord();
-        if (contentToRecord != RECORD_CONTENT_DISPLAY) {
-            // TODO(b/216625226) handle task-based recording
-            // Not a valid region, or recording is disabled, so fall back to prior MediaProjection
-            // approach.
-            clearContentRecordingSession();
-            ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
-                    "Unable to start recording due to invalid region for display %d",
-                    mDisplayContent.getDisplayId());
+        mRecordedWindowContainer = retrieveRecordedWindowContainer();
+        if (mRecordedWindowContainer == null) {
+            // Either the token is missing, or the window associated with the token is missing.
+            // Error has already been handled, so just leave.
             return;
         }
-        // Given the WindowToken of the DisplayArea to record, retrieve the associated
-        // SurfaceControl.
-        IBinder tokenToRecord = mContentRecordingSession.getTokenToRecord();
-        if (tokenToRecord == null) {
-            // Unexpectedly missing token. Fall back to prior MediaProjection approach.
-            clearContentRecordingSession();
-            ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
-                    "Unable to start recording due to null token for display %d",
-                    mDisplayContent.getDisplayId());
-            return;
-        }
-
-        final WindowContainer wc =
-                mDisplayContent.mWmService.mWindowContextListenerController.getContainer(
-                        tokenToRecord);
-        if (wc == null) {
-            // Un-set the window token to record for this VirtualDisplay. Fall back to the
-            // original MediaProjection approach.
-            mDisplayContent.mWmService.mDisplayManagerInternal.setWindowManagerMirroring(
-                    mDisplayContent.getDisplayId(), false);
-            clearContentRecordingSession();
-            ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
-                    "Unable to retrieve window container to start recording for "
-                            + "display %d",
-                    mDisplayContent.getDisplayId());
-            return;
-        }
-        // TODO(206461622) Migrate to using the RootDisplayArea
-        mRecordedWindowContainer = wc.getDisplayContent();
 
         final Point surfaceSize = fetchSurfaceSizeIfPresent();
         if (surfaceSize == null) {
@@ -296,6 +271,107 @@
     }
 
     /**
+     * Retrieves the {@link WindowContainer} for the level of the hierarchy to start recording,
+     * indicated by the {@link #mContentRecordingSession}. Performs any error handling and state
+     * updates necessary if the {@link WindowContainer} could not be retrieved.
+     * {@link #mContentRecordingSession} must be non-null.
+     *
+     * @return a {@link WindowContainer} to record, or {@code null} if an error was encountered. The
+     * error is logged and any cleanup is handled.
+     */
+    @Nullable
+    private WindowContainer retrieveRecordedWindowContainer() {
+        final int contentToRecord = mContentRecordingSession.getContentToRecord();
+        // Given the WindowToken of the region to record, retrieve the associated
+        // SurfaceControl.
+        final IBinder tokenToRecord = mContentRecordingSession.getTokenToRecord();
+        if (tokenToRecord == null) {
+            handleStartRecordingFailed();
+            ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
+                    "Unable to start recording due to null token for display %d",
+                    mDisplayContent.getDisplayId());
+            return null;
+        }
+        switch (contentToRecord) {
+            case RECORD_CONTENT_DISPLAY:
+                final WindowContainer wc =
+                        mDisplayContent.mWmService.mWindowContextListenerController.getContainer(
+                                tokenToRecord);
+                if (wc == null) {
+                    // Un-set the window token to record for this VirtualDisplay. Fall back to
+                    // Display stack capture for the entire display.
+                    mDisplayContent.mWmService.mDisplayManagerInternal.setWindowManagerMirroring(
+                            mDisplayContent.getDisplayId(), false);
+                    handleStartRecordingFailed();
+                    ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
+                            "Unable to retrieve window container to start recording for "
+                                    + "display %d", mDisplayContent.getDisplayId());
+                    return null;
+                }
+                // TODO(206461622) Migrate to using the RootDisplayArea
+                return wc.getDisplayContent();
+            case RECORD_CONTENT_TASK:
+                if (!DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_WINDOW_MANAGER,
+                        KEY_RECORD_TASK_FEATURE, false)) {
+                    handleStartRecordingFailed();
+                    ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
+                            "Unable to record task since feature is disabled %d",
+                            mDisplayContent.getDisplayId());
+                    return null;
+                }
+                Task taskToRecord = WindowContainer.fromBinder(tokenToRecord).asTask();
+                if (taskToRecord == null) {
+                    handleStartRecordingFailed();
+                    ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
+                            "Unable to retrieve task to start recording for "
+                                    + "display %d", mDisplayContent.getDisplayId());
+                }
+                return taskToRecord;
+            default:
+                // Not a valid region, or recording is disabled, so fall back to Display stack
+                // capture for the entire display.
+                handleStartRecordingFailed();
+                ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
+                        "Unable to start recording due to invalid region for display %d",
+                        mDisplayContent.getDisplayId());
+                return null;
+        }
+    }
+
+    /**
+     * Exit this recording session.
+     * <p>
+     * If this is a task session, tear down the recording entirely. Do not fall back
+     * to recording the entire display on the display stack; this would surprise the user
+     * given they selected task capture.
+     * </p><p>
+     * If this is a display session, just stop recording by layer mirroring. Fall back to recording
+     * from the display stack.
+     * </p>
+     */
+    private void handleStartRecordingFailed() {
+        final boolean shouldExitTaskRecording = mContentRecordingSession != null
+                && mContentRecordingSession.getContentToRecord() == RECORD_CONTENT_TASK;
+        if (shouldExitTaskRecording) {
+            // Clean up the cached session first, since tearing down the display will generate
+            // display
+            // events which will trickle back to here.
+            clearContentRecordingSession();
+            tearDownVirtualDisplay();
+        } else {
+            clearContentRecordingSession();
+        }
+    }
+
+    /**
+     * Ensure recording does not fall back to the display stack; ensure the recording is stopped
+     * and the client notified by tearing down the virtual display.
+     */
+    private void tearDownVirtualDisplay() {
+        // TODO(b/219761722) Clean up the VirtualDisplay if task mirroring fails
+    }
+
+    /**
      * Apply transformations to the mirrored surface to ensure the captured contents are scaled to
      * fit and centred in the output surface.
      *
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index d187bd6..2ac41a7 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -1459,7 +1459,8 @@
             // next activity.
             final boolean lastResumedCanPip = prev.checkEnterPictureInPictureState(
                     "shouldAutoPipWhilePausing", userLeaving);
-            if (lastResumedCanPip && prev.pictureInPictureArgs.isAutoEnterEnabled()) {
+            if (userLeaving && lastResumedCanPip
+                    && prev.pictureInPictureArgs.isAutoEnterEnabled()) {
                 shouldAutoPip = true;
             } else if (!lastResumedCanPip) {
                 // If the flag RESUME_WHILE_PAUSING is set, then continue to schedule the previous
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index c50888b..eb88b8b 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -3278,7 +3278,7 @@
         mContext.enforceCallingOrSelfPermission(
                 Manifest.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE,
                 Manifest.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE
-                        + " permission required to read keyguard visibility");
+                        + " permission required to subscribe to keyguard locked state changes");
     }
 
     private void dispatchKeyguardLockedState() {
diff --git a/services/core/jni/gnss/MeasurementCorrections.cpp b/services/core/jni/gnss/MeasurementCorrections.cpp
index 8a3d84c..07d0a45 100644
--- a/services/core/jni/gnss/MeasurementCorrections.cpp
+++ b/services/core/jni/gnss/MeasurementCorrections.cpp
@@ -44,6 +44,7 @@
 using ReflectingPlane_V1_0 =
         android::hardware::gnss::measurement_corrections::V1_0::ReflectingPlane;
 using ReflectingPlane_Aidl = android::hardware::gnss::measurement_corrections::ReflectingPlane;
+using ExcessPathInfo = SingleSatCorrection_Aidl::ExcessPathInfo;
 using GnssConstellationType_V1_0 = android::hardware::gnss::V1_0::GnssConstellationType;
 using GnssConstellationType_V2_0 = android::hardware::gnss::V2_0::GnssConstellationType;
 using GnssConstellationType_Aidl = android::hardware::gnss::GnssConstellationType;
@@ -62,7 +63,7 @@
 jmethodID method_correctionsGetEnvironmentBearingDegrees;
 jmethodID method_correctionsGetEnvironmentBearingUncertaintyDegrees;
 jmethodID method_listSize;
-jmethodID method_correctionListGet;
+jmethodID method_listGet;
 jmethodID method_correctionSatFlags;
 jmethodID method_correctionSatConstType;
 jmethodID method_correctionSatId;
@@ -71,10 +72,17 @@
 jmethodID method_correctionSatEpl;
 jmethodID method_correctionSatEplUnc;
 jmethodID method_correctionSatRefPlane;
+jmethodID method_correctionSatAttenuation;
+jmethodID method_correctionSatExcessPathInfoList;
 jmethodID method_correctionPlaneLatDeg;
 jmethodID method_correctionPlaneLngDeg;
 jmethodID method_correctionPlaneAltDeg;
 jmethodID method_correctionPlaneAzimDeg;
+jmethodID method_excessPathInfoFlags;
+jmethodID method_excessPathInfoEpl;
+jmethodID method_excessPathInfoEplUnc;
+jmethodID method_excessPathInfoRefPlane;
+jmethodID method_excessPathInfoAttenuation;
 } // anonymous namespace
 
 void MeasurementCorrections_class_init_once(JNIEnv* env, jclass clazz) {
@@ -103,7 +111,7 @@
 
     jclass corrListClass = env->FindClass("java/util/List");
     method_listSize = env->GetMethodID(corrListClass, "size", "()I");
-    method_correctionListGet = env->GetMethodID(corrListClass, "get", "(I)Ljava/lang/Object;");
+    method_listGet = env->GetMethodID(corrListClass, "get", "(I)Ljava/lang/Object;");
 
     jclass singleSatCorrClass = env->FindClass("android/location/GnssSingleSatCorrection");
     method_correctionSatFlags =
@@ -121,12 +129,27 @@
             env->GetMethodID(singleSatCorrClass, "getExcessPathLengthUncertaintyMeters", "()F");
     method_correctionSatRefPlane = env->GetMethodID(singleSatCorrClass, "getReflectingPlane",
                                                     "()Landroid/location/GnssReflectingPlane;");
+    method_correctionSatAttenuation =
+            env->GetMethodID(singleSatCorrClass, "getCombinedAttenuationDb", "()F");
+    method_correctionSatExcessPathInfoList =
+            env->GetMethodID(singleSatCorrClass, "getGnssExcessPathInfoList", "()Ljava/util/List;");
 
     jclass refPlaneClass = env->FindClass("android/location/GnssReflectingPlane");
     method_correctionPlaneLatDeg = env->GetMethodID(refPlaneClass, "getLatitudeDegrees", "()D");
     method_correctionPlaneLngDeg = env->GetMethodID(refPlaneClass, "getLongitudeDegrees", "()D");
     method_correctionPlaneAltDeg = env->GetMethodID(refPlaneClass, "getAltitudeMeters", "()D");
     method_correctionPlaneAzimDeg = env->GetMethodID(refPlaneClass, "getAzimuthDegrees", "()D");
+
+    jclass excessPathInfoClass = env->FindClass("android/location/GnssExcessPathInfo");
+    method_excessPathInfoFlags = env->GetMethodID(excessPathInfoClass, "getFlags", "()I");
+    method_excessPathInfoEpl =
+            env->GetMethodID(excessPathInfoClass, "getExcessPathLengthMeters", "()F");
+    method_excessPathInfoEplUnc =
+            env->GetMethodID(excessPathInfoClass, "getExcessPathLengthUncertaintyMeters", "()F");
+    method_excessPathInfoRefPlane = env->GetMethodID(excessPathInfoClass, "getReflectingPlane",
+                                                     "()Landroid/location/GnssReflectingPlane;");
+    method_excessPathInfoAttenuation =
+            env->GetMethodID(excessPathInfoClass, "getAttenuationDb", "()F");
 }
 
 template <>
@@ -324,7 +347,8 @@
 SingleSatCorrection_V1_0
 MeasurementCorrectionsUtil::getSingleSatCorrection_1_0_withoutConstellation(
         JNIEnv* env, jobject singleSatCorrectionObj) {
-    jint correctionFlags = env->CallIntMethod(singleSatCorrectionObj, method_correctionSatFlags);
+    uint16_t corrFlags = static_cast<uint16_t>(
+            env->CallIntMethod(singleSatCorrectionObj, method_correctionSatFlags));
     jint satId = env->CallIntMethod(singleSatCorrectionObj, method_correctionSatId);
     jfloat carrierFreqHz =
             env->CallFloatMethod(singleSatCorrectionObj, method_correctionSatCarrierFreq);
@@ -332,14 +356,16 @@
             env->CallFloatMethod(singleSatCorrectionObj, method_correctionSatIsLosProb);
     jfloat eplMeters = env->CallFloatMethod(singleSatCorrectionObj, method_correctionSatEpl);
     jfloat eplUncMeters = env->CallFloatMethod(singleSatCorrectionObj, method_correctionSatEplUnc);
-    uint16_t corrFlags = static_cast<uint16_t>(correctionFlags);
 
     ReflectingPlane_V1_0 reflectingPlane;
-    if ((corrFlags & GnssSingleSatCorrectionFlags_V1_0::HAS_REFLECTING_PLANE) != 0)
-        MeasurementCorrectionsUtil::getReflectingPlane<ReflectingPlane_V1_0>(env,
-                                                                             singleSatCorrectionObj,
+    if ((corrFlags & GnssSingleSatCorrectionFlags_V1_0::HAS_REFLECTING_PLANE) != 0) {
+        jobject reflectingPlaneObj =
+                env->CallObjectMethod(singleSatCorrectionObj, method_correctionSatRefPlane);
+        MeasurementCorrectionsUtil::setReflectingPlane<ReflectingPlane_V1_0>(env,
+                                                                             reflectingPlaneObj,
                                                                              reflectingPlane);
-
+        env->DeleteLocalRef(reflectingPlaneObj);
+    }
     SingleSatCorrection_V1_0 singleSatCorrection = {
             .singleSatCorrectionFlags = corrFlags,
             .svid = static_cast<uint16_t>(satId),
@@ -349,13 +375,14 @@
             .excessPathLengthUncertaintyMeters = eplUncMeters,
             .reflectingPlane = reflectingPlane,
     };
-
     return singleSatCorrection;
 }
 
 SingleSatCorrection_Aidl MeasurementCorrectionsUtil::getSingleSatCorrection_Aidl(
         JNIEnv* env, jobject singleSatCorrectionObj) {
-    jint correctionFlags = env->CallIntMethod(singleSatCorrectionObj, method_correctionSatFlags);
+    int32_t corrFlags = static_cast<int32_t>(
+            env->CallIntMethod(singleSatCorrectionObj, method_correctionSatFlags));
+    jint constType = env->CallIntMethod(singleSatCorrectionObj, method_correctionSatConstType);
     jint satId = env->CallIntMethod(singleSatCorrectionObj, method_correctionSatId);
     jfloat carrierFreqHz =
             env->CallFloatMethod(singleSatCorrectionObj, method_correctionSatCarrierFreq);
@@ -363,15 +390,10 @@
             env->CallFloatMethod(singleSatCorrectionObj, method_correctionSatIsLosProb);
     jfloat eplMeters = env->CallFloatMethod(singleSatCorrectionObj, method_correctionSatEpl);
     jfloat eplUncMeters = env->CallFloatMethod(singleSatCorrectionObj, method_correctionSatEplUnc);
-    int32_t corrFlags = static_cast<int32_t>(correctionFlags);
-
-    ReflectingPlane_Aidl reflectingPlane;
-    if ((corrFlags & SingleSatCorrection_Aidl::SINGLE_SAT_CORRECTION_HAS_REFLECTING_PLANE) != 0)
-        MeasurementCorrectionsUtil::getReflectingPlane<ReflectingPlane_Aidl>(env,
-                                                                             singleSatCorrectionObj,
-                                                                             reflectingPlane);
-
-    jint constType = env->CallIntMethod(singleSatCorrectionObj, method_correctionSatConstType);
+    jfloat attenuationDb =
+            env->CallFloatMethod(singleSatCorrectionObj, method_correctionSatAttenuation);
+    std::vector<ExcessPathInfo> excessPathInfos =
+            MeasurementCorrectionsUtil::getExcessPathInfoList(env, singleSatCorrectionObj);
 
     SingleSatCorrection_Aidl singleSatCorrection;
     singleSatCorrection.singleSatCorrectionFlags = corrFlags;
@@ -379,9 +401,10 @@
     singleSatCorrection.svid = static_cast<int32_t>(satId);
     singleSatCorrection.carrierFrequencyHz = carrierFreqHz;
     singleSatCorrection.probSatIsLos = probSatIsLos;
-    singleSatCorrection.excessPathLengthMeters = eplMeters;
-    singleSatCorrection.excessPathLengthUncertaintyMeters = eplUncMeters;
-    singleSatCorrection.reflectingPlane = reflectingPlane;
+    singleSatCorrection.combinedExcessPathLengthMeters = eplMeters;
+    singleSatCorrection.combinedExcessPathLengthUncertaintyMeters = eplUncMeters;
+    singleSatCorrection.combinedAttenuationDb = attenuationDb;
+    singleSatCorrection.excessPathInfos = excessPathInfos;
 
     return singleSatCorrection;
 }
@@ -391,8 +414,7 @@
         hardware::hidl_vec<SingleSatCorrection_V1_0>& list) {
     for (uint16_t i = 0; i < list.size(); ++i) {
         jobject singleSatCorrectionObj =
-                env->CallObjectMethod(singleSatCorrectionList, method_correctionListGet, i);
-
+                env->CallObjectMethod(singleSatCorrectionList, method_listGet, i);
         SingleSatCorrection_V1_0 singleSatCorrection =
                 getSingleSatCorrection_1_0_withoutConstellation(env, singleSatCorrectionObj);
 
@@ -410,7 +432,7 @@
         hardware::hidl_vec<SingleSatCorrection_V1_1>& list) {
     for (uint16_t i = 0; i < list.size(); ++i) {
         jobject singleSatCorrectionObj =
-                env->CallObjectMethod(singleSatCorrectionList, method_correctionListGet, i);
+                env->CallObjectMethod(singleSatCorrectionList, method_listGet, i);
 
         SingleSatCorrection_V1_0 singleSatCorrection_1_0 =
                 getSingleSatCorrection_1_0_withoutConstellation(env, singleSatCorrectionObj);
@@ -431,7 +453,7 @@
         JNIEnv* env, jobject singleSatCorrectionList, std::vector<SingleSatCorrection_Aidl>& list) {
     for (uint16_t i = 0; i < list.size(); ++i) {
         jobject singleSatCorrectionObj =
-                env->CallObjectMethod(singleSatCorrectionList, method_correctionListGet, i);
+                env->CallObjectMethod(singleSatCorrectionList, method_listGet, i);
 
         SingleSatCorrection_Aidl singleSatCorrection_Aidl =
                 getSingleSatCorrection_Aidl(env, singleSatCorrectionObj);
@@ -441,4 +463,63 @@
     }
 }
 
+template <>
+void MeasurementCorrectionsUtil::setReflectingPlaneAzimuthDegrees<ReflectingPlane_V1_0>(
+        ReflectingPlane_V1_0& reflectingPlane, double azimuthDegreeRefPlane) {
+    reflectingPlane.azimuthDegrees = azimuthDegreeRefPlane;
+}
+
+template <>
+void MeasurementCorrectionsUtil::setReflectingPlaneAzimuthDegrees<ReflectingPlane_Aidl>(
+        ReflectingPlane_Aidl& reflectingPlane, double azimuthDegreeRefPlane) {
+    reflectingPlane.reflectingPlaneAzimuthDegrees = azimuthDegreeRefPlane;
+}
+
+std::vector<ExcessPathInfo> MeasurementCorrectionsUtil::getExcessPathInfoList(
+        JNIEnv* env, jobject singleSatCorrectionObj) {
+    jobject excessPathInfoListObj =
+            env->CallObjectMethod(singleSatCorrectionObj, method_correctionSatExcessPathInfoList);
+
+    int len = env->CallIntMethod(excessPathInfoListObj, method_listSize);
+    std::vector<ExcessPathInfo> list(len);
+    for (int i = 0; i < len; ++i) {
+        jobject excessPathInfoObj = env->CallObjectMethod(excessPathInfoListObj, method_listGet, i);
+        list[i] = getExcessPathInfo(env, excessPathInfoObj);
+        env->DeleteLocalRef(excessPathInfoObj);
+    }
+    env->DeleteLocalRef(excessPathInfoListObj);
+    return list;
+}
+
+ExcessPathInfo MeasurementCorrectionsUtil::getExcessPathInfo(JNIEnv* env,
+                                                             jobject excessPathInfoObj) {
+    ExcessPathInfo excessPathInfo;
+    jint flags = env->CallIntMethod(excessPathInfoObj, method_excessPathInfoFlags);
+    excessPathInfo.excessPathInfoFlags = flags;
+    if ((flags & ExcessPathInfo::EXCESS_PATH_INFO_HAS_EXCESS_PATH_LENGTH) != 0) {
+        jfloat epl = env->CallFloatMethod(excessPathInfoObj, method_excessPathInfoEpl);
+        excessPathInfo.excessPathLengthMeters = epl;
+    }
+    if ((flags & ExcessPathInfo::EXCESS_PATH_INFO_HAS_EXCESS_PATH_LENGTH_UNC) != 0) {
+        jfloat eplUnc = env->CallFloatMethod(excessPathInfoObj, method_excessPathInfoEplUnc);
+        excessPathInfo.excessPathLengthUncertaintyMeters = eplUnc;
+    }
+    if ((flags & ExcessPathInfo::EXCESS_PATH_INFO_HAS_REFLECTING_PLANE) != 0) {
+        ReflectingPlane_Aidl reflectingPlane;
+        jobject reflectingPlaneObj =
+                env->CallObjectMethod(excessPathInfoObj, method_excessPathInfoRefPlane);
+        MeasurementCorrectionsUtil::setReflectingPlane<ReflectingPlane_Aidl>(env,
+                                                                             reflectingPlaneObj,
+                                                                             reflectingPlane);
+        env->DeleteLocalRef(reflectingPlaneObj);
+        excessPathInfo.reflectingPlane = reflectingPlane;
+    }
+    if ((flags & ExcessPathInfo::EXCESS_PATH_INFO_HAS_ATTENUATION) != 0) {
+        jfloat attenuation =
+                env->CallFloatMethod(excessPathInfoObj, method_excessPathInfoAttenuation);
+        excessPathInfo.attenuationDb = attenuation;
+    }
+    return excessPathInfo;
+}
+
 } // namespace android::gnss
diff --git a/services/core/jni/gnss/MeasurementCorrections.h b/services/core/jni/gnss/MeasurementCorrections.h
index a2e6027..598ad48 100644
--- a/services/core/jni/gnss/MeasurementCorrections.h
+++ b/services/core/jni/gnss/MeasurementCorrections.h
@@ -43,7 +43,7 @@
 extern jmethodID method_correctionsGetEnvironmentBearingDegrees;
 extern jmethodID method_correctionsGetEnvironmentBearingUncertaintyDegrees;
 extern jmethodID method_listSize;
-extern jmethodID method_correctionListGet;
+extern jmethodID method_listGet;
 extern jmethodID method_correctionSatFlags;
 extern jmethodID method_correctionSatConstType;
 extern jmethodID method_correctionSatId;
@@ -52,6 +52,7 @@
 extern jmethodID method_correctionSatEpl;
 extern jmethodID method_correctionSatEplUnc;
 extern jmethodID method_correctionSatRefPlane;
+extern jmethodID method_correctionSatExcessPathInfos;
 extern jmethodID method_correctionPlaneLatDeg;
 extern jmethodID method_correctionPlaneLngDeg;
 extern jmethodID method_correctionPlaneAltDeg;
@@ -130,14 +131,20 @@
     static bool translateMeasurementCorrections(JNIEnv* env, jobject correctionsObj,
                                                 T& corrections);
     template <class T>
-    static void getReflectingPlane(JNIEnv* env, jobject singleSatCorrectionObj, T& reflectingPlane);
+    static void setReflectingPlane(JNIEnv* env, jobject reflectingPlaneObj, T& reflectingPlane);
+    template <class T>
+    static void setReflectingPlaneAzimuthDegrees(T& reflectingPlane, double azimuthDegreeRefPlane);
+
+    static std::vector<
+            android::hardware::gnss::measurement_corrections::SingleSatCorrection::ExcessPathInfo>
+    getExcessPathInfoList(JNIEnv* env, jobject correctionsObj);
+    static android::hardware::gnss::measurement_corrections::SingleSatCorrection::ExcessPathInfo
+    getExcessPathInfo(JNIEnv* env, jobject correctionsObj);
 };
 
 template <class T>
-void MeasurementCorrectionsUtil::getReflectingPlane(JNIEnv* env, jobject singleSatCorrectionObj,
+void MeasurementCorrectionsUtil::setReflectingPlane(JNIEnv* env, jobject reflectingPlaneObj,
                                                     T& reflectingPlane) {
-    jobject reflectingPlaneObj =
-            env->CallObjectMethod(singleSatCorrectionObj, method_correctionSatRefPlane);
     jdouble latitudeDegreesRefPlane =
             env->CallDoubleMethod(reflectingPlaneObj, method_correctionPlaneLatDeg);
     jdouble longitudeDegreesRefPlane =
@@ -149,8 +156,7 @@
     reflectingPlane.latitudeDegrees = latitudeDegreesRefPlane;
     reflectingPlane.longitudeDegrees = longitudeDegreesRefPlane;
     reflectingPlane.altitudeMeters = altitudeDegreesRefPlane;
-    reflectingPlane.azimuthDegrees = azimuthDegreeRefPlane;
-    env->DeleteLocalRef(reflectingPlaneObj);
+    setReflectingPlaneAzimuthDegrees<T>(reflectingPlane, azimuthDegreeRefPlane);
 }
 
 } // namespace android::gnss
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/BackgroundDexOptServiceUnitTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/BackgroundDexOptServiceUnitTest.java
index 6f503c7..444db91 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/BackgroundDexOptServiceUnitTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/BackgroundDexOptServiceUnitTest.java
@@ -19,7 +19,9 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.argThat;
 import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.inOrder;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.timeout;
 import static org.mockito.Mockito.times;
@@ -36,23 +38,21 @@
 import android.content.IntentFilter;
 import android.os.HandlerThread;
 import android.os.PowerManager;
-import android.util.ArraySet;
 
 import com.android.server.LocalServices;
 import com.android.server.PinnerService;
 import com.android.server.pm.dex.DexManager;
-import com.android.server.pm.dex.DexoptOptions;
 
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
+import org.mockito.InOrder;
 import org.mockito.Mock;
 import org.mockito.junit.MockitoJUnitRunner;
 
 import java.util.Arrays;
-import java.util.HashMap;
 import java.util.List;
 import java.util.concurrent.CountDownLatch;
 import java.util.stream.Collectors;
@@ -66,9 +66,8 @@
 
     private static final long TEST_WAIT_TIMEOUT_MS = 10_000;
 
-    private static final ArraySet<String> DEFAULT_PACKAGE_LIST = new ArraySet<>(
-            Arrays.asList("aaa", "bbb"));
-    private static final ArraySet<String> EMPTY_PACKAGE_LIST = new ArraySet<>();
+    private static final List<String> DEFAULT_PACKAGE_LIST = List.of("aaa", "bbb");
+    private static final List<String> EMPTY_PACKAGE_LIST = List.of();
 
     @Mock
     private Context mContext;
@@ -116,9 +115,11 @@
         when(mInjector.getDataDirStorageLowBytes()).thenReturn(STORAGE_LOW_BYTES);
         when(mInjector.getDexOptThermalCutoff()).thenReturn(PowerManager.THERMAL_STATUS_CRITICAL);
         when(mInjector.getCurrentThermalStatus()).thenReturn(PowerManager.THERMAL_STATUS_NONE);
+        when(mInjector.supportSecondaryDex()).thenReturn(true);
         when(mDexOptHelper.getOptimizablePackages(any())).thenReturn(DEFAULT_PACKAGE_LIST);
         when(mDexOptHelper.performDexOptWithStatus(any())).thenReturn(
                 PackageDexOptimizer.DEX_OPT_PERFORMED);
+        when(mDexOptHelper.performDexOpt(any())).thenReturn(true);
 
         mService = new BackgroundDexOptService(mInjector);
     }
@@ -418,26 +419,16 @@
         verifyPerformDexOpt(DEFAULT_PACKAGE_LIST, totalJobRuns);
     }
 
-    private void verifyPerformDexOpt(ArraySet<String> pkgs, int expectedRuns) {
-        ArgumentCaptor<DexoptOptions> dexOptOptions = ArgumentCaptor.forClass(DexoptOptions.class);
-        verify(mDexOptHelper, atLeastOnce()).performDexOptWithStatus(dexOptOptions.capture());
-        HashMap<String, Integer> primaryPkgs = new HashMap<>(); // K: pkg, V: dexopt runs left
-        for (String pkg : pkgs) {
-            primaryPkgs.put(pkg, expectedRuns);
-        }
-
-        for (DexoptOptions opt : dexOptOptions.getAllValues()) {
-            assertThat(pkgs).contains(opt.getPackageName());
-            assertThat(opt.isDexoptOnlySecondaryDex()).isFalse();
-            Integer count = primaryPkgs.get(opt.getPackageName());
-            assertThat(count).isNotNull();
-            if (count == 1) {
-                primaryPkgs.remove(opt.getPackageName());
-            } else {
-                primaryPkgs.put(opt.getPackageName(), count - 1);
+    private void verifyPerformDexOpt(List<String> pkgs, int expectedRuns) {
+        InOrder inOrder = inOrder(mDexOptHelper);
+        for (int i = 0; i < expectedRuns; i++) {
+            for (String pkg : pkgs) {
+                inOrder.verify(mDexOptHelper, times(1)).performDexOptWithStatus(argThat((option) ->
+                        option.getPackageName().equals(pkg) && !option.isDexoptOnlySecondaryDex()));
+                inOrder.verify(mDexOptHelper, times(1)).performDexOpt(argThat((option) ->
+                        option.getPackageName().equals(pkg) && option.isDexoptOnlySecondaryDex()));
             }
         }
-        assertThat(primaryPkgs).isEmpty();
     }
 
     private static class StartAndWaitThread extends Thread {
diff --git a/services/tests/mockingservicestests/src/com/android/server/utils/TimingsTraceAndSlogTest.java b/services/tests/mockingservicestests/src/com/android/server/utils/TimingsTraceAndSlogTest.java
new file mode 100644
index 0000000..52cd29c
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/utils/TimingsTraceAndSlogTest.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2022 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.utils;
+
+import static android.os.Trace.TRACE_TAG_APP;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.contains;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Matchers.matches;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+
+import android.os.Trace;
+import android.util.Slog;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.dx.mockito.inline.extended.MockedVoidMethod;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.MockitoSession;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Tests for {@link TimingsTraceAndSlog}.
+ *
+ * <p>Usage: {@code atest FrameworksMockingServicesTests:TimingsTraceAndSlogTest}
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class TimingsTraceAndSlogTest {
+
+    private static final String TAG = "TEST";
+
+    private MockitoSession mSession;
+
+    @Before
+    public final void startMockSession() {
+        mSession = mockitoSession()
+                .spyStatic(Slog.class)
+                .spyStatic(Trace.class)
+                .startMocking();
+    }
+
+    @After
+    public final void finishMockSession() {
+        mSession.finishMocking();
+    }
+
+    @Test
+    public void testDifferentThreads() throws Exception {
+        TimingsTraceAndSlog log = new TimingsTraceAndSlog(TAG, TRACE_TAG_APP);
+        // Should be able to log on the same thread
+        log.traceBegin("test");
+        log.traceEnd();
+        final List<String> errors = new ArrayList<>();
+        // Calling from a different thread should fail
+        Thread t = new Thread(() -> {
+            try {
+                log.traceBegin("test");
+                errors.add("traceBegin should fail on a different thread");
+            } catch (IllegalStateException expected) {
+            }
+            try {
+                log.traceEnd();
+                errors.add("traceEnd should fail on a different thread");
+            } catch (IllegalStateException expected) {
+            }
+            // Verify that creating a new log will work
+            TimingsTraceAndSlog log2 = new TimingsTraceAndSlog(TAG, TRACE_TAG_APP);
+            log2.traceBegin("test");
+            log2.traceEnd();
+
+        });
+        t.start();
+        t.join();
+        assertThat(errors).isEmpty();
+    }
+
+    @Test
+    public void testGetUnfinishedTracesForDebug() {
+        TimingsTraceAndSlog log = new TimingsTraceAndSlog(TAG, TRACE_TAG_APP);
+        assertThat(log.getUnfinishedTracesForDebug()).isEmpty();
+
+        log.traceBegin("One");
+        assertThat(log.getUnfinishedTracesForDebug()).containsExactly("One").inOrder();
+
+        log.traceBegin("Two");
+        assertThat(log.getUnfinishedTracesForDebug()).containsExactly("One", "Two").inOrder();
+
+        log.traceEnd();
+        assertThat(log.getUnfinishedTracesForDebug()).containsExactly("One").inOrder();
+
+        log.traceEnd();
+        assertThat(log.getUnfinishedTracesForDebug()).isEmpty();
+    }
+
+    @Test
+    public void testLogDuration() throws Exception {
+        TimingsTraceAndSlog log = new TimingsTraceAndSlog(TAG, TRACE_TAG_APP);
+        log.logDuration("logro", 42);
+        verify((MockedVoidMethod) () -> Slog.v(eq(TAG), contains("logro took to complete: 42ms")));
+    }
+
+    @Test
+    public void testOneLevel() throws Exception {
+        TimingsTraceAndSlog log = new TimingsTraceAndSlog(TAG, TRACE_TAG_APP);
+        log.traceBegin("test");
+        log.traceEnd();
+
+        verify((MockedVoidMethod) () -> Trace.traceBegin(TRACE_TAG_APP, "test"));
+        verify((MockedVoidMethod) () -> Trace.traceEnd(TRACE_TAG_APP));
+        verify((MockedVoidMethod) () -> Slog.v(eq(TAG), matches("test took to complete: \\dms")));
+    }
+
+    @Test
+    public void testMultipleLevels() throws Exception {
+        TimingsTraceAndSlog log = new TimingsTraceAndSlog(TAG, TRACE_TAG_APP);
+        log.traceBegin("L1");
+        log.traceBegin("L2");
+        log.traceEnd();
+        log.traceEnd();
+
+        verify((MockedVoidMethod) () -> Trace.traceBegin(TRACE_TAG_APP, "L1"));
+        verify((MockedVoidMethod) () -> Trace.traceBegin(TRACE_TAG_APP, "L2"));
+        verify((MockedVoidMethod) () -> Trace.traceEnd(TRACE_TAG_APP), times(2)); // L1 and L2
+
+        verify((MockedVoidMethod) () -> Slog.v(eq(TAG), matches("L2 took to complete: \\d+ms")));
+        verify((MockedVoidMethod) () -> Slog.v(eq(TAG), matches("L1 took to complete: \\d+ms")));
+    }
+
+    @Test
+    public void testEndNoBegin() throws Exception {
+        TimingsTraceAndSlog log = new TimingsTraceAndSlog(TAG, TRACE_TAG_APP);
+        log.traceEnd();
+        verify((MockedVoidMethod) () -> Trace.traceEnd(TRACE_TAG_APP));
+        verify((MockedVoidMethod) () -> Slog.d(eq(TAG), anyString()), never());
+        verify((MockedVoidMethod) () -> Slog.w(TAG, "traceEnd called more times than traceBegin"));
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/display/ColorFadeTest.java b/services/tests/servicestests/src/com/android/server/display/ColorFadeTest.java
new file mode 100644
index 0000000..26a83a2
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/display/ColorFadeTest.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2022 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.display;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import static org.junit.Assert.assertFalse;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.hardware.display.DisplayManagerInternal;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.server.LocalServices;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class ColorFadeTest {
+    private static final int DISPLAY_ID = 123;
+
+    private Context mContext;
+
+    @Mock private DisplayManagerInternal mDisplayManagerInternalMock;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        addLocalServiceMock(DisplayManagerInternal.class, mDisplayManagerInternalMock);
+        mContext = getInstrumentation().getTargetContext();
+    }
+
+    @After
+    public void tearDown() {
+        LocalServices.removeServiceForTest(DisplayManagerInternal.class);
+    }
+
+    @Test
+    public void testPrepareColorFadeForInvalidDisplay() {
+        when(mDisplayManagerInternalMock.getDisplayInfo(eq(DISPLAY_ID))).thenReturn(null);
+        ColorFade colorFade = new ColorFade(DISPLAY_ID);
+        assertFalse(colorFade.prepare(mContext, ColorFade.MODE_FADE));
+    }
+
+    private static <T> void addLocalServiceMock(Class<T> clazz, T mock) {
+        LocalServices.removeServiceForTest(clazz);
+        LocalServices.addService(clazz, mock);
+    }
+
+}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java b/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java
index 50eefa0..c5117bb 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java
@@ -19,12 +19,12 @@
 
 import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR;
-import static android.view.ContentRecordingSession.RECORD_CONTENT_TASK;
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+import static com.android.server.wm.ContentRecorder.KEY_RECORD_TASK_FEATURE;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -40,17 +40,22 @@
 import android.os.Binder;
 import android.os.IBinder;
 import android.platform.test.annotations.Presubmit;
+import android.provider.DeviceConfig;
 import android.util.DisplayMetrics;
 import android.view.ContentRecordingSession;
 import android.view.Surface;
 import android.view.SurfaceControl;
 
+import androidx.annotation.NonNull;
 import androidx.test.filters.SmallTest;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.concurrent.CountDownLatch;
+
 /**
  * Tests for the {@link ContentRecorder} class.
  *
@@ -62,17 +67,18 @@
 @RunWith(WindowTestRunner.class)
 public class ContentRecorderTests extends WindowTestsBase {
     private static final IBinder TEST_TOKEN = new RecordingTestToken();
-    private final ContentRecordingSession mDefaultSession =
+    private static IBinder sTaskWindowContainerToken;
+    private final ContentRecordingSession mDisplaySession =
             ContentRecordingSession.createDisplaySession(TEST_TOKEN);
+    private ContentRecordingSession mTaskSession;
     private static Point sSurfaceSize;
     private ContentRecorder mContentRecorder;
     private SurfaceControl mRecordedSurface;
+    // Handle feature flag.
+    private ConfigListener mConfigListener;
+    private CountDownLatch mLatch;
 
     @Before public void setUp() {
-        // GIVEN MediaProjection has already initialized the WindowToken of the DisplayArea to
-        // mirror.
-        setUpDefaultTaskDisplayAreaWindowToken();
-
         // GIVEN SurfaceControl can successfully mirror the provided surface.
         sSurfaceSize = new Point(
                 mDefaultDisplay.getDefaultTaskDisplayArea().getBounds().width(),
@@ -84,12 +90,32 @@
                 sSurfaceSize.x, sSurfaceSize.y,
                 DisplayMetrics.DENSITY_140, new Surface(), VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR);
         final int displayId = virtualDisplay.getDisplay().getDisplayId();
-        mDefaultSession.setDisplayId(displayId);
-
         mWm.mRoot.onDisplayAdded(displayId);
-        final DisplayContent mVirtualDisplayContent = mWm.mRoot.getDisplayContent(displayId);
-        mContentRecorder = new ContentRecorder(mVirtualDisplayContent);
-        spyOn(mVirtualDisplayContent);
+        final DisplayContent virtualDisplayContent = mWm.mRoot.getDisplayContent(displayId);
+        mContentRecorder = new ContentRecorder(virtualDisplayContent);
+        spyOn(virtualDisplayContent);
+
+        // GIVEN MediaProjection has already initialized the WindowToken of the DisplayArea to
+        // record.
+        setUpDefaultTaskDisplayAreaWindowToken();
+        mDisplaySession.setDisplayId(displayId);
+
+        // GIVEN there is a window token associated with a task to record.
+        sTaskWindowContainerToken = setUpTaskWindowContainerToken(virtualDisplayContent);
+        mTaskSession = ContentRecordingSession.createTaskSession(sTaskWindowContainerToken);
+        mTaskSession.setDisplayId(displayId);
+
+        mConfigListener = new ConfigListener();
+        DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_WINDOW_MANAGER,
+                mContext.getMainExecutor(), mConfigListener);
+        mLatch = new CountDownLatch(1);
+        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_WINDOW_MANAGER, KEY_RECORD_TASK_FEATURE,
+                "true", true);
+    }
+
+    @After
+    public void teardown() {
+        DeviceConfig.removeOnPropertiesChangedListener(mConfigListener);
     }
 
     @Test
@@ -102,22 +128,74 @@
 
     @Test
     public void testUpdateRecording_display() {
-        mContentRecorder.setContentRecordingSession(mDefaultSession);
+        mContentRecorder.setContentRecordingSession(mDisplaySession);
         mContentRecorder.updateRecording();
         assertThat(mContentRecorder.isCurrentlyRecording()).isTrue();
     }
 
     @Test
-    public void testUpdateRecording_task() {
-        mDefaultSession.setContentToRecord(RECORD_CONTENT_TASK);
-        mContentRecorder.setContentRecordingSession(mDefaultSession);
+    public void testUpdateRecording_display_nullToken() {
+        ContentRecordingSession session = ContentRecordingSession.createDisplaySession(TEST_TOKEN);
+        session.setDisplayId(mDisplaySession.getDisplayId());
+        session.setTokenToRecord(null);
+        mContentRecorder.setContentRecordingSession(session);
         mContentRecorder.updateRecording();
         assertThat(mContentRecorder.isCurrentlyRecording()).isFalse();
     }
 
     @Test
+    public void testUpdateRecording_display_noWindowContainer() {
+        doReturn(null).when(
+                mWm.mWindowContextListenerController).getContainer(any());
+        mContentRecorder.setContentRecordingSession(mDisplaySession);
+        mContentRecorder.updateRecording();
+        assertThat(mContentRecorder.isCurrentlyRecording()).isFalse();
+    }
+
+    @Test
+    public void testUpdateRecording_task_featureDisabled() {
+        mLatch = new CountDownLatch(1);
+        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_WINDOW_MANAGER, KEY_RECORD_TASK_FEATURE,
+                "false", false);
+        mContentRecorder.setContentRecordingSession(mTaskSession);
+        mContentRecorder.updateRecording();
+        assertThat(mContentRecorder.isCurrentlyRecording()).isFalse();
+    }
+
+    @Test
+    public void testUpdateRecording_task_featureEnabled() {
+        // Feature already enabled; don't need to again.
+        mContentRecorder.setContentRecordingSession(mTaskSession);
+        mContentRecorder.updateRecording();
+        assertThat(mContentRecorder.isCurrentlyRecording()).isTrue();
+    }
+
+    @Test
+    public void testUpdateRecording_task_nullToken() {
+        ContentRecordingSession session = ContentRecordingSession.createTaskSession(
+                sTaskWindowContainerToken);
+        session.setDisplayId(mDisplaySession.getDisplayId());
+        session.setTokenToRecord(null);
+        mContentRecorder.setContentRecordingSession(session);
+        mContentRecorder.updateRecording();
+        assertThat(mContentRecorder.isCurrentlyRecording()).isFalse();
+        // TODO(b/219761722) validate VirtualDisplay is torn down when can't set up task recording.
+    }
+
+    @Test
+    public void testUpdateRecording_task_noWindowContainer() {
+        // Use the window container token of the DisplayContent, rather than task.
+        ContentRecordingSession invalidTaskSession = ContentRecordingSession.createTaskSession(
+                new WindowContainer.RemoteToken(mDisplayContent));
+        mContentRecorder.setContentRecordingSession(invalidTaskSession);
+        mContentRecorder.updateRecording();
+        assertThat(mContentRecorder.isCurrentlyRecording()).isFalse();
+        // TODO(b/219761722) validate VirtualDisplay is torn down when can't set up task recording.
+    }
+
+    @Test
     public void testUpdateRecording_wasPaused() {
-        mContentRecorder.setContentRecordingSession(mDefaultSession);
+        mContentRecorder.setContentRecordingSession(mDisplaySession);
         mContentRecorder.updateRecording();
 
         mContentRecorder.pauseRecording();
@@ -126,16 +204,6 @@
     }
 
     @Test
-    public void testUpdateRecording_wasStopped() {
-        mContentRecorder.setContentRecordingSession(mDefaultSession);
-        mContentRecorder.updateRecording();
-
-        mContentRecorder.remove();
-        mContentRecorder.updateRecording();
-        assertThat(mContentRecorder.isCurrentlyRecording()).isFalse();
-    }
-
-    @Test
     public void testOnConfigurationChanged_neverRecording() {
         mContentRecorder.onConfigurationChanged(ORIENTATION_PORTRAIT);
 
@@ -146,7 +214,7 @@
 
     @Test
     public void testOnConfigurationChanged_resizesSurface() {
-        mContentRecorder.setContentRecordingSession(mDefaultSession);
+        mContentRecorder.setContentRecordingSession(mDisplaySession);
         mContentRecorder.updateRecording();
         mContentRecorder.onConfigurationChanged(ORIENTATION_PORTRAIT);
 
@@ -158,7 +226,7 @@
 
     @Test
     public void testPauseRecording_pausesRecording() {
-        mContentRecorder.setContentRecordingSession(mDefaultSession);
+        mContentRecorder.setContentRecordingSession(mDisplaySession);
         mContentRecorder.updateRecording();
 
         mContentRecorder.pauseRecording();
@@ -173,7 +241,7 @@
 
     @Test
     public void testRemove_stopsRecording() {
-        mContentRecorder.setContentRecordingSession(mDefaultSession);
+        mContentRecorder.setContentRecordingSession(mDisplaySession);
         mContentRecorder.updateRecording();
 
         mContentRecorder.remove();
@@ -188,8 +256,9 @@
 
     @Test
     public void testUpdateMirroredSurface_capturedAreaResized() {
-        mContentRecorder.setContentRecordingSession(mDefaultSession);
+        mContentRecorder.setContentRecordingSession(mDisplaySession);
         mContentRecorder.updateRecording();
+        assertThat(mContentRecorder.isCurrentlyRecording()).isTrue();
 
         // WHEN attempting to mirror on the virtual display, and the captured content is resized.
         float xScale = 0.7f;
@@ -197,13 +266,14 @@
         Rect displayAreaBounds = new Rect(0, 0, Math.round(sSurfaceSize.x * xScale),
                 Math.round(sSurfaceSize.y * yScale));
         mContentRecorder.updateMirroredSurface(mTransaction, displayAreaBounds, sSurfaceSize);
+        assertThat(mContentRecorder.isCurrentlyRecording()).isTrue();
 
         // THEN content in the captured DisplayArea is scaled to fit the surface size.
         verify(mTransaction, atLeastOnce()).setMatrix(mRecordedSurface, 1.0f / yScale, 0, 0,
                 1.0f / yScale);
         // THEN captured content is positioned in the centre of the output surface.
-        float scaledWidth = displayAreaBounds.width() / xScale;
-        float xInset = (sSurfaceSize.x - scaledWidth) / 2;
+        int scaledWidth = Math.round((float) displayAreaBounds.width() / xScale);
+        int xInset = (sSurfaceSize.x - scaledWidth) / 2;
         verify(mTransaction, atLeastOnce()).setPosition(mRecordedSurface, xInset, 0);
     }
 
@@ -222,6 +292,18 @@
     }
 
     /**
+     * Creates a {@link android.window.WindowContainerToken} associated with a task, in order for
+     * that task to be recorded.
+     */
+    private IBinder setUpTaskWindowContainerToken(DisplayContent displayContent) {
+        final Task rootTask = createTask(displayContent);
+        final Task task = createTaskInRootTask(rootTask, 0 /* userId */);
+        // Ensure the task is not empty.
+        createActivityRecord(displayContent, task);
+        return task.getTaskInfo().token.asBinder();
+    }
+
+    /**
      * SurfaceControl successfully creates a mirrored surface of the given size.
      */
     private SurfaceControl surfaceControlMirrors(Point surfaceSize) {
@@ -236,4 +318,13 @@
                 anyInt());
         return mirroredSurface;
     }
+
+    private class ConfigListener implements DeviceConfig.OnPropertiesChangedListener {
+        @Override
+        public void onPropertiesChanged(@NonNull DeviceConfig.Properties properties) {
+            if (mLatch != null && properties.getKeyset().contains(KEY_RECORD_TASK_FEATURE)) {
+                mLatch.countDown();
+            }
+        }
+    }
 }