Merge "Add CredDescRegistry unit tests" into udc-dev am: e334986d9b am: d2a4acedcc

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/21689143

Change-Id: I44343579d901e07480f214c5f46e94b88ae8c623
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/apct-tests/perftests/core/src/android/input/VelocityTrackerBenchmarkTest.kt b/apct-tests/perftests/core/src/android/input/VelocityTrackerBenchmarkTest.kt
new file mode 100644
index 0000000..13269eb
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/input/VelocityTrackerBenchmarkTest.kt
@@ -0,0 +1,258 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.input
+
+import android.perftests.utils.PerfStatusReporter
+import android.view.InputDevice
+import android.view.MotionEvent
+import android.view.VelocityTracker
+
+import androidx.test.filters.LargeTest
+import androidx.test.runner.AndroidJUnit4
+
+import java.time.Duration
+
+import org.junit.Assert
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/**
+ * Helper class to maintain [MotionEvent]s for tests.
+ *
+ * This is primarily used to create [MotionEvent]s for tests, in a way where a sequence of
+ * [MotionEvent]s created in multiple test runs are exactly the same, as long as [reset] is called
+ * between consecutive sequences of [MotionEvent]s.
+ *
+ * Furthermore, it also contains convenience methods to run any queries/verifications of the
+ * generated [MotionEvent]s.
+ */
+abstract class MotionState {
+    /** Current time, in ms. */
+    protected var currentTime = START_TIME
+
+    /** Resets the state of this instance. */
+    open fun reset() {
+        currentTime = START_TIME
+    }
+
+    /** Creates a [MotionEvent]. */
+    abstract fun createMotionEvent(): MotionEvent
+
+    /** Asserts that the current velocity is not zero, just for verifying there's motion. */
+    abstract fun assertNonZeroVelocity(velocityTracker: VelocityTracker)
+
+    companion object {
+        /** Arbitrarily chosen start time. */
+        val START_TIME = Duration.ofMillis(100)
+        /**
+         * A small enough time jump, which won't be considered by the tracker as big enough to
+         * deduce that a pointer has stopped.
+         */
+        val DEFAULT_TIME_JUMP = Duration.ofMillis(2)
+    }
+}
+
+/** An implementation of [MotionState] for [MotionEvent.AXIS_SCROLL]. */
+private class ScrollMotionState : MotionState() {
+    override fun createMotionEvent(): MotionEvent {
+        val props = MotionEvent.PointerProperties()
+        props.id = 0
+        val coords = MotionEvent.PointerCoords()
+        coords.setAxisValue(MotionEvent.AXIS_SCROLL, DEFAULT_SCROLL_AMOUNT)
+        val motionEvent = MotionEvent.obtain(
+            /*downTime=*/0,
+            currentTime.toMillis(),
+            MotionEvent.ACTION_SCROLL,
+            /*pointerCount=*/1,
+            arrayOf(props),
+            arrayOf(coords),
+            /*metaState=*/0,
+            /*buttonState=*/0,
+            /*xPrecision=*/0f,
+            /*yPrecision=*/0f,
+            /*deviceId=*/1,
+            /*edgeFlags=*/0,
+            InputDevice.SOURCE_ROTARY_ENCODER,
+            /*flags=*/0
+        )
+
+        currentTime = currentTime.plus(DEFAULT_TIME_JUMP)
+
+        return motionEvent
+    }
+
+    override fun assertNonZeroVelocity(velocityTracker: VelocityTracker) {
+        Assert.assertTrue(velocityTracker.getAxisVelocity(MotionEvent.AXIS_SCROLL) != 0f)
+    }
+
+    companion object {
+        private val DEFAULT_SCROLL_AMOUNT: Float = 30f
+    }
+}
+
+/** An implementation of [MotionState] for [MotionEvent.AXIS_X] and [MotionEvent.AXIS_Y]. */
+private class PlanarMotionState : MotionState() {
+    private var x: Float = DEFAULT_X
+    private var y: Float = DEFAULT_Y
+    private var downEventCreated = false
+
+    override fun createMotionEvent(): MotionEvent {
+        val action: Int = if (downEventCreated) MotionEvent.ACTION_MOVE else MotionEvent.ACTION_DOWN
+        val motionEvent = MotionEvent.obtain(
+            /*downTime=*/START_TIME.toMillis(),
+            currentTime.toMillis(),
+            action,
+            x,
+            y,
+            /*metaState=*/0)
+
+        if (downEventCreated) {
+            x += INCREMENT
+            y += INCREMENT
+        } else {
+            downEventCreated = true
+        }
+        currentTime = currentTime.plus(DEFAULT_TIME_JUMP)
+
+        return motionEvent
+    }
+
+    override fun assertNonZeroVelocity(velocityTracker: VelocityTracker) {
+        Assert.assertTrue(velocityTracker.getAxisVelocity(MotionEvent.AXIS_X) != 0f)
+        Assert.assertTrue(velocityTracker.getAxisVelocity(MotionEvent.AXIS_Y) != 0f)
+    }
+
+    override fun reset() {
+        super.reset()
+        x = DEFAULT_X
+        y = DEFAULT_Y
+        downEventCreated = false
+    }
+
+    companion object {
+        /** Arbitrarily chosen constants. No need to have varying velocity for now. */
+        private val DEFAULT_X: Float = 2f
+        private val DEFAULT_Y: Float = 4f
+        private val INCREMENT: Float = 0.7f
+    }
+}
+
+/**
+ * Benchmark tests for [VelocityTracker]
+ *
+ * Build/Install/Run:
+ * atest VelocityTrackerBenchmarkTest
+ */
+@LargeTest
+@RunWith(AndroidJUnit4::class)
+class VelocityTrackerBenchmarkTest {
+    @get:Rule
+    val perfStatusReporter: PerfStatusReporter = PerfStatusReporter()
+
+    private val velocityTracker = VelocityTracker.obtain()
+    @Before
+    fun setup() {
+        velocityTracker.clear()
+    }
+
+    @Test
+    fun addMovement_axisScroll() {
+        testAddMovement(ScrollMotionState())
+    }
+
+    @Test
+    fun computeCurrentVelocity_computeAfterAllAdditions_axisScroll() {
+        testComputeCurrentVelocity_computeAfterAllAdditions(ScrollMotionState())
+    }
+
+    @Test
+    fun computeCurrentVelocity_computeAfterEachAdd_axisScroll() {
+        testComputeCurrentVelocity_computeAfterEachAdd(ScrollMotionState())
+    }
+
+    @Test
+    fun addMovementTest_planarAxes() {
+        testAddMovement(PlanarMotionState())
+    }
+
+    @Test
+    fun computeCurrentVelocity_computeAfterAllAdditions_planarAxes() {
+        testComputeCurrentVelocity_computeAfterAllAdditions(PlanarMotionState())
+    }
+
+    private fun testAddMovement(motionState: MotionState) {
+        val state = perfStatusReporter.getBenchmarkState()
+        while (state.keepRunning()) {
+            state.pauseTiming()
+            for (i in 0 until TEST_NUM_DATAPOINTS) {
+                val motionEvent = motionState.createMotionEvent()
+                state.resumeTiming()
+                velocityTracker.addMovement(motionEvent)
+                state.pauseTiming()
+            }
+            velocityTracker.computeCurrentVelocity(1000)
+            motionState.assertNonZeroVelocity(velocityTracker)
+            // Clear the tracker for the next run
+            velocityTracker.clear()
+            motionState.reset()
+            state.resumeTiming()
+        }
+    }
+
+    private fun testComputeCurrentVelocity_computeAfterAllAdditions(motionState: MotionState) {
+        val state = perfStatusReporter.getBenchmarkState()
+        while (state.keepRunning()) {
+            // Add the data points
+            state.pauseTiming()
+            for (i in 0 until TEST_NUM_DATAPOINTS) {
+                velocityTracker.addMovement(motionState.createMotionEvent())
+            }
+
+            // Do the velocity computation
+            state.resumeTiming()
+            velocityTracker.computeCurrentVelocity(1000)
+
+            state.pauseTiming()
+            motionState.assertNonZeroVelocity(velocityTracker)
+            // Clear the tracker for the next run
+            velocityTracker.clear()
+            state.resumeTiming()
+        }
+    }
+
+    private fun testComputeCurrentVelocity_computeAfterEachAdd(motionState: MotionState) {
+        val state = perfStatusReporter.getBenchmarkState()
+        while (state.keepRunning()) {
+            state.pauseTiming()
+            for (i in 0 until TEST_NUM_DATAPOINTS) {
+                velocityTracker.addMovement(motionState.createMotionEvent())
+                state.resumeTiming()
+                velocityTracker.computeCurrentVelocity(1000)
+                state.pauseTiming()
+            }
+            motionState.assertNonZeroVelocity(velocityTracker)
+            // Clear the tracker for the next run
+            velocityTracker.clear()
+            state.resumeTiming()
+        }
+    }
+
+    companion object {
+        private const val TEST_NUM_DATAPOINTS = 100
+    }
+}
\ No newline at end of file
diff --git a/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java b/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java
index 051dde0..4c2cf2b 100644
--- a/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java
+++ b/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java
@@ -1554,8 +1554,9 @@
     }
 
     private void waitCoolDownPeriod() {
-        final int tenSeconds = 1000 * 10;
+        // Heuristic value based on local tests. Stability increased compared to no waiting.
+        final int fiveSeconds = 1000 * 5;
         waitForBroadcastIdle();
-        sleep(tenSeconds);
+        sleep(fiveSeconds);
     }
 }
diff --git a/cmds/locksettings/Android.bp b/cmds/locksettings/Android.bp
index 5ee5824..ee31aed 100644
--- a/cmds/locksettings/Android.bp
+++ b/cmds/locksettings/Android.bp
@@ -21,8 +21,7 @@
     default_applicable_licenses: ["frameworks_base_license"],
 }
 
-java_binary {
+sh_binary {
     name: "locksettings",
-    wrapper: "locksettings.sh",
-    srcs: ["**/*.java"],
+    src: "locksettings.sh",
 }
diff --git a/cmds/locksettings/locksettings.sh b/cmds/locksettings/locksettings.sh
index 0ef4fa9..2f8d868 100755
--- a/cmds/locksettings/locksettings.sh
+++ b/cmds/locksettings/locksettings.sh
@@ -1,6 +1,2 @@
 #!/system/bin/sh
-# Script to start "locksettings" on the device
-#
-base=/system
-export CLASSPATH=$base/framework/locksettings.jar
-exec app_process $base/bin com.android.commands.locksettings.LockSettingsCmd "$@"
+cmd lock_settings "$@"
diff --git a/cmds/locksettings/src/com/android/commands/locksettings/LockSettingsCmd.java b/cmds/locksettings/src/com/android/commands/locksettings/LockSettingsCmd.java
deleted file mode 100644
index 7d9260a..0000000
--- a/cmds/locksettings/src/com/android/commands/locksettings/LockSettingsCmd.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2016 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.commands.locksettings;
-
-import android.os.ResultReceiver;
-import android.os.ServiceManager;
-import android.os.ShellCallback;
-
-import com.android.internal.os.BaseCommand;
-import com.android.internal.widget.ILockSettings;
-
-import java.io.FileDescriptor;
-import java.io.PrintStream;
-
-public final class LockSettingsCmd extends BaseCommand {
-
-    public static void main(String[] args) {
-        (new LockSettingsCmd()).run(args);
-    }
-
-    @Override
-    public void onShowUsage(PrintStream out) {
-        main(new String[] { "help" });
-    }
-
-    @Override
-    public void onRun() throws Exception {
-        ILockSettings lockSettings = ILockSettings.Stub.asInterface(
-                ServiceManager.getService("lock_settings"));
-        lockSettings.asBinder().shellCommand(FileDescriptor.in, FileDescriptor.out,
-                FileDescriptor.err, getRawArgs(), new ShellCallback(), new ResultReceiver(null) {});
-    }
-}
diff --git a/core/api/current.txt b/core/api/current.txt
index 6d89717..7930c01 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -20388,7 +20388,7 @@
   public final class GnssCapabilities implements android.os.Parcelable {
     method public int describeContents();
     method @NonNull public java.util.List<android.location.GnssSignalType> getGnssSignalTypes();
-    method public boolean hasAccumulatedDeltaRange();
+    method public int hasAccumulatedDeltaRange();
     method public boolean hasAntennaInfo();
     method public boolean hasGeofencing();
     method @Deprecated public boolean hasGnssAntennaInfo();
@@ -20414,8 +20414,10 @@
     method public boolean hasSatellitePvt();
     method public boolean hasScheduling();
     method public boolean hasSingleShotFix();
-    method public boolean isAccumulatedDeltaRangeCapabilityKnown();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field public static final int CAPABILITY_SUPPORTED = 1; // 0x1
+    field public static final int CAPABILITY_UNKNOWN = 0; // 0x0
+    field public static final int CAPABILITY_UNSUPPORTED = 2; // 0x2
     field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssCapabilities> CREATOR;
   }
 
@@ -20423,9 +20425,8 @@
     ctor public GnssCapabilities.Builder();
     ctor public GnssCapabilities.Builder(@NonNull android.location.GnssCapabilities);
     method @NonNull public android.location.GnssCapabilities build();
-    method @NonNull public android.location.GnssCapabilities.Builder clearIsAccumulatedDeltaRangeCapabilityKnown();
     method @NonNull public android.location.GnssCapabilities.Builder setGnssSignalTypes(@NonNull java.util.List<android.location.GnssSignalType>);
-    method @NonNull public android.location.GnssCapabilities.Builder setHasAccumulatedDeltaRange(boolean);
+    method @NonNull public android.location.GnssCapabilities.Builder setHasAccumulatedDeltaRange(int);
     method @NonNull public android.location.GnssCapabilities.Builder setHasAntennaInfo(boolean);
     method @NonNull public android.location.GnssCapabilities.Builder setHasGeofencing(boolean);
     method @NonNull public android.location.GnssCapabilities.Builder setHasLowPowerMode(boolean);
@@ -32597,6 +32598,7 @@
     field public static final int S_V2 = 32; // 0x20
     field public static final int TIRAMISU = 33; // 0x21
     field public static final int UPSIDE_DOWN_CAKE = 10000; // 0x2710
+    field public static final int VANILLA_ICE_CREAM = 10000; // 0x2710
   }
 
   public final class Bundle extends android.os.BaseBundle implements java.lang.Cloneable android.os.Parcelable {
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 8a6faa1..29976c8 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -5988,6 +5988,7 @@
     method @Nullable public android.media.AudioFormat getCaptureFormat();
     method public int getCaptureSession();
     method public byte[] getData();
+    method public long getHalEventReceivedMillis();
     method public boolean isCaptureAvailable();
   }
 
@@ -13053,6 +13054,7 @@
     method @Nullable public android.media.AudioFormat getCaptureAudioFormat();
     method @Nullable public byte[] getData();
     method public int getDataFormat();
+    method public long getHalEventReceivedMillis();
     method @Nullable public android.service.voice.HotwordDetectedResult getHotwordDetectedResult();
     method @NonNull public java.util.List<android.hardware.soundtrigger.SoundTrigger.KeyphraseRecognitionExtra> getKeyphraseRecognitionExtras();
     method @Deprecated @Nullable public byte[] getTriggerAudio();
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 1860f43..2f8d0b5 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -1578,7 +1578,7 @@
   }
 
   public static class SoundTrigger.RecognitionEvent {
-    ctor public SoundTrigger.RecognitionEvent(int, int, boolean, int, int, int, boolean, @NonNull android.media.AudioFormat, @Nullable byte[]);
+    ctor public SoundTrigger.RecognitionEvent(int, int, boolean, int, int, int, boolean, @NonNull android.media.AudioFormat, @Nullable byte[], long);
   }
 
 }
@@ -2796,7 +2796,7 @@
   public class AlwaysOnHotwordDetector implements android.service.voice.HotwordDetector {
     method public void overrideAvailability(int);
     method public void resetAvailability();
-    method @RequiresPermission(allOf={android.Manifest.permission.RECORD_AUDIO, android.Manifest.permission.CAPTURE_AUDIO_HOTWORD}) public void triggerHardwareRecognitionEventForTest(int, int, boolean, int, int, int, boolean, @NonNull android.media.AudioFormat, @Nullable byte[], @NonNull java.util.List<android.hardware.soundtrigger.SoundTrigger.KeyphraseRecognitionExtra>);
+    method @RequiresPermission(allOf={android.Manifest.permission.RECORD_AUDIO, android.Manifest.permission.CAPTURE_AUDIO_HOTWORD}) public void triggerHardwareRecognitionEventForTest(int, int, long, boolean, int, int, int, boolean, @NonNull android.media.AudioFormat, @Nullable byte[], @NonNull java.util.List<android.hardware.soundtrigger.SoundTrigger.KeyphraseRecognitionExtra>);
   }
 
   public static final class AlwaysOnHotwordDetector.EventPayload.Builder {
@@ -2808,6 +2808,7 @@
     method @NonNull public android.service.voice.AlwaysOnHotwordDetector.EventPayload.Builder setCaptureSession(int);
     method @NonNull public android.service.voice.AlwaysOnHotwordDetector.EventPayload.Builder setData(@NonNull byte[]);
     method @NonNull public android.service.voice.AlwaysOnHotwordDetector.EventPayload.Builder setDataFormat(int);
+    method @NonNull public android.service.voice.AlwaysOnHotwordDetector.EventPayload.Builder setHalEventReceivedMillis(long);
     method @NonNull public android.service.voice.AlwaysOnHotwordDetector.EventPayload.Builder setHotwordDetectedResult(@NonNull android.service.voice.HotwordDetectedResult);
     method @NonNull public android.service.voice.AlwaysOnHotwordDetector.EventPayload.Builder setKeyphraseRecognitionExtras(@NonNull java.util.List<android.hardware.soundtrigger.SoundTrigger.KeyphraseRecognitionExtra>);
   }
diff --git a/core/java/android/animation/Animator.java b/core/java/android/animation/Animator.java
index a81ef18..322d23b 100644
--- a/core/java/android/animation/Animator.java
+++ b/core/java/android/animation/Animator.java
@@ -72,6 +72,13 @@
     private static long sBackgroundPauseDelay = 10000;
 
     /**
+     * A cache of the values in a list. Used so that when calling the list, we have a copy
+     * of it in case the list is modified while iterating. The array can be reused to avoid
+     * allocation on every notification.
+     */
+    private Object[] mCachedList;
+
+    /**
      * Sets the duration for delaying pausing animators when apps go into the background.
      * Used by AnimationHandler when requested to pause animators.
      *
@@ -160,14 +167,7 @@
     public void pause() {
         if (isStarted() && !mPaused) {
             mPaused = true;
-            if (mPauseListeners != null) {
-                ArrayList<AnimatorPauseListener> tmpListeners =
-                        (ArrayList<AnimatorPauseListener>) mPauseListeners.clone();
-                int numListeners = tmpListeners.size();
-                for (int i = 0; i < numListeners; ++i) {
-                    tmpListeners.get(i).onAnimationPause(this);
-                }
-            }
+            notifyPauseListeners(AnimatorCaller.ON_PAUSE);
         }
     }
 
@@ -184,14 +184,7 @@
     public void resume() {
         if (mPaused) {
             mPaused = false;
-            if (mPauseListeners != null) {
-                ArrayList<AnimatorPauseListener> tmpListeners =
-                        (ArrayList<AnimatorPauseListener>) mPauseListeners.clone();
-                int numListeners = tmpListeners.size();
-                for (int i = 0; i < numListeners; ++i) {
-                    tmpListeners.get(i).onAnimationResume(this);
-                }
-            }
+            notifyPauseListeners(AnimatorCaller.ON_RESUME);
         }
     }
 
@@ -450,6 +443,7 @@
             if (mPauseListeners != null) {
                 anim.mPauseListeners = new ArrayList<AnimatorPauseListener>(mPauseListeners);
             }
+            anim.mCachedList = null;
             return anim;
         } catch (CloneNotSupportedException e) {
            throw new AssertionError();
@@ -591,6 +585,70 @@
     }
 
     /**
+     * Calls notification for each AnimatorListener.
+     *
+     * @param notification The notification method to call on each listener.
+     * @param isReverse When this is used with start/end, this is the isReverse parameter. For
+     *                  other calls, this is ignored.
+     */
+    void notifyListeners(
+            AnimatorCaller<AnimatorListener, Animator> notification,
+            boolean isReverse
+    ) {
+        callOnList(mListeners, notification, this, isReverse);
+    }
+
+    /**
+     * Call pause/resume on each AnimatorPauseListener.
+     *
+     * @param notification Either ON_PAUSE or ON_RESUME to call onPause or onResume on each
+     *                     listener.
+     */
+    void notifyPauseListeners(AnimatorCaller<AnimatorPauseListener, Animator> notification) {
+        callOnList(mPauseListeners, notification, this, false);
+    }
+
+    /**
+     * Calls <code>call</code> for every item in <code>list</code> with <code>animator</code> and
+     * <code>isReverse</code> as parameters.
+     *
+     * @param list The list of items to make calls on.
+     * @param call The method to call for each item in list.
+     * @param animator The animator parameter of call.
+     * @param isReverse The isReverse parameter of call.
+     * @param <T> The item type of list
+     * @param <A> The Animator type of animator.
+     */
+    <T, A> void callOnList(
+            ArrayList<T> list,
+            AnimatorCaller<T, A> call,
+            A animator,
+            boolean isReverse
+    ) {
+        int size = list == null ? 0 : list.size();
+        if (size > 0) {
+            // Try to reuse mCacheList to store the items of list.
+            Object[] array;
+            if (mCachedList == null || mCachedList.length < size) {
+                array = new Object[size];
+            } else {
+                array = mCachedList;
+                // Clear it in case there is some reentrancy
+                mCachedList = null;
+            }
+            list.toArray(array);
+            for (int i = 0; i < size; i++) {
+                //noinspection unchecked
+                T item = (T) array[i];
+                call.call(item, animator, isReverse);
+                array[i] = null;
+            }
+            // Store it for the next call so we can reuse this array, if needed.
+            mCachedList = array;
+        }
+    }
+
+    /**
      * <p>An animation listener receives notifications from an animation.
      * Notifications indicate animation related events, such as the end or the
      * repetition of the animation.</p>
@@ -748,4 +806,29 @@
             return clone;
         }
     }
+
+    /**
+     * Internally used by {@link #callOnList(ArrayList, AnimatorCaller, Object, boolean)} to
+     * make a call on all children of a list. This can be for start, stop, pause, cancel, update,
+     * etc notifications.
+     *
+     * @param <T> The type of listener to make the call on
+     * @param <A> The type of animator that is passed as a parameter
+     */
+    interface AnimatorCaller<T, A> {
+        void call(T listener, A animator, boolean isReverse);
+
+        AnimatorCaller<AnimatorListener, Animator> ON_START = AnimatorListener::onAnimationStart;
+        AnimatorCaller<AnimatorListener, Animator> ON_END = AnimatorListener::onAnimationEnd;
+        AnimatorCaller<AnimatorListener, Animator> ON_CANCEL =
+                (listener, animator, isReverse) -> listener.onAnimationCancel(animator);
+        AnimatorCaller<AnimatorListener, Animator> ON_REPEAT =
+                (listener, animator, isReverse) -> listener.onAnimationRepeat(animator);
+        AnimatorCaller<AnimatorPauseListener, Animator> ON_PAUSE =
+                (listener, animator, isReverse) -> listener.onAnimationPause(animator);
+        AnimatorCaller<AnimatorPauseListener, Animator> ON_RESUME =
+                (listener, animator, isReverse) -> listener.onAnimationResume(animator);
+        AnimatorCaller<ValueAnimator.AnimatorUpdateListener, ValueAnimator> ON_UPDATE =
+                (listener, animator, isReverse) -> listener.onAnimationUpdate(animator);
+    }
 }
diff --git a/core/java/android/animation/AnimatorSet.java b/core/java/android/animation/AnimatorSet.java
index 257adfe..09eec9d 100644
--- a/core/java/android/animation/AnimatorSet.java
+++ b/core/java/android/animation/AnimatorSet.java
@@ -32,6 +32,7 @@
 import java.util.Comparator;
 import java.util.HashMap;
 import java.util.List;
+import java.util.function.Consumer;
 
 /**
  * This class plays a set of {@link Animator} objects in the specified order. Animations
@@ -424,24 +425,28 @@
             throw new AndroidRuntimeException("Animators may only be run on Looper threads");
         }
         if (isStarted()) {
-            ArrayList<AnimatorListener> tmpListeners = null;
-            if (mListeners != null) {
-                tmpListeners = (ArrayList<AnimatorListener>) mListeners.clone();
-                int size = tmpListeners.size();
-                for (int i = 0; i < size; i++) {
-                    tmpListeners.get(i).onAnimationCancel(this);
-                }
-            }
-            ArrayList<Node> playingSet = new ArrayList<>(mPlayingSet);
-            int setSize = playingSet.size();
-            for (int i = 0; i < setSize; i++) {
-                playingSet.get(i).mAnimation.cancel();
-            }
+            notifyListeners(AnimatorCaller.ON_CANCEL, false);
+            callOnPlayingSet(Animator::cancel);
             mPlayingSet.clear();
             endAnimation();
         }
     }
 
+    /**
+     * Calls consumer on every Animator of mPlayingSet.
+     *
+     * @param consumer The method to call on every Animator of mPlayingSet.
+     */
+    private void callOnPlayingSet(Consumer<Animator> consumer) {
+        final ArrayList<Node> list = mPlayingSet;
+        final int size = list.size();
+        //noinspection ForLoopReplaceableByForEach
+        for (int i = 0; i < size; i++) {
+            final Animator animator = list.get(i).mAnimation;
+            consumer.accept(animator);
+        }
+    }
+
     // Force all the animations to end when the duration scale is 0.
     private void forceToEnd() {
         if (mEndCanBeCalled) {
@@ -662,6 +667,7 @@
         super.pause();
         if (!previouslyPaused && mPaused) {
             mPauseTime = -1;
+            callOnPlayingSet(Animator::pause);
         }
     }
 
@@ -676,6 +682,7 @@
             if (mPauseTime >= 0) {
                 addAnimationCallback(0);
             }
+            callOnPlayingSet(Animator::resume);
         }
     }
 
@@ -751,26 +758,14 @@
 
     private void notifyStartListeners(boolean inReverse) {
         if (mListeners != null && !mStartListenersCalled) {
-            ArrayList<AnimatorListener> tmpListeners =
-                    (ArrayList<AnimatorListener>) mListeners.clone();
-            int numListeners = tmpListeners.size();
-            for (int i = 0; i < numListeners; ++i) {
-                AnimatorListener listener = tmpListeners.get(i);
-                listener.onAnimationStart(this, inReverse);
-            }
+            notifyListeners(AnimatorCaller.ON_START, inReverse);
         }
         mStartListenersCalled = true;
     }
 
     private void notifyEndListeners(boolean inReverse) {
         if (mListeners != null && mStartListenersCalled) {
-            ArrayList<AnimatorListener> tmpListeners =
-                    (ArrayList<AnimatorListener>) mListeners.clone();
-            int numListeners = tmpListeners.size();
-            for (int i = 0; i < numListeners; ++i) {
-                AnimatorListener listener = tmpListeners.get(i);
-                listener.onAnimationEnd(this, inReverse);
-            }
+            notifyListeners(AnimatorCaller.ON_END, inReverse);
         }
         mStartListenersCalled = false;
     }
@@ -1503,6 +1498,7 @@
         anim.mNodeMap = new ArrayMap<Animator, Node>();
         anim.mNodes = new ArrayList<Node>(nodeCount);
         anim.mEvents = new ArrayList<AnimationEvent>();
+        anim.mStartListenersCalled = false;
         anim.mAnimationEndListener = new AnimatorListenerAdapter() {
             @Override
             public void onAnimationEnd(Animator animation) {
diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java
index 7009725..719f596 100644
--- a/core/java/android/animation/ValueAnimator.java
+++ b/core/java/android/animation/ValueAnimator.java
@@ -1110,24 +1110,14 @@
 
     private void notifyStartListeners(boolean isReversing) {
         if (mListeners != null && !mStartListenersCalled) {
-            ArrayList<AnimatorListener> tmpListeners =
-                    (ArrayList<AnimatorListener>) mListeners.clone();
-            int numListeners = tmpListeners.size();
-            for (int i = 0; i < numListeners; ++i) {
-                tmpListeners.get(i).onAnimationStart(this, isReversing);
-            }
+            notifyListeners(AnimatorCaller.ON_START, isReversing);
         }
         mStartListenersCalled = true;
     }
 
     private void notifyEndListeners(boolean isReversing) {
         if (mListeners != null && mStartListenersCalled) {
-            ArrayList<AnimatorListener> tmpListeners =
-                    (ArrayList<AnimatorListener>) mListeners.clone();
-            int numListeners = tmpListeners.size();
-            for (int i = 0; i < numListeners; ++i) {
-                tmpListeners.get(i).onAnimationEnd(this, isReversing);
-            }
+            notifyListeners(AnimatorCaller.ON_END, isReversing);
         }
         mStartListenersCalled = false;
     }
@@ -1224,15 +1214,7 @@
                 // If it's not yet running, then start listeners weren't called. Call them now.
                 notifyStartListeners(mReversing);
             }
-            int listenersSize = mListeners.size();
-            if (listenersSize > 0) {
-                ArrayList<AnimatorListener> tmpListeners =
-                        (ArrayList<AnimatorListener>) mListeners.clone();
-                for (int i = 0; i < listenersSize; i++) {
-                    AnimatorListener listener = tmpListeners.get(i);
-                    listener.onAnimationCancel(this);
-                }
-            }
+            notifyListeners(AnimatorCaller.ON_CANCEL, false);
         }
         endAnimation();
 
@@ -1435,12 +1417,7 @@
                 done = true;
             } else if (newIteration && !lastIterationFinished) {
                 // Time to repeat
-                if (mListeners != null) {
-                    int numListeners = mListeners.size();
-                    for (int i = 0; i < numListeners; ++i) {
-                        mListeners.get(i).onAnimationRepeat(this);
-                    }
-                }
+                notifyListeners(AnimatorCaller.ON_REPEAT, false);
             } else if (lastIterationFinished) {
                 done = true;
             }
@@ -1493,13 +1470,8 @@
             iteration = Math.min(iteration, mRepeatCount);
             lastIteration = Math.min(lastIteration, mRepeatCount);
 
-            if (iteration != lastIteration) {
-                if (mListeners != null) {
-                    int numListeners = mListeners.size();
-                    for (int i = 0; i < numListeners; ++i) {
-                        mListeners.get(i).onAnimationRepeat(this);
-                    }
-                }
+            if (notify && iteration != lastIteration) {
+                notifyListeners(AnimatorCaller.ON_REPEAT, false);
             }
         }
 
@@ -1697,11 +1669,8 @@
         for (int i = 0; i < numValues; ++i) {
             mValues[i].calculateValue(fraction);
         }
-        if (mUpdateListeners != null) {
-            int numListeners = mUpdateListeners.size();
-            for (int i = 0; i < numListeners; ++i) {
-                mUpdateListeners.get(i).onAnimationUpdate(this);
-            }
+        if (mSeekFraction >= 0 || mStartListenersCalled) {
+            callOnList(mUpdateListeners, AnimatorCaller.ON_UPDATE, this, false);
         }
     }
 
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index 5cad1ae..ac92811 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -93,7 +93,7 @@
 
     private static final String TAG = "Instrumentation";
 
-    private static final long CONNECT_TIMEOUT_MILLIS = 5000;
+    private static final long CONNECT_TIMEOUT_MILLIS = 60_000;
 
     private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
 
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index bf69531..dc197bd 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -1401,95 +1401,99 @@
         if (mApplication != null) {
             return mApplication;
         }
-        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "makeApplication");
 
-        synchronized (sApplications) {
-            final Application cached = sApplications.get(mPackageName);
-            if (cached != null) {
-                // Looks like this is always happening for the system server, because
-                // the LoadedApk created in systemMain() -> attach() isn't cached properly?
-                if (!"android".equals(mPackageName)) {
-                    Slog.wtfStack(TAG, "App instance already created for package=" + mPackageName
-                            + " instance=" + cached);
-                }
-                if (!allowDuplicateInstances) {
-                    mApplication = cached;
-                    return cached;
-                }
-                // Some apps intentionally call makeApplication() to create a new Application
-                // instance... Sigh...
-            }
-        }
 
-        Application app = null;
-
-        final String myProcessName = Process.myProcessName();
-        String appClass = mApplicationInfo.getCustomApplicationClassNameForProcess(
-                myProcessName);
-        if (forceDefaultAppClass || (appClass == null)) {
-            appClass = "android.app.Application";
+        if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
+            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "makeApplication");
         }
 
         try {
-            final java.lang.ClassLoader cl = getClassLoader();
-            if (!mPackageName.equals("android")) {
-                Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
-                        "initializeJavaContextClassLoader");
-                initializeJavaContextClassLoader();
-                Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
-            }
-
-            // Rewrite the R 'constants' for all library apks.
-            SparseArray<String> packageIdentifiers = getAssets().getAssignedPackageIdentifiers(
-                    false, false);
-            for (int i = 0, n = packageIdentifiers.size(); i < n; i++) {
-                final int id = packageIdentifiers.keyAt(i);
-                if (id == 0x01 || id == 0x7f) {
-                    continue;
-                }
-
-                rewriteRValues(cl, packageIdentifiers.valueAt(i), id);
-            }
-
-            ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
-            // The network security config needs to be aware of multiple
-            // applications in the same process to handle discrepancies
-            NetworkSecurityConfigProvider.handleNewApplication(appContext);
-            app = mActivityThread.mInstrumentation.newApplication(
-                    cl, appClass, appContext);
-            appContext.setOuterContext(app);
-        } catch (Exception e) {
-            if (!mActivityThread.mInstrumentation.onException(app, e)) {
-                Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
-                throw new RuntimeException(
-                    "Unable to instantiate application " + appClass
-                    + " package " + mPackageName + ": " + e.toString(), e);
-            }
-        }
-        mActivityThread.mAllApplications.add(app);
-        mApplication = app;
-        if (!allowDuplicateInstances) {
             synchronized (sApplications) {
-                sApplications.put(mPackageName, app);
-            }
-        }
-
-        if (instrumentation != null) {
-            try {
-                instrumentation.callApplicationOnCreate(app);
-            } catch (Exception e) {
-                if (!instrumentation.onException(app, e)) {
-                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
-                    throw new RuntimeException(
-                        "Unable to create application " + app.getClass().getName()
-                        + ": " + e.toString(), e);
+                final Application cached = sApplications.get(mPackageName);
+                if (cached != null) {
+                    // Looks like this is always happening for the system server, because
+                    // the LoadedApk created in systemMain() -> attach() isn't cached properly?
+                    if (!"android".equals(mPackageName)) {
+                        Slog.wtfStack(TAG, "App instance already created for package="
+                                + mPackageName + " instance=" + cached);
+                    }
+                    if (!allowDuplicateInstances) {
+                        mApplication = cached;
+                        return cached;
+                    }
+                    // Some apps intentionally call makeApplication() to create a new Application
+                    // instance... Sigh...
                 }
             }
+
+            Application app = null;
+
+            final String myProcessName = Process.myProcessName();
+            String appClass = mApplicationInfo.getCustomApplicationClassNameForProcess(
+                    myProcessName);
+            if (forceDefaultAppClass || (appClass == null)) {
+                appClass = "android.app.Application";
+            }
+
+            try {
+                final java.lang.ClassLoader cl = getClassLoader();
+                if (!mPackageName.equals("android")) {
+                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
+                            "initializeJavaContextClassLoader");
+                    initializeJavaContextClassLoader();
+                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
+                }
+
+                // Rewrite the R 'constants' for all library apks.
+                SparseArray<String> packageIdentifiers = getAssets().getAssignedPackageIdentifiers(
+                        false, false);
+                for (int i = 0, n = packageIdentifiers.size(); i < n; i++) {
+                    final int id = packageIdentifiers.keyAt(i);
+                    if (id == 0x01 || id == 0x7f) {
+                        continue;
+                    }
+
+                    rewriteRValues(cl, packageIdentifiers.valueAt(i), id);
+                }
+
+                ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
+                // The network security config needs to be aware of multiple
+                // applications in the same process to handle discrepancies
+                NetworkSecurityConfigProvider.handleNewApplication(appContext);
+                app = mActivityThread.mInstrumentation.newApplication(
+                        cl, appClass, appContext);
+                appContext.setOuterContext(app);
+            } catch (Exception e) {
+                if (!mActivityThread.mInstrumentation.onException(app, e)) {
+                    throw new RuntimeException(
+                        "Unable to instantiate application " + appClass
+                        + " package " + mPackageName + ": " + e.toString(), e);
+                }
+            }
+            mActivityThread.mAllApplications.add(app);
+            mApplication = app;
+            if (!allowDuplicateInstances) {
+                synchronized (sApplications) {
+                    sApplications.put(mPackageName, app);
+                }
+            }
+
+            if (instrumentation != null) {
+                try {
+                    instrumentation.callApplicationOnCreate(app);
+                } catch (Exception e) {
+                    if (!instrumentation.onException(app, e)) {
+                        throw new RuntimeException(
+                            "Unable to create application " + app.getClass().getName()
+                            + ": " + e.toString(), e);
+                    }
+                }
+            }
+
+            return app;
+        } finally {
+            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
         }
-
-        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
-
-        return app;
     }
 
     @UnsupportedAppUsage
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index d3502c5..aa302ad 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -20,7 +20,7 @@
 import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
 import static android.os.Process.SYSTEM_UID;
 import static android.os.Process.myUserHandle;
-import static android.os.Trace.TRACE_TAG_DATABASE;
+import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
 
 import static com.android.internal.util.FrameworkStatsLog.GET_TYPE_ACCESSED_WITHOUT_PERMISSION;
 import static com.android.internal.util.FrameworkStatsLog.GET_TYPE_ACCESSED_WITHOUT_PERMISSION__LOCATION__PROVIDER_CHECK_URI_PERMISSION;
@@ -285,7 +285,7 @@
                 // Return an empty cursor for all columns.
                 return new MatrixCursor(cursor.getColumnNames(), 0);
             }
-            traceBegin(TRACE_TAG_DATABASE, "query: ", uri.getAuthority());
+            traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "query: ", uri.getAuthority());
             final AttributionSource original = setCallingAttributionSource(
                     attributionSource);
             try {
@@ -296,7 +296,7 @@
                 throw e.rethrowAsRuntimeException();
             } finally {
                 setCallingAttributionSource(original);
-                Trace.traceEnd(TRACE_TAG_DATABASE);
+                Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
             }
         }
 
@@ -305,7 +305,7 @@
             // getCallingPackage() isn't available in getType(), as the javadoc states.
             uri = validateIncomingUri(uri);
             uri = maybeGetUriWithoutUserId(uri);
-            traceBegin(TRACE_TAG_DATABASE, "getType: ", uri.getAuthority());
+            traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "getType: ", uri.getAuthority());
             try {
                 if (checkGetTypePermission(attributionSource, uri)
                         == PermissionChecker.PERMISSION_GRANTED) {
@@ -330,7 +330,7 @@
             } catch (RemoteException e) {
                 throw e.rethrowAsRuntimeException();
             } finally {
-                Trace.traceEnd(TRACE_TAG_DATABASE);
+                Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
             }
         }
 
@@ -417,7 +417,7 @@
                     setCallingAttributionSource(original);
                 }
             }
-            traceBegin(TRACE_TAG_DATABASE, "insert: ", uri.getAuthority());
+            traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "insert: ", uri.getAuthority());
             final AttributionSource original = setCallingAttributionSource(
                     attributionSource);
             try {
@@ -426,7 +426,7 @@
                 throw e.rethrowAsRuntimeException();
             } finally {
                 setCallingAttributionSource(original);
-                Trace.traceEnd(TRACE_TAG_DATABASE);
+                Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
             }
         }
 
@@ -439,7 +439,7 @@
                     != PermissionChecker.PERMISSION_GRANTED) {
                 return 0;
             }
-            traceBegin(TRACE_TAG_DATABASE, "bulkInsert: ", uri.getAuthority());
+            traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "bulkInsert: ", uri.getAuthority());
             final AttributionSource original = setCallingAttributionSource(
                     attributionSource);
             try {
@@ -448,7 +448,7 @@
                 throw e.rethrowAsRuntimeException();
             } finally {
                 setCallingAttributionSource(original);
-                Trace.traceEnd(TRACE_TAG_DATABASE);
+                Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
             }
         }
 
@@ -485,7 +485,7 @@
                     }
                 }
             }
-            traceBegin(TRACE_TAG_DATABASE, "applyBatch: ", authority);
+            traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "applyBatch: ", authority);
             final AttributionSource original = setCallingAttributionSource(
                     attributionSource);
             try {
@@ -504,7 +504,7 @@
                 throw e.rethrowAsRuntimeException();
             } finally {
                 setCallingAttributionSource(original);
-                Trace.traceEnd(TRACE_TAG_DATABASE);
+                Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
             }
         }
 
@@ -517,7 +517,7 @@
                     != PermissionChecker.PERMISSION_GRANTED) {
                 return 0;
             }
-            traceBegin(TRACE_TAG_DATABASE, "delete: ", uri.getAuthority());
+            traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "delete: ", uri.getAuthority());
             final AttributionSource original = setCallingAttributionSource(
                     attributionSource);
             try {
@@ -526,7 +526,7 @@
                 throw e.rethrowAsRuntimeException();
             } finally {
                 setCallingAttributionSource(original);
-                Trace.traceEnd(TRACE_TAG_DATABASE);
+                Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
             }
         }
 
@@ -539,7 +539,7 @@
                     != PermissionChecker.PERMISSION_GRANTED) {
                 return 0;
             }
-            traceBegin(TRACE_TAG_DATABASE, "update: ", uri.getAuthority());
+            traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "update: ", uri.getAuthority());
             final AttributionSource original = setCallingAttributionSource(
                     attributionSource);
             try {
@@ -548,7 +548,7 @@
                 throw e.rethrowAsRuntimeException();
             } finally {
                 setCallingAttributionSource(original);
-                Trace.traceEnd(TRACE_TAG_DATABASE);
+                Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
             }
         }
 
@@ -559,7 +559,7 @@
             uri = validateIncomingUri(uri);
             uri = maybeGetUriWithoutUserId(uri);
             enforceFilePermission(attributionSource, uri, mode);
-            traceBegin(TRACE_TAG_DATABASE, "openFile: ", uri.getAuthority());
+            traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "openFile: ", uri.getAuthority());
             final AttributionSource original = setCallingAttributionSource(
                     attributionSource);
             try {
@@ -569,7 +569,7 @@
                 throw e.rethrowAsRuntimeException();
             } finally {
                 setCallingAttributionSource(original);
-                Trace.traceEnd(TRACE_TAG_DATABASE);
+                Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
             }
         }
 
@@ -580,7 +580,7 @@
             uri = validateIncomingUri(uri);
             uri = maybeGetUriWithoutUserId(uri);
             enforceFilePermission(attributionSource, uri, mode);
-            traceBegin(TRACE_TAG_DATABASE, "openAssetFile: ", uri.getAuthority());
+            traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "openAssetFile: ", uri.getAuthority());
             final AttributionSource original = setCallingAttributionSource(
                     attributionSource);
             try {
@@ -590,7 +590,7 @@
                 throw e.rethrowAsRuntimeException();
             } finally {
                 setCallingAttributionSource(original);
-                Trace.traceEnd(TRACE_TAG_DATABASE);
+                Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
             }
         }
 
@@ -599,7 +599,7 @@
                 String method, @Nullable String arg, @Nullable Bundle extras) {
             validateIncomingAuthority(authority);
             Bundle.setDefusable(extras, true);
-            traceBegin(TRACE_TAG_DATABASE, "call: ", authority);
+            traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "call: ", authority);
             final AttributionSource original = setCallingAttributionSource(
                     attributionSource);
             try {
@@ -608,7 +608,7 @@
                 throw e.rethrowAsRuntimeException();
             } finally {
                 setCallingAttributionSource(original);
-                Trace.traceEnd(TRACE_TAG_DATABASE);
+                Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
             }
         }
 
@@ -617,13 +617,13 @@
             // getCallingPackage() isn't available in getType(), as the javadoc states.
             uri = validateIncomingUri(uri);
             uri = maybeGetUriWithoutUserId(uri);
-            traceBegin(TRACE_TAG_DATABASE, "getStreamTypes: ", uri.getAuthority());
+            traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "getStreamTypes: ", uri.getAuthority());
             try {
                 return mInterface.getStreamTypes(uri, mimeTypeFilter);
             } catch (RemoteException e) {
                 throw e.rethrowAsRuntimeException();
             } finally {
-                Trace.traceEnd(TRACE_TAG_DATABASE);
+                Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
             }
         }
 
@@ -635,7 +635,7 @@
             uri = validateIncomingUri(uri);
             uri = maybeGetUriWithoutUserId(uri);
             enforceFilePermission(attributionSource, uri, "r");
-            traceBegin(TRACE_TAG_DATABASE, "openTypedAssetFile: ", uri.getAuthority());
+            traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "openTypedAssetFile: ", uri.getAuthority());
             final AttributionSource original = setCallingAttributionSource(
                     attributionSource);
             try {
@@ -645,7 +645,7 @@
                 throw e.rethrowAsRuntimeException();
             } finally {
                 setCallingAttributionSource(original);
-                Trace.traceEnd(TRACE_TAG_DATABASE);
+                Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
             }
         }
 
@@ -663,7 +663,7 @@
                     != PermissionChecker.PERMISSION_GRANTED) {
                 return null;
             }
-            traceBegin(TRACE_TAG_DATABASE, "canonicalize: ", uri.getAuthority());
+            traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "canonicalize: ", uri.getAuthority());
             final AttributionSource original = setCallingAttributionSource(
                     attributionSource);
             try {
@@ -672,7 +672,7 @@
                 throw e.rethrowAsRuntimeException();
             } finally {
                 setCallingAttributionSource(original);
-                Trace.traceEnd(TRACE_TAG_DATABASE);
+                Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
             }
         }
 
@@ -699,7 +699,7 @@
                     != PermissionChecker.PERMISSION_GRANTED) {
                 return null;
             }
-            traceBegin(TRACE_TAG_DATABASE, "uncanonicalize: ", uri.getAuthority());
+            traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "uncanonicalize: ", uri.getAuthority());
             final AttributionSource original = setCallingAttributionSource(
                     attributionSource);
             try {
@@ -708,7 +708,7 @@
                 throw e.rethrowAsRuntimeException();
             } finally {
                 setCallingAttributionSource(original);
-                Trace.traceEnd(TRACE_TAG_DATABASE);
+                Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
             }
         }
 
@@ -735,7 +735,7 @@
                     != PermissionChecker.PERMISSION_GRANTED) {
                 return false;
             }
-            traceBegin(TRACE_TAG_DATABASE, "refresh: ", uri.getAuthority());
+            traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "refresh: ", uri.getAuthority());
             final AttributionSource original = setCallingAttributionSource(
                     attributionSource);
             try {
@@ -743,7 +743,7 @@
                         CancellationSignal.fromTransport(cancellationSignal));
             } finally {
                 setCallingAttributionSource(original);
-                Trace.traceEnd(TRACE_TAG_DATABASE);
+                Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
             }
         }
 
@@ -752,7 +752,7 @@
                 int uid, int modeFlags) {
             uri = validateIncomingUri(uri);
             uri = maybeGetUriWithoutUserId(uri);
-            traceBegin(TRACE_TAG_DATABASE, "checkUriPermission: ", uri.getAuthority());
+            traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "checkUriPermission: ", uri.getAuthority());
             final AttributionSource original = setCallingAttributionSource(
                     attributionSource);
             try {
@@ -761,7 +761,7 @@
                 throw e.rethrowAsRuntimeException();
             } finally {
                 setCallingAttributionSource(original);
-                Trace.traceEnd(TRACE_TAG_DATABASE);
+                Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
             }
         }
 
diff --git a/core/java/android/hardware/HardwareBuffer.java b/core/java/android/hardware/HardwareBuffer.java
index ddbfb9e..889a43c 100644
--- a/core/java/android/hardware/HardwareBuffer.java
+++ b/core/java/android/hardware/HardwareBuffer.java
@@ -40,7 +40,7 @@
  * HardwareBuffer wraps a native <code>AHardwareBuffer</code> object, which is a low-level object
  * representing a memory buffer accessible by various hardware units. HardwareBuffer allows sharing
  * buffers across different application processes. In particular, HardwareBuffers may be mappable
- * to memory accessibly to various hardware systems, such as the GPU, a sensor or context hub, or
+ * to memory accessible to various hardware systems, such as the GPU, a sensor or context hub, or
  * other auxiliary processing units.
  *
  * For more information, see the NDK documentation for <code>AHardwareBuffer</code>.
diff --git a/core/java/android/hardware/soundtrigger/ConversionUtil.java b/core/java/android/hardware/soundtrigger/ConversionUtil.java
index 9a2cd06..de18fa3 100644
--- a/core/java/android/hardware/soundtrigger/ConversionUtil.java
+++ b/core/java/android/hardware/soundtrigger/ConversionUtil.java
@@ -198,13 +198,13 @@
             int modelHandle, int captureSession, RecognitionEvent aidlEvent) {
         // The API recognition event doesn't allow for a null audio format, even though it doesn't
         // always make sense. We thus replace it with a default.
-        AudioFormat audioFormat = aidl2apiAudioFormatWithDefault(
-                aidlEvent.audioConfig, true /*isInput*/);
-        return new SoundTrigger.GenericRecognitionEvent(
-                aidlEvent.status,
-                modelHandle, aidlEvent.captureAvailable, captureSession,
-                aidlEvent.captureDelayMs, aidlEvent.capturePreambleMs, aidlEvent.triggerInData,
-                audioFormat, aidlEvent.data, aidlEvent.recognitionStillActive);
+        AudioFormat audioFormat = aidl2apiAudioFormatWithDefault(aidlEvent.audioConfig,
+                true /*isInput*/);
+        // TODO(b/265852186) propagate a timestamp from aidl interfaces
+        return new SoundTrigger.GenericRecognitionEvent(aidlEvent.status, modelHandle,
+                aidlEvent.captureAvailable, captureSession, aidlEvent.captureDelayMs,
+                aidlEvent.capturePreambleMs, aidlEvent.triggerInData, audioFormat, aidlEvent.data,
+                aidlEvent.recognitionStillActive, -1 /* halEventReceivedMillis */);
     }
 
     public static SoundTrigger.RecognitionEvent aidl2apiPhraseRecognitionEvent(
@@ -217,14 +217,13 @@
         }
         // The API recognition event doesn't allow for a null audio format, even though it doesn't
         // always make sense. We thus replace it with a default.
-        AudioFormat audioFormat = aidl2apiAudioFormatWithDefault(
-                aidlEvent.common.audioConfig, true /*isInput*/);
+        AudioFormat audioFormat = aidl2apiAudioFormatWithDefault(aidlEvent.common.audioConfig,
+                true /*isInput*/);
+        // TODO(b/265852186) propagate a timestamp from aidl interfaces
         return new SoundTrigger.KeyphraseRecognitionEvent(aidlEvent.common.status, modelHandle,
-                aidlEvent.common.captureAvailable,
-                captureSession, aidlEvent.common.captureDelayMs,
-                aidlEvent.common.capturePreambleMs, aidlEvent.common.triggerInData,
-                audioFormat, aidlEvent.common.data,
-                apiExtras);
+                aidlEvent.common.captureAvailable, captureSession, aidlEvent.common.captureDelayMs,
+                aidlEvent.common.capturePreambleMs, aidlEvent.common.triggerInData, audioFormat,
+                aidlEvent.common.data, apiExtras, -1 /* halEventReceivedMillis */);
     }
 
     // In case of a null input returns a non-null valid output.
diff --git a/core/java/android/hardware/soundtrigger/SoundTrigger.java b/core/java/android/hardware/soundtrigger/SoundTrigger.java
index b7a694c..01558a3 100644
--- a/core/java/android/hardware/soundtrigger/SoundTrigger.java
+++ b/core/java/android/hardware/soundtrigger/SoundTrigger.java
@@ -28,6 +28,7 @@
 
 import static java.util.Objects.requireNonNull;
 
+import android.annotation.ElapsedRealtimeLong;
 import android.annotation.IntDef;
 import android.annotation.IntRange;
 import android.annotation.NonNull;
@@ -36,17 +37,13 @@
 import android.annotation.SuppressLint;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
-import android.app.ActivityThread;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.media.AudioFormat;
-import android.media.permission.ClearCallingIdentityContext;
 import android.media.permission.Identity;
-import android.media.permission.SafeCloseable;
 import android.media.soundtrigger.Status;
 import android.media.soundtrigger_middleware.ISoundTriggerMiddlewareService;
 import android.media.soundtrigger_middleware.SoundTriggerModuleDescriptor;
-import android.os.Binder;
 import android.os.Build;
 import android.os.Handler;
 import android.os.IBinder;
@@ -56,6 +53,7 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.ServiceSpecificException;
+import android.os.SystemClock;
 import android.util.Log;
 
 import java.lang.annotation.Retention;
@@ -1182,23 +1180,38 @@
          * @hide
          */
         public final boolean recognitionStillActive;
+        /**
+         * Timestamp of when the trigger event from SoundTriggerHal was received by the
+         * framework.
+         *
+         * <p>Clock monotonic including suspend time or its equivalent on the system,
+         * in the same units and timebase as {@link SystemClock#elapsedRealtime()}.
+         *
+         * <p>Value represents elapsed realtime in milliseconds when the event was received from the
+         * HAL. The value will be -1 if the event was not generated from the HAL.
+         *
+         * @hide
+         */
+        @ElapsedRealtimeLong
+        public final long halEventReceivedMillis;
 
         /** @hide */
         @TestApi
         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
         public RecognitionEvent(int status, int soundModelHandle, boolean captureAvailable,
                 int captureSession, int captureDelayMs, int capturePreambleMs,
-                boolean triggerInData, @NonNull AudioFormat captureFormat, @Nullable byte[] data) {
-            this(status, soundModelHandle, captureAvailable, captureSession, captureDelayMs,
-                    capturePreambleMs, triggerInData, captureFormat, data,
-                    status == RECOGNITION_STATUS_GET_STATE_RESPONSE);
+                boolean triggerInData, @NonNull AudioFormat captureFormat, @Nullable byte[] data,
+                @ElapsedRealtimeLong long halEventReceivedMillis) {
+            this(status, soundModelHandle, captureAvailable,
+                    captureSession, captureDelayMs, capturePreambleMs, triggerInData, captureFormat,
+                    data, status == RECOGNITION_STATUS_GET_STATE_RESPONSE, halEventReceivedMillis);
         }
 
         /** @hide */
         public RecognitionEvent(int status, int soundModelHandle, boolean captureAvailable,
                 int captureSession, int captureDelayMs, int capturePreambleMs,
                 boolean triggerInData, @NonNull AudioFormat captureFormat, @Nullable byte[] data,
-                boolean recognitionStillActive) {
+                boolean recognitionStillActive, @ElapsedRealtimeLong long halEventReceivedMillis) {
             this.status = status;
             this.soundModelHandle = soundModelHandle;
             this.captureAvailable = captureAvailable;
@@ -1209,6 +1222,7 @@
             this.captureFormat = requireNonNull(captureFormat);
             this.data = data != null ? data : new byte[0];
             this.recognitionStillActive = recognitionStillActive;
+            this.halEventReceivedMillis = halEventReceivedMillis;
         }
 
         /**
@@ -1251,6 +1265,21 @@
             return data;
         }
 
+        /**
+         * Timestamp of when the trigger event from SoundTriggerHal was received by the
+         * framework.
+         *
+         * Clock monotonic including suspend time or its equivalent on the system,
+         * in the same units and timebase as {@link SystemClock#elapsedRealtime()}.
+         *
+         * @return Elapsed realtime in milliseconds when the event was received from the HAL.
+         *      Returns -1 if the event was not generated from the HAL.
+         */
+        @ElapsedRealtimeLong
+        public long getHalEventReceivedMillis() {
+            return halEventReceivedMillis;
+        }
+
         /** @hide */
         public static final @android.annotation.NonNull Parcelable.Creator<RecognitionEvent> CREATOR
                 = new Parcelable.Creator<RecognitionEvent>() {
@@ -1285,9 +1314,10 @@
             }
             byte[] data = in.readBlob();
             boolean recognitionStillActive = in.readBoolean();
+            long halEventReceivedMillis = in.readLong();
             return new RecognitionEvent(status, soundModelHandle, captureAvailable, captureSession,
                     captureDelayMs, capturePreambleMs, triggerInData, captureFormat, data,
-                    recognitionStillActive);
+                    recognitionStillActive, halEventReceivedMillis);
         }
 
         /** @hide */
@@ -1314,6 +1344,7 @@
             }
             dest.writeBlob(data);
             dest.writeBoolean(recognitionStillActive);
+            dest.writeLong(halEventReceivedMillis);
         }
         @Override
         public int hashCode() {
@@ -1333,6 +1364,7 @@
             result = prime * result + soundModelHandle;
             result = prime * result + status;
             result = result + (recognitionStillActive ? 1289 : 1291);
+            result = prime * result + Long.hashCode(halEventReceivedMillis);
             return result;
         }
 
@@ -1359,6 +1391,9 @@
                 return false;
             if (soundModelHandle != other.soundModelHandle)
                 return false;
+            if (halEventReceivedMillis != other.halEventReceivedMillis) {
+                return false;
+            }
             if (status != other.status)
                 return false;
             if (triggerInData != other.triggerInData)
@@ -1395,6 +1430,7 @@
                         (", channelMask=" + captureFormat.getChannelMask()))
                     + ", data=" + (data == null ? 0 : data.length)
                     + ", recognitionStillActive=" + recognitionStillActive
+                    + ", halEventReceivedMillis=" + halEventReceivedMillis
                     + "]";
         }
     }
@@ -1776,19 +1812,22 @@
         public KeyphraseRecognitionEvent(int status, int soundModelHandle, boolean captureAvailable,
                 int captureSession, int captureDelayMs, int capturePreambleMs,
                 boolean triggerInData, @NonNull AudioFormat captureFormat, @Nullable byte[] data,
-                @Nullable KeyphraseRecognitionExtra[] keyphraseExtras) {
+                @Nullable KeyphraseRecognitionExtra[] keyphraseExtras,
+                @ElapsedRealtimeLong long halEventReceivedMillis) {
             this(status, soundModelHandle, captureAvailable, captureSession, captureDelayMs,
                     capturePreambleMs, triggerInData, captureFormat, data, keyphraseExtras,
-                    status == RECOGNITION_STATUS_GET_STATE_RESPONSE);
+                    status == RECOGNITION_STATUS_GET_STATE_RESPONSE, halEventReceivedMillis);
         }
 
-        public KeyphraseRecognitionEvent(int status, int soundModelHandle, boolean captureAvailable,
+        public KeyphraseRecognitionEvent(int status, int soundModelHandle,
+                boolean captureAvailable,
                 int captureSession, int captureDelayMs, int capturePreambleMs,
                 boolean triggerInData, @NonNull AudioFormat captureFormat, @Nullable byte[] data,
                 @Nullable KeyphraseRecognitionExtra[] keyphraseExtras,
-                boolean recognitionStillActive) {
-            super(status, soundModelHandle, captureAvailable, captureSession, captureDelayMs,
-                    capturePreambleMs, triggerInData, captureFormat, data, recognitionStillActive);
+                boolean recognitionStillActive, @ElapsedRealtimeLong long halEventReceivedMillis) {
+            super(status, soundModelHandle, captureAvailable,
+                    captureSession, captureDelayMs, capturePreambleMs, triggerInData, captureFormat,
+                    data, recognitionStillActive, halEventReceivedMillis);
             this.keyphraseExtras =
                     keyphraseExtras != null ? keyphraseExtras : new KeyphraseRecognitionExtra[0];
         }
@@ -1825,11 +1864,13 @@
             }
             byte[] data = in.readBlob();
             boolean recognitionStillActive = in.readBoolean();
+            long halEventReceivedMillis = in.readLong();
             KeyphraseRecognitionExtra[] keyphraseExtras =
                     in.createTypedArray(KeyphraseRecognitionExtra.CREATOR);
-            return new KeyphraseRecognitionEvent(status, soundModelHandle, captureAvailable,
-                    captureSession, captureDelayMs, capturePreambleMs, triggerInData,
-                    captureFormat, data, keyphraseExtras, recognitionStillActive);
+            return new KeyphraseRecognitionEvent(status, soundModelHandle,
+                    captureAvailable, captureSession, captureDelayMs, capturePreambleMs,
+                    triggerInData, captureFormat, data, keyphraseExtras, recognitionStillActive,
+                    halEventReceivedMillis);
         }
 
         @Override
@@ -1851,6 +1892,7 @@
             }
             dest.writeBlob(data);
             dest.writeBoolean(recognitionStillActive);
+            dest.writeLong(halEventReceivedMillis);
             dest.writeTypedArray(keyphraseExtras, flags);
         }
 
@@ -1885,9 +1927,11 @@
         public String toString() {
             return "KeyphraseRecognitionEvent [keyphraseExtras=" + Arrays.toString(keyphraseExtras)
                     + ", status=" + status
-                    + ", soundModelHandle=" + soundModelHandle + ", captureAvailable="
-                    + captureAvailable + ", captureSession=" + captureSession + ", captureDelayMs="
-                    + captureDelayMs + ", capturePreambleMs=" + capturePreambleMs
+                    + ", soundModelHandle=" + soundModelHandle
+                    + ", captureAvailable=" + captureAvailable
+                    + ", captureSession=" + captureSession
+                    + ", captureDelayMs=" + captureDelayMs
+                    + ", capturePreambleMs=" + capturePreambleMs
                     + ", triggerInData=" + triggerInData
                     + ((captureFormat == null) ? "" :
                         (", sampleRate=" + captureFormat.getSampleRate()))
@@ -1897,6 +1941,7 @@
                         (", channelMask=" + captureFormat.getChannelMask()))
                     + ", data=" + (data == null ? 0 : data.length)
                     + ", recognitionStillActive=" + recognitionStillActive
+                    + ", halEventReceivedMillis=" + halEventReceivedMillis
                     + "]";
         }
     }
@@ -1909,21 +1954,23 @@
      */
     public static class GenericRecognitionEvent extends RecognitionEvent implements Parcelable {
         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-        public GenericRecognitionEvent(int status, int soundModelHandle,
-                boolean captureAvailable, int captureSession, int captureDelayMs,
-                int capturePreambleMs, boolean triggerInData, @NonNull AudioFormat captureFormat,
-                @Nullable byte[] data) {
-            this(status, soundModelHandle, captureAvailable, captureSession, captureDelayMs,
+        public GenericRecognitionEvent(int status, int soundModelHandle, boolean captureAvailable,
+                int captureSession, int captureDelayMs, int capturePreambleMs,
+                boolean triggerInData, @NonNull AudioFormat captureFormat, @Nullable byte[] data,
+                @ElapsedRealtimeLong long halEventReceivedMillis) {
+            this(status, soundModelHandle, captureAvailable,
+                    captureSession, captureDelayMs,
                     capturePreambleMs, triggerInData, captureFormat, data,
-                    status == RECOGNITION_STATUS_GET_STATE_RESPONSE);
+                    status == RECOGNITION_STATUS_GET_STATE_RESPONSE, halEventReceivedMillis);
         }
 
-        public GenericRecognitionEvent(int status, int soundModelHandle,
-                boolean captureAvailable, int captureSession, int captureDelayMs,
-                int capturePreambleMs, boolean triggerInData, @NonNull AudioFormat captureFormat,
-                @Nullable byte[] data, boolean recognitionStillActive) {
-            super(status, soundModelHandle, captureAvailable, captureSession, captureDelayMs,
-                    capturePreambleMs, triggerInData, captureFormat, data, recognitionStillActive);
+        public GenericRecognitionEvent(int status, int soundModelHandle, boolean captureAvailable,
+                int captureSession, int captureDelayMs, int capturePreambleMs,
+                boolean triggerInData, @NonNull AudioFormat captureFormat, @Nullable byte[] data,
+                boolean recognitionStillActive, @ElapsedRealtimeLong long halEventReceivedMillis) {
+            super(status, soundModelHandle, captureAvailable,
+                    captureSession, captureDelayMs, capturePreambleMs, triggerInData, captureFormat,
+                    data, recognitionStillActive, halEventReceivedMillis);
         }
 
         public static final @android.annotation.NonNull Parcelable.Creator<GenericRecognitionEvent> CREATOR
@@ -1942,7 +1989,7 @@
             return new GenericRecognitionEvent(event.status, event.soundModelHandle,
                     event.captureAvailable, event.captureSession, event.captureDelayMs,
                     event.capturePreambleMs, event.triggerInData, event.captureFormat, event.data,
-                    event.recognitionStillActive);
+                    event.recognitionStillActive, event.halEventReceivedMillis);
         }
 
         @Override
diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java
index e2af9b0..b749d69 100644
--- a/core/java/android/nfc/NfcAdapter.java
+++ b/core/java/android/nfc/NfcAdapter.java
@@ -420,6 +420,7 @@
     // Guarded by NfcAdapter.class
     static boolean sIsInitialized = false;
     static boolean sHasNfcFeature;
+    static boolean sHasCeFeature;
 
     // Final after first constructor, except for
     // attemptDeadServiceRecovery() when NFC crashes - we accept a best effort
@@ -616,11 +617,13 @@
             PackageManager pm;
             pm = context.getPackageManager();
             sHasNfcFeature = pm.hasSystemFeature(PackageManager.FEATURE_NFC);
-            boolean hasHceFeature =
+            sHasCeFeature =
                     pm.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION)
-                    || pm.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION_NFCF);
+                    || pm.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION_NFCF)
+                    || pm.hasSystemFeature(PackageManager.FEATURE_NFC_OFF_HOST_CARD_EMULATION_UICC)
+                    || pm.hasSystemFeature(PackageManager.FEATURE_NFC_OFF_HOST_CARD_EMULATION_ESE);
             /* is this device meant to have NFC */
-            if (!sHasNfcFeature && !hasHceFeature) {
+            if (!sHasNfcFeature && !sHasCeFeature) {
                 Log.v(TAG, "this device does not have NFC support");
                 throw new UnsupportedOperationException();
             }
@@ -643,7 +646,7 @@
                     throw new UnsupportedOperationException();
                 }
             }
-            if (hasHceFeature) {
+            if (sHasCeFeature) {
                 try {
                     sNfcFCardEmulationService = sService.getNfcFCardEmulationInterface();
                 } catch (RemoteException e) {
@@ -1669,7 +1672,7 @@
     @SystemApi
     @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
     public boolean enableSecureNfc(boolean enable) {
-        if (!sHasNfcFeature) {
+        if (!sHasNfcFeature && !sHasCeFeature) {
             throw new UnsupportedOperationException();
         }
         try {
@@ -1694,10 +1697,13 @@
      * Checks if the device supports Secure NFC functionality.
      *
      * @return True if device supports Secure NFC, false otherwise
-     * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
+     * @throws UnsupportedOperationException if FEATURE_NFC,
+     * FEATURE_NFC_HOST_CARD_EMULATION, FEATURE_NFC_HOST_CARD_EMULATION_NFCF,
+     * FEATURE_NFC_OFF_HOST_CARD_EMULATION_UICC and FEATURE_NFC_OFF_HOST_CARD_EMULATION_ESE
+     * are unavailable
      */
     public boolean isSecureNfcSupported() {
-        if (!sHasNfcFeature) {
+        if (!sHasNfcFeature && !sHasCeFeature) {
             throw new UnsupportedOperationException();
         }
         try {
@@ -1723,11 +1729,14 @@
      * such as their relative positioning on the device.
      *
      * @return Information on the nfc antenna(s) on the device.
-     * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
+     * @throws UnsupportedOperationException if FEATURE_NFC,
+     * FEATURE_NFC_HOST_CARD_EMULATION, FEATURE_NFC_HOST_CARD_EMULATION_NFCF,
+     * FEATURE_NFC_OFF_HOST_CARD_EMULATION_UICC and FEATURE_NFC_OFF_HOST_CARD_EMULATION_ESE
+     * are unavailable
      */
     @Nullable
     public NfcAntennaInfo getNfcAntennaInfo() {
-        if (!sHasNfcFeature) {
+        if (!sHasNfcFeature && !sHasCeFeature) {
             throw new UnsupportedOperationException();
         }
         try {
@@ -1752,12 +1761,15 @@
      * Checks Secure NFC feature is enabled.
      *
      * @return True if Secure NFC is enabled, false otherwise
-     * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
+     * @throws UnsupportedOperationException if FEATURE_NFC,
+     * FEATURE_NFC_HOST_CARD_EMULATION, FEATURE_NFC_HOST_CARD_EMULATION_NFCF,
+     * FEATURE_NFC_OFF_HOST_CARD_EMULATION_UICC and FEATURE_NFC_OFF_HOST_CARD_EMULATION_ESE
+     * are unavailable
      * @throws UnsupportedOperationException if device doesn't support
      *         Secure NFC functionality. {@link #isSecureNfcSupported}
      */
     public boolean isSecureNfcEnabled() {
-        if (!sHasNfcFeature) {
+        if (!sHasNfcFeature && !sHasCeFeature) {
             throw new UnsupportedOperationException();
         }
         try {
@@ -2071,14 +2083,17 @@
      * always on.
      * @param value if true the NFCC will be kept on (with no RF enabled if NFC adapter is
      * disabled), if false the NFCC will follow completely the Nfc adapter state.
-     * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
+     * @throws UnsupportedOperationException if FEATURE_NFC,
+     * FEATURE_NFC_HOST_CARD_EMULATION, FEATURE_NFC_HOST_CARD_EMULATION_NFCF,
+     * FEATURE_NFC_OFF_HOST_CARD_EMULATION_UICC and FEATURE_NFC_OFF_HOST_CARD_EMULATION_ESE
+     * are unavailable
      * @return void
      * @hide
      */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON)
     public boolean setControllerAlwaysOn(boolean value) {
-        if (!sHasNfcFeature) {
+        if (!sHasNfcFeature && !sHasCeFeature) {
             throw new UnsupportedOperationException();
         }
         try {
@@ -2103,7 +2118,10 @@
      * Checks NFC controller always on feature is enabled.
      *
      * @return True if NFC controller always on is enabled, false otherwise
-     * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
+     * @throws UnsupportedOperationException if FEATURE_NFC,
+     * FEATURE_NFC_HOST_CARD_EMULATION, FEATURE_NFC_HOST_CARD_EMULATION_NFCF,
+     * FEATURE_NFC_OFF_HOST_CARD_EMULATION_UICC and FEATURE_NFC_OFF_HOST_CARD_EMULATION_ESE
+     * are unavailable
      * @hide
      */
     @SystemApi
@@ -2131,13 +2149,16 @@
      * Checks if the device supports NFC controller always on functionality.
      *
      * @return True if device supports NFC controller always on, false otherwise
-     * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
+     * @throws UnsupportedOperationException if FEATURE_NFC,
+     * FEATURE_NFC_HOST_CARD_EMULATION, FEATURE_NFC_HOST_CARD_EMULATION_NFCF,
+     * FEATURE_NFC_OFF_HOST_CARD_EMULATION_UICC and FEATURE_NFC_OFF_HOST_CARD_EMULATION_ESE
+     * are unavailable
      * @hide
      */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON)
     public boolean isControllerAlwaysOnSupported() {
-        if (!sHasNfcFeature) {
+        if (!sHasNfcFeature && !sHasCeFeature) {
             throw new UnsupportedOperationException();
         }
         try {
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 9689be2..168db17 100755
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -1204,6 +1204,11 @@
          * Upside Down Cake.
          */
         public static final int UPSIDE_DOWN_CAKE = CUR_DEVELOPMENT;
+
+        /**
+         * Vanilla Ice Cream.
+         */
+        public static final int VANILLA_ICE_CREAM = CUR_DEVELOPMENT;
     }
 
     /** The type of build, like "user" or "eng". */
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 290f929..08aea8e 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -1818,6 +1818,13 @@
     public static final int REMOVE_RESULT_ALREADY_BEING_REMOVED = 2;
 
     /**
+     * A response code indicating that the specified user is removable.
+     *
+     * @hide
+     */
+    public static final int REMOVE_RESULT_USER_IS_REMOVABLE = 3;
+
+    /**
      * A response code from {@link #removeUserWhenPossible(UserHandle, boolean)} indicating that
      * an unknown error occurred that prevented the user from being removed or set as ephemeral.
      *
@@ -1872,6 +1879,7 @@
             REMOVE_RESULT_REMOVED,
             REMOVE_RESULT_DEFERRED,
             REMOVE_RESULT_ALREADY_BEING_REMOVED,
+            REMOVE_RESULT_USER_IS_REMOVABLE,
             REMOVE_RESULT_ERROR_USER_RESTRICTION,
             REMOVE_RESULT_ERROR_USER_NOT_FOUND,
             REMOVE_RESULT_ERROR_SYSTEM_USER,
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index ef00774..ac78fbc 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -4385,6 +4385,16 @@
                 = "wear_accessibility_gesture_enabled";
 
         /**
+         * If the triple press gesture for toggling accessibility is enabled during OOBE.
+         * Set to 1 for true and 0 for false.
+         *
+         * This setting is used only internally.
+         * @hide
+         */
+        public static final String WEAR_ACCESSIBILITY_GESTURE_ENABLED_DURING_OOBE =
+                "wear_accessibility_gesture_enabled_during_oobe";
+
+        /**
          * @deprecated Use {@link android.provider.Settings.Global#AIRPLANE_MODE_ON} instead
          */
         @Deprecated
@@ -5766,6 +5776,7 @@
             PRIVATE_SETTINGS.add(END_BUTTON_BEHAVIOR);
             PRIVATE_SETTINGS.add(ADVANCED_SETTINGS);
             PRIVATE_SETTINGS.add(WEAR_ACCESSIBILITY_GESTURE_ENABLED);
+            PRIVATE_SETTINGS.add(WEAR_ACCESSIBILITY_GESTURE_ENABLED_DURING_OOBE);
             PRIVATE_SETTINGS.add(SCREEN_AUTO_BRIGHTNESS_ADJ);
             PRIVATE_SETTINGS.add(VIBRATE_INPUT_DEVICES);
             PRIVATE_SETTINGS.add(VOLUME_MASTER);
diff --git a/core/java/android/service/voice/AlwaysOnHotwordDetector.java b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
index b1dc686..4687855 100644
--- a/core/java/android/service/voice/AlwaysOnHotwordDetector.java
+++ b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
@@ -20,6 +20,7 @@
 import static android.Manifest.permission.RECORD_AUDIO;
 import static android.service.voice.VoiceInteractionService.MULTIPLE_ACTIVE_HOTWORD_DETECTORS;
 
+import android.annotation.ElapsedRealtimeLong;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -54,6 +55,7 @@
 import android.os.PersistableBundle;
 import android.os.RemoteException;
 import android.os.SharedMemory;
+import android.os.SystemClock;
 import android.text.TextUtils;
 import android.util.Log;
 import android.util.Slog;
@@ -401,6 +403,9 @@
         private final ParcelFileDescriptor mAudioStream;
         private final List<KeyphraseRecognitionExtra> mKephraseExtras;
 
+        @ElapsedRealtimeLong
+        private final long mHalEventReceivedMillis;
+
         private EventPayload(boolean captureAvailable,
                 @Nullable AudioFormat audioFormat,
                 int captureSession,
@@ -408,7 +413,8 @@
                 @Nullable byte[] data,
                 @Nullable HotwordDetectedResult hotwordDetectedResult,
                 @Nullable ParcelFileDescriptor audioStream,
-                @NonNull List<KeyphraseRecognitionExtra> keyphraseExtras) {
+                @NonNull List<KeyphraseRecognitionExtra> keyphraseExtras,
+                @ElapsedRealtimeLong long halEventReceivedMillis) {
             mCaptureAvailable = captureAvailable;
             mCaptureSession = captureSession;
             mAudioFormat = audioFormat;
@@ -417,6 +423,7 @@
             mHotwordDetectedResult = hotwordDetectedResult;
             mAudioStream = audioStream;
             mKephraseExtras = keyphraseExtras;
+            mHalEventReceivedMillis = halEventReceivedMillis;
         }
 
         /**
@@ -546,6 +553,20 @@
         }
 
         /**
+         * Timestamp of when the trigger event from SoundTriggerHal was received by the framework.
+         *
+         * Clock monotonic including suspend time or its equivalent on the system,
+         * in the same units and timebase as {@link SystemClock#elapsedRealtime()}.
+         *
+         * @return Elapsed realtime in milliseconds when the event was received from the HAL.
+         *      Returns -1 if the event was not generated from the HAL.
+         */
+        @ElapsedRealtimeLong
+        public long getHalEventReceivedMillis() {
+            return mHalEventReceivedMillis;
+        }
+
+        /**
          * Builder class for {@link EventPayload} objects
          *
          * @hide
@@ -561,6 +582,8 @@
             private HotwordDetectedResult mHotwordDetectedResult = null;
             private ParcelFileDescriptor mAudioStream = null;
             private List<KeyphraseRecognitionExtra> mKeyphraseExtras = Collections.emptyList();
+            @ElapsedRealtimeLong
+            private long mHalEventReceivedMillis = -1;
 
             public Builder() {}
 
@@ -579,6 +602,7 @@
                     setKeyphraseRecognitionExtras(
                             Arrays.asList(keyphraseRecognitionEvent.keyphraseExtras));
                 }
+                setHalEventReceivedMillis(keyphraseRecognitionEvent.getHalEventReceivedMillis());
             }
 
             /**
@@ -682,13 +706,27 @@
             }
 
             /**
+             * Timestamp of when the trigger event from SoundTriggerHal was received by the
+             * framework.
+             *
+             * Clock monotonic including suspend time or its equivalent on the system,
+             * in the same units and timebase as {@link SystemClock#elapsedRealtime()}.
+             */
+            @NonNull
+            public Builder setHalEventReceivedMillis(
+                    @ElapsedRealtimeLong long halEventReceivedMillis) {
+                mHalEventReceivedMillis = halEventReceivedMillis;
+                return this;
+            }
+
+            /**
              * Builds an {@link EventPayload} instance
              */
             @NonNull
             public EventPayload build() {
                 return new EventPayload(mCaptureAvailable, mAudioFormat, mCaptureSession,
                         mDataFormat, mData, mHotwordDetectedResult, mAudioStream,
-                        mKeyphraseExtras);
+                        mKeyphraseExtras, mHalEventReceivedMillis);
             }
         }
     }
@@ -905,8 +943,9 @@
     @TestApi
     @RequiresPermission(allOf = {RECORD_AUDIO, CAPTURE_AUDIO_HOTWORD})
     public void triggerHardwareRecognitionEventForTest(int status, int soundModelHandle,
-            boolean captureAvailable, int captureSession, int captureDelayMs, int capturePreambleMs,
-            boolean triggerInData, @NonNull AudioFormat captureFormat, @Nullable byte[] data,
+            @ElapsedRealtimeLong long halEventReceivedMillis, boolean captureAvailable,
+            int captureSession, int captureDelayMs, int capturePreambleMs, boolean triggerInData,
+            @NonNull AudioFormat captureFormat, @Nullable byte[] data,
             @NonNull List<KeyphraseRecognitionExtra> keyphraseRecognitionExtras) {
         Log.d(TAG, "triggerHardwareRecognitionEventForTest()");
         synchronized (mLock) {
@@ -919,7 +958,7 @@
                         new KeyphraseRecognitionEvent(status, soundModelHandle, captureAvailable,
                                 captureSession, captureDelayMs, capturePreambleMs, triggerInData,
                                 captureFormat, data, keyphraseRecognitionExtras.toArray(
-                                new KeyphraseRecognitionExtra[0])),
+                                new KeyphraseRecognitionExtra[0]), halEventReceivedMillis),
                         mInternalCallback);
             } catch (RemoteException e) {
                 throw e.rethrowFromSystemServer();
diff --git a/core/java/android/window/TransitionInfo.java b/core/java/android/window/TransitionInfo.java
index 0b43eb5..b8bd703 100644
--- a/core/java/android/window/TransitionInfo.java
+++ b/core/java/android/window/TransitionInfo.java
@@ -144,8 +144,11 @@
     /** The window should have no animation (by policy). */
     public static final int FLAG_NO_ANIMATION = 1 << 18;
 
+    /** The task is launching behind home. */
+    public static final int FLAG_TASK_LAUNCHING_BEHIND = 1 << 19;
+
     /** The first unused bit. This can be used by remotes to attach custom flags to this change. */
-    public static final int FLAG_FIRST_CUSTOM = 1 << 19;
+    public static final int FLAG_FIRST_CUSTOM = 1 << 20;
 
     /** The change belongs to a window that won't contain activities. */
     public static final int FLAGS_IS_NON_APP_WINDOW =
@@ -173,6 +176,7 @@
             FLAG_IS_SYSTEM_WINDOW,
             FLAG_BACK_GESTURE_ANIMATED,
             FLAG_NO_ANIMATION,
+            FLAG_TASK_LAUNCHING_BEHIND,
             FLAG_FIRST_CUSTOM
     })
     public @interface ChangeFlags {}
@@ -395,6 +399,9 @@
         if ((flags & FLAG_NO_ANIMATION) != 0) {
             sb.append(sb.length() == 0 ? "" : "|").append("NO_ANIMATION");
         }
+        if ((flags & FLAG_TASK_LAUNCHING_BEHIND) != 0) {
+            sb.append((sb.length() == 0 ? "" : "|") + "TASK_LAUNCHING_BEHIND");
+        }
         if ((flags & FLAG_FIRST_CUSTOM) != 0) {
             sb.append(sb.length() == 0 ? "" : "|").append("FIRST_CUSTOM");
         }
diff --git a/core/java/com/android/internal/app/procstats/UidState.java b/core/java/com/android/internal/app/procstats/UidState.java
index 8761b74..4911346 100644
--- a/core/java/com/android/internal/app/procstats/UidState.java
+++ b/core/java/com/android/internal/app/procstats/UidState.java
@@ -150,6 +150,7 @@
     public void resetSafely(long now) {
         mDurations.resetTable();
         mStartTime = now;
+        mProcesses.removeIf(p -> !p.isInUse());
     }
 
     /**
diff --git a/core/java/com/android/internal/util/LatencyTracker.java b/core/java/com/android/internal/util/LatencyTracker.java
index 2d5bb6c..c808d92 100644
--- a/core/java/com/android/internal/util/LatencyTracker.java
+++ b/core/java/com/android/internal/util/LatencyTracker.java
@@ -35,6 +35,7 @@
 import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_SHOW_BACK_ARROW;
 import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_SHOW_SELECTION_TOOLBAR;
 import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_SHOW_VOICE_INTERACTION;
+import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_SMARTSPACE_DOORBELL;
 import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_START_RECENTS_ANIMATION;
 import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_SWITCH_DISPLAY_UNFOLD;
 import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_TOGGLE_RECENTS;
@@ -205,6 +206,15 @@
      */
     public static final int ACTION_REQUEST_IME_HIDDEN = 21;
 
+    /**
+     * Time it takes to load the animation frames in smart space doorbell card.
+     * It measures the duration from the images uris are passed into the view
+     * to all the frames are loaded.
+     * <p/>
+     * A long latency makes the doorbell animation looks janky until all the frames are loaded.
+     */
+    public static final int ACTION_SMARTSPACE_DOORBELL = 22;
+
     private static final int[] ACTIONS_ALL = {
         ACTION_EXPAND_PANEL,
         ACTION_TOGGLE_RECENTS,
@@ -228,6 +238,7 @@
         ACTION_SHOW_VOICE_INTERACTION,
         ACTION_REQUEST_IME_SHOWN,
         ACTION_REQUEST_IME_HIDDEN,
+        ACTION_SMARTSPACE_DOORBELL,
     };
 
     /** @hide */
@@ -254,6 +265,7 @@
         ACTION_SHOW_VOICE_INTERACTION,
         ACTION_REQUEST_IME_SHOWN,
         ACTION_REQUEST_IME_HIDDEN,
+        ACTION_SMARTSPACE_DOORBELL,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface Action {
@@ -283,6 +295,7 @@
             UIACTION_LATENCY_REPORTED__ACTION__ACTION_SHOW_VOICE_INTERACTION,
             UIACTION_LATENCY_REPORTED__ACTION__ACTION_REQUEST_IME_SHOWN,
             UIACTION_LATENCY_REPORTED__ACTION__ACTION_REQUEST_IME_HIDDEN,
+            UIACTION_LATENCY_REPORTED__ACTION__ACTION_SMARTSPACE_DOORBELL,
     };
 
     private static LatencyTracker sLatencyTracker;
@@ -411,6 +424,8 @@
                 return "ACTION_REQUEST_IME_SHOWN";
             case UIACTION_LATENCY_REPORTED__ACTION__ACTION_REQUEST_IME_HIDDEN:
                 return "ACTION_REQUEST_IME_HIDDEN";
+            case UIACTION_LATENCY_REPORTED__ACTION__ACTION_SMARTSPACE_DOORBELL:
+                return "ACTION_SMARTSPACE_DOORBELL";
             default:
                 throw new IllegalArgumentException("Invalid action");
         }
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index b86020e..6fc6dc1 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -1075,13 +1075,6 @@
     }
 
     /**
-     * Set whether the visible password is enabled for cryptkeeper screen.
-     */
-    public void setVisiblePasswordEnabled(boolean enabled, int userId) {
-        // No longer does anything.
-    }
-
-    /**
      * Set and store the lockout deadline, meaning the user can't attempt their unlock
      * pattern until the deadline has passed.
      * @return the chosen deadline.
diff --git a/core/res/res/color-watch/btn_watch_default_dark.xml b/core/res/res/color-watch/btn_watch_default_dark.xml
index 68b0eb6..333b44b 100644
--- a/core/res/res/color-watch/btn_watch_default_dark.xml
+++ b/core/res/res/color-watch/btn_watch_default_dark.xml
@@ -17,6 +17,6 @@
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:state_enabled="false"
           android:alpha="?attr/disabledAlpha"
-          android:color="?attr/colorPrimaryDark"/>
-    <item android:color="?attr/colorPrimaryDark"/>
+          android:color="?attr/colorSurface"/>
+    <item android:color="?attr/colorSurface"/>
 </selector>
diff --git a/core/res/res/color-watch/switch_track_watch_default_dark.xml b/core/res/res/color-watch/switch_track_watch_default_dark.xml
index 15bbeda..5af2566 100644
--- a/core/res/res/color-watch/switch_track_watch_default_dark.xml
+++ b/core/res/res/color-watch/switch_track_watch_default_dark.xml
@@ -17,6 +17,6 @@
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:state_enabled="false"
           android:alpha="?attr/disabledAlpha"
-          android:color="?android:colorPrimaryDark" />
-    <item android:color="?android:colorPrimaryDark" />
+          android:color="?android:colorSurface" />
+    <item android:color="?android:colorSurface" />
 </selector>
diff --git a/core/res/res/values-watch/colors_device_defaults.xml b/core/res/res/values-watch/colors_device_defaults.xml
index 6ffd6e6..ee9481c 100644
--- a/core/res/res/values-watch/colors_device_defaults.xml
+++ b/core/res/res/values-watch/colors_device_defaults.xml
@@ -16,102 +16,51 @@
 
 <!-- Colors specific to Theme.DeviceDefault on watches, as specified via themes_device_default.xml
      Note: These colors specifically proide a darker, high-contrast UI that is suitable for
-     wearables with respect to 'glanceability'. OEM customization is supported within this set. -->
+     wearables with respect to 'glanceability'. -->
 <resources>
     <!--
        accent_device_default_dark
-         > from values/colors_material/accent_material_dark
-         > from values/colors_material/material_deep_teal_200
-         = #ff80cbc4
-         ! replaced with custom color #5E97F6
-         ! OEMS can customize as per specification
+         > from values/system_accent1_100
+         ! replaced with color/system_accent1_400
     -->
-    <color name="accent_device_default_dark">#5E97F6</color>
+    <color name="accent_device_default_dark">@color/system_accent1_400</color>
 
     <!--
        foreground_device_default_dark
          - introduced to avoid coupling to foreground_material_dark
          - colorForeground typically falls through Theme.DeviceDefault to Theme.Material
          ! fixed as white for optimal glanceability/contrast
-         ! OEMs should not customize
     -->
     <color name="foreground_device_default_dark">@color/white</color>
 
     <!--
        background_device_default_dark
-         > from values/colors_material/background_material_dark
-         > from values/colors_material/material_grey_850
-         = #ff303030
+         > from values/system_neutral1_900
          ! replaced with custom color #000000
-         ! OEMs can customized as per specification
-           (derived from accent color, constrained by brightness)
     -->
     <color name="background_device_default_dark">#000000</color>
 
-    <!--
-       background_floating_device_default_dark
-         > from values/colors_material/background_floating_material_dark
-         > from values/colors_material/material_grey_800
-         = #ff424242
-         ! replaced with custom color #1D2E4D
-           (derived from accent color, constrained by brightness)
-    -->
-    <color name="background_floating_device_default_dark">#1D2E4D</color>
+    <!-- Derived from accent color at 20% luminance -->
+    <color name="background_floating_device_default_dark">@color/system_accent1_800</color>
 
     <!--
-       primary_device_default_dark
-         > from values/colors_material/primary_material_dark
-         > from values/colors_material/material_grey_900
-         = #ff212121
-         ! replaced with custom color #808080
-         ! OEMs can customize as per specification
-           (derived from background color + foreground @ 50% opacity)
-    -->
-    <color name="primary_device_default_dark">#808080</color>
+        primary_device_default_dark
+          > from values/colors/system_neutral1_900
+          ! replaced with system_neutral1_500
+     -->
+    <color name="primary_device_default_dark">@color/system_neutral1_500</color>
 
-    <!--
-       primary_dark_device_default_dark
-         > from values/colors_material/primary_dark_material_dark
-         = @color/black
-         ! replaced with custom color #333333
-         ! OEMS can customize as per specification
-           (derived from background color + foreground @ 20% opacity)
-    -->
-    <color name="primary_dark_device_default_dark">#333333</color>
+    <!-- Currently matches the "surface dark" definition for phones. -->
+    <color name="surface_dark">@color/system_neutral1_800</color>
 
     <!--
        button_normal_device_default_dark
-         - uses ?attr/disabledAlpha and ?attr/colorPrimaryDark to draw state list
+         - uses ?attr/disabledAlpha and ?attr/colorSurface to draw state list
            (used as colorButtonNormal attribute in theme)
          - see color-watch/btn_watch_default_dark.xml
     -->
     <color name="button_normal_device_default_dark">@color/btn_watch_default_dark</color>
 
-    <!--
-       error_color_device_default_dark
-         - introduced to avoid coupling to error_color_mtterial (also #F4511E)
-         - colorError typically falls through Theme.DeviceDefault to Theme.Material
-         ! OEMs can customize as per specification
-    -->
-    <color name="error_color_device_default_dark">#F4511E</color>
-
-    <!-- no customization required/suggested below this point -->
-
-    <!--
-       background_cache_hint_selector_device_default
-         - note that this is based off of colors/background_cache_hint_selector_device_default
-           xml drawable
-         - uses ?attr/colorBackground and transparency to draw
-         - no color customization required here
-    -->
-
-    <!-- deprecated for Wear
-         these overrides exist only for compatibility with existing
-         WTS theme test heuristics, based on the previous modifications
-         to the material theme, they should not be used for customization
-         as they are not exposed via publicly accessible attributes -->
-    <color name="accent_device_default_dark_60_percent_opacity">#995E97f6</color>
-    <color name="accent_device_default_700">#5385DB</color>
-    <color name="accent_device_default_light">#75A4F5</color>
-    <color name="accent_device_default_50">#93B7F5</color>
+    <!-- Matches the Wear Compose error color. -->
+    <color name="error_color_device_default_dark">#FF746E</color>
 </resources>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 2a67b44..a21009f2f 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -9142,10 +9142,10 @@
              {@link android.os.Build.VERSION_CODES#N} and not used in previous versions. -->
         <attr name="supportsLocalInteraction" format="boolean" />
         <!-- The service that provides {@link android.service.voice.HotwordDetectionService}.
-             @hide @SystemApi -->
+             Expect a component name to be provided. @hide @SystemApi -->
         <attr name="hotwordDetectionService" format="string" />
         <!-- The service that provides {@link android.service.voice.VisualQueryDetectionService}.
-             @hide @SystemApi -->
+             Expect a component name to be provided. @hide @SystemApi -->
         <attr name="visualQueryDetectionService" format="string" />
 
     </declare-styleable>
diff --git a/core/tests/coretests/src/android/animation/AnimatorSetCallsTest.java b/core/tests/coretests/src/android/animation/AnimatorSetCallsTest.java
new file mode 100644
index 0000000..22da0aa
--- /dev/null
+++ b/core/tests/coretests/src/android/animation/AnimatorSetCallsTest.java
@@ -0,0 +1,301 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.animation;
+
+import static org.junit.Assert.assertEquals;
+
+import android.util.PollingCheck;
+import android.view.View;
+
+import androidx.test.ext.junit.rules.ActivityScenarioRule;
+import androidx.test.filters.MediumTest;
+
+import com.android.frameworks.coretests.R;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import java.util.ArrayList;
+
+@MediumTest
+public class AnimatorSetCallsTest {
+    @Rule
+    public final ActivityScenarioRule<AnimatorSetActivity> mRule =
+            new ActivityScenarioRule<>(AnimatorSetActivity.class);
+
+    private AnimatorSetActivity mActivity;
+    private AnimatorSet mSet1;
+    private ObjectAnimator mAnimator;
+    private CountListener mListener1;
+    private CountListener mListener2;
+    private CountListener mListener3;
+
+    @Before
+    public void setUp() throws Exception {
+        mRule.getScenario().onActivity((activity) -> {
+            mActivity = activity;
+            View square = mActivity.findViewById(R.id.square1);
+
+            mSet1 = new AnimatorSet();
+            mListener1 = new CountListener();
+            mSet1.addListener(mListener1);
+            mSet1.addPauseListener(mListener1);
+
+            AnimatorSet set2 = new AnimatorSet();
+            mListener2 = new CountListener();
+            set2.addListener(mListener2);
+            set2.addPauseListener(mListener2);
+
+            mAnimator = ObjectAnimator.ofFloat(square, "translationX", 0f, 100f);
+            mListener3 = new CountListener();
+            mAnimator.addListener(mListener3);
+            mAnimator.addPauseListener(mListener3);
+            mAnimator.setDuration(1);
+
+            set2.play(mAnimator);
+            mSet1.play(set2);
+        });
+    }
+
+    @Test
+    public void startEndCalledOnChildren() {
+        mRule.getScenario().onActivity((a) -> mSet1.start());
+        waitForOnUiThread(() -> mListener1.endForward > 0);
+
+        // only startForward and endForward should have been called once
+        mListener1.assertValues(
+                1, 0, 1, 0, 0, 0, 0, 0
+        );
+        mListener2.assertValues(
+                1, 0, 1, 0, 0, 0, 0, 0
+        );
+        mListener3.assertValues(
+                1, 0, 1, 0, 0, 0, 0, 0
+        );
+    }
+
+    @Test
+    public void cancelCalledOnChildren() {
+        mRule.getScenario().onActivity((a) -> {
+            mSet1.start();
+            mSet1.cancel();
+        });
+        waitForOnUiThread(() -> mListener1.endForward > 0);
+
+        // only startForward and endForward should have been called once
+        mListener1.assertValues(
+                1, 0, 1, 0, 1, 0, 0, 0
+        );
+        mListener2.assertValues(
+                1, 0, 1, 0, 1, 0, 0, 0
+        );
+        mListener3.assertValues(
+                1, 0, 1, 0, 1, 0, 0, 0
+        );
+    }
+
+    @Test
+    public void startEndReversedCalledOnChildren() {
+        mRule.getScenario().onActivity((a) -> mSet1.reverse());
+        waitForOnUiThread(() -> mListener1.endReverse > 0);
+
+        // only startForward and endForward should have been called once
+        mListener1.assertValues(
+                0, 1, 0, 1, 0, 0, 0, 0
+        );
+        mListener2.assertValues(
+                0, 1, 0, 1, 0, 0, 0, 0
+        );
+        mListener3.assertValues(
+                0, 1, 0, 1, 0, 0, 0, 0
+        );
+    }
+
+    @Test
+    public void pauseResumeCalledOnChildren() {
+        mRule.getScenario().onActivity((a) -> {
+            mSet1.start();
+            mSet1.pause();
+        });
+        waitForOnUiThread(() -> mListener1.pause > 0);
+
+        // only startForward and pause should have been called once
+        mListener1.assertValues(
+                1, 0, 0, 0, 0, 0, 1, 0
+        );
+        mListener2.assertValues(
+                1, 0, 0, 0, 0, 0, 1, 0
+        );
+        mListener3.assertValues(
+                1, 0, 0, 0, 0, 0, 1, 0
+        );
+
+        mRule.getScenario().onActivity((a) -> mSet1.resume());
+        waitForOnUiThread(() -> mListener1.endForward > 0);
+
+        // resume and endForward should have been called once
+        mListener1.assertValues(
+                1, 0, 1, 0, 0, 0, 1, 1
+        );
+        mListener2.assertValues(
+                1, 0, 1, 0, 0, 0, 1, 1
+        );
+        mListener3.assertValues(
+                1, 0, 1, 0, 0, 0, 1, 1
+        );
+    }
+
+    @Test
+    public void updateOnlyWhileChangingValues() {
+        ArrayList<Float> updateValues = new ArrayList<>();
+        mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator animation) {
+                updateValues.add((Float) animation.getAnimatedValue());
+            }
+        });
+
+        mSet1.setCurrentPlayTime(0);
+
+        assertEquals(1, updateValues.size());
+        assertEquals(0f, updateValues.get(0), 0f);
+    }
+    @Test
+    public void updateOnlyWhileRunning() {
+        ArrayList<Float> updateValues = new ArrayList<>();
+        mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator animation) {
+                updateValues.add((Float) animation.getAnimatedValue());
+            }
+        });
+
+        mRule.getScenario().onActivity((a) -> {
+            mSet1.start();
+        });
+
+        waitForOnUiThread(() -> mListener1.endForward > 0);
+
+        // the duration is only 1ms, so there should only be two values, 0 and 100.
+        assertEquals(0f, updateValues.get(0), 0f);
+        assertEquals(100f, updateValues.get(updateValues.size() - 1), 0f);
+
+        // now check all the values in the middle, which can never go from 100->0.
+        boolean isAtEnd = false;
+        for (int i = 1; i < updateValues.size() - 1; i++) {
+            float actual = updateValues.get(i);
+            if (actual == 100f) {
+                isAtEnd = true;
+            }
+            float expected = isAtEnd ? 100f : 0f;
+            assertEquals(expected, actual, 0f);
+        }
+    }
+
+    private void waitForOnUiThread(PollingCheck.PollingCheckCondition condition) {
+        final boolean[] value = new boolean[1];
+        PollingCheck.waitFor(() -> {
+            mActivity.runOnUiThread(() -> value[0] = condition.canProceed());
+            return value[0];
+        });
+    }
+
+    private static class CountListener implements Animator.AnimatorListener,
+            Animator.AnimatorPauseListener {
+        public int startNoParam;
+        public int endNoParam;
+        public int startReverse;
+        public int startForward;
+        public int endForward;
+        public int endReverse;
+        public int cancel;
+        public int repeat;
+        public int pause;
+        public int resume;
+
+        public void assertValues(
+                int startForward,
+                int startReverse,
+                int endForward,
+                int endReverse,
+                int cancel,
+                int repeat,
+                int pause,
+                int resume
+        ) {
+            assertEquals(0, startNoParam);
+            assertEquals(0, endNoParam);
+            assertEquals(startForward, this.startForward);
+            assertEquals(startReverse, this.startReverse);
+            assertEquals(endForward, this.endForward);
+            assertEquals(endReverse, this.endReverse);
+            assertEquals(cancel, this.cancel);
+            assertEquals(repeat, this.repeat);
+            assertEquals(pause, this.pause);
+            assertEquals(resume, this.resume);
+        }
+
+        @Override
+        public void onAnimationStart(Animator animation, boolean isReverse) {
+            if (isReverse) {
+                startReverse++;
+            } else {
+                startForward++;
+            }
+        }
+
+        @Override
+        public void onAnimationEnd(Animator animation, boolean isReverse) {
+            if (isReverse) {
+                endReverse++;
+            } else {
+                endForward++;
+            }
+        }
+
+        @Override
+        public void onAnimationStart(Animator animation) {
+            startNoParam++;
+        }
+
+        @Override
+        public void onAnimationEnd(Animator animation) {
+            endNoParam++;
+        }
+
+        @Override
+        public void onAnimationCancel(Animator animation) {
+            cancel++;
+        }
+
+        @Override
+        public void onAnimationRepeat(Animator animation) {
+            repeat++;
+        }
+
+        @Override
+        public void onAnimationPause(Animator animation) {
+            pause++;
+        }
+
+        @Override
+        public void onAnimationResume(Animator animation) {
+            resume++;
+        }
+    }
+}
diff --git a/core/tests/coretests/src/android/animation/ViewPropertyAnimatorTest.java b/core/tests/coretests/src/android/animation/ViewPropertyAnimatorTest.java
index 81cd4da..8cc88ea 100644
--- a/core/tests/coretests/src/android/animation/ViewPropertyAnimatorTest.java
+++ b/core/tests/coretests/src/android/animation/ViewPropertyAnimatorTest.java
@@ -135,11 +135,15 @@
      * @throws Exception
      */
     @Before
-    public void setUp() throws Exception {
+    public void setUp() throws Throwable {
         final BasicAnimatorActivity activity = mActivityRule.getActivity();
         Button button = activity.findViewById(R.id.animatingButton);
 
         mAnimator = button.animate().x(100).y(100);
+        mActivityRule.runOnUiThread(() -> {
+            mAnimator.start();
+            mAnimator.cancel();
+        });
 
         // mListener is the main testing mechanism of this file. The asserts of each test
         // are embedded in the listener callbacks that it implements.
diff --git a/core/tests/coretests/src/com/android/internal/app/procstats/ProcessStatsTest.java b/core/tests/coretests/src/com/android/internal/app/procstats/ProcessStatsTest.java
index 9b9a84b..35b3267 100644
--- a/core/tests/coretests/src/com/android/internal/app/procstats/ProcessStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/procstats/ProcessStatsTest.java
@@ -156,4 +156,19 @@
                         eq(0),
                         eq(APP_1_PROCESS_NAME));
     }
+
+    @SmallTest
+    public void testSafelyResetClearsProcessInUidState() throws Exception {
+        ProcessStats processStats = new ProcessStats();
+        ProcessState processState =
+                processStats.getProcessStateLocked(
+                        APP_1_PACKAGE_NAME, APP_1_UID, APP_1_VERSION, APP_1_PROCESS_NAME);
+        processState.makeActive();
+        UidState uidState = processStats.mUidStates.get(APP_1_UID);
+        assertTrue(uidState.isInUse());
+        processState.makeInactive();
+        uidState.resetSafely(NOW_MS);
+        processState.makeActive();
+        assertFalse(uidState.isInUse());
+    }
 }
diff --git a/core/tests/mockingcoretests/Android.bp b/core/tests/mockingcoretests/Android.bp
index 96811be..29d7902 100644
--- a/core/tests/mockingcoretests/Android.bp
+++ b/core/tests/mockingcoretests/Android.bp
@@ -40,7 +40,6 @@
         "platform-test-annotations",
         "truth-prebuilt",
         "testables",
-        "ub-uiautomator",
     ],
 
     libs: [
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java
index fee9140..e6f47d4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java
@@ -32,6 +32,7 @@
 import android.hardware.input.InputManager;
 import android.os.Looper;
 import android.provider.DeviceConfig;
+import android.util.Log;
 import android.view.BatchedInputEventReceiver;
 import android.view.Choreographer;
 import android.view.InputChannel;
@@ -243,6 +244,7 @@
 
     @VisibleForTesting
     void onInputEvent(InputEvent ev) {
+        Log.d(TAG, "onInputEvent: " + ev);
         if (!mEnableDragCornerResize && !mEnablePinchResize) {
             // No need to handle anything if neither form of resizing is enabled.
             return;
@@ -256,6 +258,17 @@
         if (ev instanceof MotionEvent) {
             MotionEvent mv = (MotionEvent) ev;
             int action = mv.getActionMasked();
+
+            // TODO: remove logging once b/269505548 is resolved
+            if (action == MotionEvent.ACTION_MOVE && mFirstIndex != -1 && mSecondIndex != -1) {
+                float x0 = mv.getRawX(mFirstIndex);
+                float y0 = mv.getRawY(mFirstIndex);
+                float x1 = mv.getRawX(mSecondIndex);
+                float y1 = mv.getRawY(mSecondIndex);
+                Log.d(TAG, "at onInputEvent (" + x0 + ", " + y0 + ")");
+                Log.d(TAG, "at onInputEvent (" + x1 + ", " + y1 + ")");
+            }
+
             final Rect pipBounds = mPipBoundsState.getBounds();
             if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
                 if (!pipBounds.contains((int) mv.getRawX(), (int) mv.getRawY())
@@ -393,6 +406,7 @@
 
     @VisibleForTesting
     void onPinchResize(MotionEvent ev) {
+        Log.d(TAG, "onPinchResize: " + ev);
         int action = ev.getActionMasked();
 
         if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
@@ -436,6 +450,10 @@
             mLastPoint.set(x0, y0);
             mLastSecondPoint.set(x1, y1);
 
+            // TODO: remove logging once b/269505548 is resolved
+            Log.d(TAG, "at onPinchResize (" + x0 + ", " + y0 + ")");
+            Log.d(TAG, "at onPinchResize (" + x1 + ", " + y1 + ")");
+
             // Capture inputs
             if (!mThresholdCrossed
                     && (distanceBetween(mDownSecondPoint, mLastSecondPoint) > mTouchSlop
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/BaseAppCompat.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/BaseAppCompat.kt
new file mode 100644
index 0000000..d01a0ee
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/BaseAppCompat.kt
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.appcompat
+
+import android.content.Context
+import android.system.helpers.CommandsHelper
+import android.tools.device.flicker.legacy.FlickerBuilder
+import android.tools.device.flicker.legacy.FlickerTest
+import com.android.wm.shell.flicker.BaseTest
+import com.android.server.wm.flicker.helpers.setRotation
+import com.android.server.wm.flicker.helpers.LetterboxAppHelper
+import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.IFlickerTestData
+import com.android.wm.shell.flicker.appWindowIsVisibleAtEnd
+import com.android.wm.shell.flicker.appWindowIsVisibleAtStart
+import org.junit.Assume
+import org.junit.Before
+import org.junit.runners.Parameterized
+
+abstract class BaseAppCompat(flicker: FlickerTest) : BaseTest(flicker) {
+    protected val context: Context = instrumentation.context
+    protected val letterboxApp = LetterboxAppHelper(instrumentation)
+    lateinit var cmdHelper: CommandsHelper
+    lateinit var letterboxStyle: HashMap<String, String>
+
+    /** {@inheritDoc} */
+    override val transition: FlickerBuilder.() -> Unit
+        get() = {
+            setup {
+                setStartRotation()
+                letterboxApp.launchViaIntent(wmHelper)
+                setEndRotation()
+            }
+        }
+
+    @Before
+    fun before() {
+        cmdHelper = CommandsHelper.getInstance(instrumentation)
+        Assume.assumeTrue(tapl.isTablet && isIgnoreOrientationRequest())
+    }
+
+    private fun mapLetterboxStyle(): HashMap<String, String> {
+        val res = cmdHelper.executeShellCommand("wm get-letterbox-style")
+        val lines = res.lines()
+        val map = HashMap<String, String>()
+        for (line in lines) {
+            val keyValuePair = line.split(":")
+            if (keyValuePair.size == 2) {
+                val key = keyValuePair[0].trim()
+                map[key] = keyValuePair[1].trim()
+            }
+        }
+        return map
+    }
+
+    private fun isIgnoreOrientationRequest(): Boolean {
+        val res = cmdHelper.executeShellCommand("wm get-ignore-orientation-request")
+        return res != null && res.contains("true")
+    }
+
+    fun IFlickerTestData.setStartRotation() = setRotation(flicker.scenario.startRotation)
+
+    fun IFlickerTestData.setEndRotation() = setRotation(flicker.scenario.endRotation)
+
+    /** Checks that app entering letterboxed state have rounded corners */
+    fun assertLetterboxAppAtStartHasRoundedCorners() {
+        assumeLetterboxRoundedCornersEnabled()
+        flicker.assertLayersStart { this.hasRoundedCorners(letterboxApp) }
+    }
+
+    fun assertLetterboxAppAtEndHasRoundedCorners() {
+        assumeLetterboxRoundedCornersEnabled()
+        flicker.assertLayersEnd { this.hasRoundedCorners(letterboxApp) }
+    }
+
+    /** Only run on tests with config_letterboxActivityCornersRadius != 0 in devices */
+    private fun assumeLetterboxRoundedCornersEnabled() {
+        if (!::letterboxStyle.isInitialized) {
+            letterboxStyle = mapLetterboxStyle()
+        }
+        Assume.assumeTrue(letterboxStyle.getValue("Corner radius") != "0")
+    }
+
+    fun assertLetterboxAppVisibleAtStartAndEnd() {
+        flicker.appWindowIsVisibleAtStart(letterboxApp)
+        flicker.appWindowIsVisibleAtEnd(letterboxApp)
+    }
+
+    companion object {
+        /**
+         * Creates the test configurations.
+         *
+         * See [FlickerTestFactory.rotationTests] for configuring screen orientation and
+         * navigation modes.
+         */
+        @Parameterized.Parameters(name = "{0}")
+        @JvmStatic
+        fun getParams(): Collection<FlickerTest> {
+            return FlickerTestFactory.rotationTests()
+        }
+    }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/OpenAppInSizeCompatModeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/OpenAppInSizeCompatModeTest.kt
new file mode 100644
index 0000000..c57100e
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/OpenAppInSizeCompatModeTest.kt
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.appcompat
+
+import android.platform.test.annotations.Postsubmit
+import androidx.test.filters.RequiresDevice
+import android.tools.device.flicker.legacy.FlickerBuilder
+import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.common.datatypes.component.ComponentNameMatcher
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+
+/**
+ * Test launching app in size compat mode.
+ *
+ * To run this test: `atest WMShellFlickerTests:OpenAppInSizeCompatModeTest`
+ *
+ * Actions:
+ * ```
+ *     Rotate non resizable portrait only app to opposite orientation to trigger size compat mode
+ * ```
+ * Notes:
+ * ```
+ *     Some default assertions (e.g., nav bar, status bar and screen covered)
+ *     are inherited [BaseTest]
+ * ```
+ */
+
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+class OpenAppInSizeCompatModeTest(flicker: FlickerTest) : BaseAppCompat(flicker) {
+
+    /** {@inheritDoc} */
+    override val transition: FlickerBuilder.() -> Unit
+        get() = {
+            setup {
+                setStartRotation()
+                letterboxApp.launchViaIntent(wmHelper)
+            }
+            transitions { setEndRotation() }
+            teardown { letterboxApp.exit(wmHelper) }
+        }
+
+    /**
+     * Windows maybe recreated when rotated. Checks that the focus does not change or if it does,
+     * focus returns to [letterboxApp]
+     */
+    @Postsubmit
+    @Test
+    fun letterboxAppFocusedAtEnd() = flicker.assertEventLog { focusChanges(letterboxApp.`package`) }
+
+    @Postsubmit
+    @Test
+    fun letterboxedAppHasRoundedCorners() = assertLetterboxAppAtEndHasRoundedCorners()
+
+    /**
+     * Checks that the [ComponentNameMatcher.ROTATION] layer appears during the transition, doesn't
+     * flicker, and disappears before the transition is complete
+     */
+    @Postsubmit
+    @Test
+    fun rotationLayerAppearsAndVanishes() {
+        flicker.assertLayers {
+            this.isVisible(letterboxApp)
+                .then()
+                .isVisible(ComponentNameMatcher.ROTATION)
+                .then()
+                .isVisible(letterboxApp)
+                .isInvisible(ComponentNameMatcher.ROTATION)
+        }
+    }
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/RestartAppInSizeCompatModeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/RestartAppInSizeCompatModeTest.kt
new file mode 100644
index 0000000..f111a8d
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/RestartAppInSizeCompatModeTest.kt
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.appcompat
+
+import android.platform.test.annotations.Postsubmit
+import androidx.test.filters.RequiresDevice
+import android.tools.device.flicker.legacy.FlickerBuilder
+import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.device.helpers.WindowUtils
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+
+/**
+ * Test restarting app in size compat mode.
+ *
+ * To run this test: `atest WMShellFlickerTests:RestartAppInSizeCompatModeTest`
+ *
+ * Actions:
+ * ```
+ *     Rotate app to opposite orientation to trigger size compat mode
+ *     Press restart button and wait for letterboxed app to resize
+ * ```
+ * Notes:
+ * ```
+ *     Some default assertions (e.g., nav bar, status bar and screen covered)
+ *     are inherited [BaseTest]
+ * ```
+ */
+
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+class RestartAppInSizeCompatModeTest(flicker: FlickerTest) : BaseAppCompat(flicker) {
+
+    /** {@inheritDoc} */
+    override val transition: FlickerBuilder.() -> Unit
+        get() = {
+            super.transition(this)
+            transitions { letterboxApp.clickRestart(wmHelper) }
+            teardown { letterboxApp.exit(wmHelper) }
+        }
+
+    @Postsubmit
+    @Test
+    fun appVisibleAtStartAndEnd() = assertLetterboxAppVisibleAtStartAndEnd()
+
+    @Postsubmit
+    @Test
+    fun appLayerVisibilityChanges() {
+        flicker.assertLayers {
+            this.isVisible(letterboxApp)
+                .then()
+                .isInvisible(letterboxApp)
+                .then()
+                .isVisible(letterboxApp)
+        }
+    }
+
+    @Postsubmit
+    @Test
+    fun letterboxedAppHasRoundedCorners() = assertLetterboxAppAtStartHasRoundedCorners()
+
+    /** Checks that the visible region of [letterboxApp] is still within display bounds */
+    @Postsubmit
+    @Test
+    fun appWindowRemainInsideVisibleBounds() {
+        val displayBounds = WindowUtils.getDisplayBounds(flicker.scenario.endRotation)
+        flicker.assertLayersEnd { visibleRegion(letterboxApp).coversAtMost(displayBounds) }
+    }
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipPinchInTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipPinchInTest.kt
index 85b2fbc..8eb41b4 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipPinchInTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipPinchInTest.kt
@@ -16,6 +16,7 @@
 
 package com.android.wm.shell.flicker.pip
 
+import android.platform.test.annotations.FlakyTest
 import android.platform.test.annotations.Postsubmit
 import android.tools.common.Rotation
 import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
@@ -34,6 +35,7 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@FlakyTest(bugId = 270677470)
 class PipPinchInTest(flicker: FlickerTest) : PipTransition(flicker) {
     override val transition: FlickerBuilder.() -> Unit
         get() = buildTransition { transitions { pipApp.pinchInPipWindow(wmHelper, 0.4f, 30) } }
diff --git a/libs/androidfw/ApkParsing.cpp b/libs/androidfw/ApkParsing.cpp
index 32d2c5b..7eedfdb 100644
--- a/libs/androidfw/ApkParsing.cpp
+++ b/libs/androidfw/ApkParsing.cpp
@@ -56,6 +56,11 @@
         return nullptr;
     }
 
+    // Make sure file starts with 'lib/' prefix.
+    if (strncmp(fileName, APK_LIB.data(), APK_LIB_LEN) != 0) {
+        return nullptr;
+    }
+
     // Make sure there aren't subdirectories by checking if the next / after lib/ is the last slash
     if (memchr(fileName + APK_LIB_LEN, '/', fileNameLen - APK_LIB_LEN) != lastSlash) {
         return nullptr;
diff --git a/libs/androidfw/tests/ApkParsing_test.cpp b/libs/androidfw/tests/ApkParsing_test.cpp
index 62e88c6..ac1dc9b 100644
--- a/libs/androidfw/tests/ApkParsing_test.cpp
+++ b/libs/androidfw/tests/ApkParsing_test.cpp
@@ -74,4 +74,10 @@
   auto lastSlash = util::ValidLibraryPathLastSlash(path, false, false);
   ASSERT_THAT(lastSlash, IsNull());
 }
+
+TEST(ApkParsingTest, InvalidPrefix) {
+  const char* path = "assets/libhello.so";
+  auto lastSlash = util::ValidLibraryPathLastSlash(path, false, false);
+  ASSERT_THAT(lastSlash, IsNull());
+}
 }
\ No newline at end of file
diff --git a/libs/hwui/Properties.cpp b/libs/hwui/Properties.cpp
index b0896da..33c9eac 100644
--- a/libs/hwui/Properties.cpp
+++ b/libs/hwui/Properties.cpp
@@ -21,7 +21,7 @@
 #ifdef __ANDROID__
 #include "HWUIProperties.sysprop.h"
 #endif
-#include "SkTraceEventCommon.h"
+#include "src/core/SkTraceEventCommon.h"
 
 #include <algorithm>
 #include <cstdlib>
diff --git a/libs/hwui/SkiaInterpolator.cpp b/libs/hwui/SkiaInterpolator.cpp
index b58f517..c67b135 100644
--- a/libs/hwui/SkiaInterpolator.cpp
+++ b/libs/hwui/SkiaInterpolator.cpp
@@ -18,9 +18,8 @@
 
 #include "include/core/SkScalar.h"
 #include "include/core/SkTypes.h"
-#include "include/private/SkFixed.h"
-#include "src/core/SkTSearch.h"
 
+#include <cstdlib>
 #include <log/log.h>
 
 typedef int Dot14;
@@ -41,18 +40,18 @@
     if (x <= 0) {
         return 0;
     }
-    if (x >= SK_Scalar1) {
+    if (x >= 1.0f) {
         return Dot14_ONE;
     }
-    return SkScalarToFixed(x) >> 2;
+    return static_cast<Dot14>(x * Dot14_ONE);
 }
 
 static float SkUnitCubicInterp(float value, float bx, float by, float cx, float cy) {
     // pin to the unit-square, and convert to 2.14
     Dot14 x = pin_and_convert(value);
 
-    if (x == 0) return 0;
-    if (x == Dot14_ONE) return SK_Scalar1;
+    if (x == 0) return 0.0f;
+    if (x == Dot14_ONE) return 1.0f;
 
     Dot14 b = pin_and_convert(bx);
     Dot14 c = pin_and_convert(cx);
@@ -84,7 +83,7 @@
     A = 3 * b;
     B = 3 * (c - 2 * b);
     C = 3 * (b - c) + Dot14_ONE;
-    return SkFixedToScalar(eval_cubic(t, A, B, C) << 2);
+    return Dot14ToFloat(eval_cubic(t, A, B, C));
 }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -104,7 +103,7 @@
     fFlags = 0;
     fElemCount = static_cast<uint8_t>(elemCount);
     fFrameCount = static_cast<int16_t>(frameCount);
-    fRepeat = SK_Scalar1;
+    fRepeat = 1.0f;
     if (fStorage) {
         free(fStorage);
         fStorage = nullptr;
@@ -136,17 +135,46 @@
 
 float SkiaInterpolatorBase::ComputeRelativeT(SkMSec time, SkMSec prevTime, SkMSec nextTime,
                                              const float blend[4]) {
-    SkASSERT(time > prevTime && time < nextTime);
+    LOG_FATAL_IF(time < prevTime || time > nextTime);
 
     float t = (float)(time - prevTime) / (float)(nextTime - prevTime);
     return blend ? SkUnitCubicInterp(t, blend[0], blend[1], blend[2], blend[3]) : t;
 }
 
+// Returns the index of where the item is or the bit not of the index
+// where the item should go in order to keep arr sorted in ascending order.
+int SkiaInterpolatorBase::binarySearch(const SkTimeCode* arr, int count, SkMSec target) {
+    if (count <= 0) {
+        return ~0;
+    }
+
+    int lo = 0;
+    int hi = count - 1;
+
+    while (lo < hi) {
+        int mid = (hi + lo) / 2;
+        SkMSec elem = arr[mid].fTime;
+        if (elem == target) {
+            return mid;
+        } else if (elem < target) {
+            lo = mid + 1;
+        } else {
+            hi = mid;
+        }
+    }
+    // Check to see if target is greater or less than where we stopped
+    if (target < arr[lo].fTime) {
+        return ~lo;
+    }
+    // e.g. it should go at the end.
+    return ~(lo + 1);
+}
+
 SkiaInterpolatorBase::Result SkiaInterpolatorBase::timeToT(SkMSec time, float* T, int* indexPtr,
                                                            bool* exactPtr) const {
-    SkASSERT(fFrameCount > 0);
+    LOG_FATAL_IF(fFrameCount <= 0);
     Result result = kNormal_Result;
-    if (fRepeat != SK_Scalar1) {
+    if (fRepeat != 1.0f) {
         SkMSec startTime = 0, endTime = 0;  // initialize to avoid warning
         this->getDuration(&startTime, &endTime);
         SkMSec totalTime = endTime - startTime;
@@ -168,10 +196,8 @@
         time = offsetTime + startTime;
     }
 
-    int index = SkTSearch<SkMSec>(&fTimes[0].fTime, fFrameCount, time, sizeof(SkTimeCode));
-
+    int index = SkiaInterpolatorBase::binarySearch(fTimes, fFrameCount, time);
     bool exact = true;
-
     if (index < 0) {
         index = ~index;
         if (index == 0) {
@@ -184,10 +210,11 @@
             }
             result = kFreezeEnd_Result;
         } else {
+            // Need to interpolate between two frames.
             exact = false;
         }
     }
-    SkASSERT(index < fFrameCount);
+    LOG_FATAL_IF(index >= fFrameCount);
     const SkTimeCode* nextTime = &fTimes[index];
     SkMSec nextT = nextTime[0].fTime;
     if (exact) {
@@ -207,7 +234,7 @@
 }
 
 SkiaInterpolator::SkiaInterpolator(int elemCount, int frameCount) {
-    SkASSERT(elemCount > 0);
+    LOG_FATAL_IF(elemCount <= 0);
     this->reset(elemCount, frameCount);
 }
 
@@ -221,21 +248,19 @@
     fValues = (float*)((char*)fStorage + sizeof(SkTimeCode) * frameCount);
 }
 
-#define SK_Fixed1Third (SK_Fixed1 / 3)
-#define SK_Fixed2Third (SK_Fixed1 * 2 / 3)
-
 static const float gIdentityBlend[4] = {0.33333333f, 0.33333333f, 0.66666667f, 0.66666667f};
 
 bool SkiaInterpolator::setKeyFrame(int index, SkMSec time, const float values[],
                                    const float blend[4]) {
-    SkASSERT(values != nullptr);
+    LOG_FATAL_IF(values == nullptr);
 
     if (blend == nullptr) {
         blend = gIdentityBlend;
     }
 
-    bool success = ~index == SkTSearch<SkMSec>(&fTimes->fTime, index, time, sizeof(SkTimeCode));
-    SkASSERT(success);
+    // Verify the time should go after all the frames before index
+    bool success = ~index == SkiaInterpolatorBase::binarySearch(fTimes, index, time);
+    LOG_FATAL_IF(!success);
     if (success) {
         SkTimeCode* timeCode = &fTimes[index];
         timeCode->fTime = time;
@@ -257,7 +282,7 @@
         if (exact) {
             memcpy(values, nextSrc, fElemCount * sizeof(float));
         } else {
-            SkASSERT(index > 0);
+            LOG_FATAL_IF(index <= 0);
 
             const float* prevSrc = nextSrc - fElemCount;
 
diff --git a/libs/hwui/SkiaInterpolator.h b/libs/hwui/SkiaInterpolator.h
index 9422cb5..62e6c1e 100644
--- a/libs/hwui/SkiaInterpolator.h
+++ b/libs/hwui/SkiaInterpolator.h
@@ -68,14 +68,16 @@
     enum Flags { kMirror = 1, kReset = 2, kHasBlend = 4 };
     static float ComputeRelativeT(uint32_t time, uint32_t prevTime, uint32_t nextTime,
                                   const float blend[4] = nullptr);
-    int16_t fFrameCount;
-    uint8_t fElemCount;
-    uint8_t fFlags;
-    float fRepeat;
     struct SkTimeCode {
         uint32_t fTime;
         float fBlend[4];
     };
+    static int binarySearch(const SkTimeCode* arr, int count, uint32_t target);
+
+    int16_t fFrameCount;
+    uint8_t fElemCount;
+    uint8_t fFlags;
+    float fRepeat;
     SkTimeCode* fTimes;  // pointer into fStorage
     void* fStorage;
 };
diff --git a/libs/hwui/jni/CreateJavaOutputStreamAdaptor.cpp b/libs/hwui/jni/CreateJavaOutputStreamAdaptor.cpp
index 15e529e..a66d3b8 100644
--- a/libs/hwui/jni/CreateJavaOutputStreamAdaptor.cpp
+++ b/libs/hwui/jni/CreateJavaOutputStreamAdaptor.cpp
@@ -1,11 +1,11 @@
 #include "CreateJavaOutputStreamAdaptor.h"
 #include "SkData.h"
-#include "SkMalloc.h"
 #include "SkRefCnt.h"
 #include "SkStream.h"
 #include "SkTypes.h"
 #include "Utils.h"
 
+#include <cstdlib>
 #include <nativehelper/JNIHelp.h>
 #include <log/log.h>
 #include <memory>
@@ -177,6 +177,10 @@
     return JavaInputStreamAdaptor::Create(env, stream, storage, swallowExceptions);
 }
 
+static void free_pointer_skproc(const void* ptr, void*) {
+    free((void*)ptr);
+}
+
 sk_sp<SkData> CopyJavaInputStream(JNIEnv* env, jobject inputStream, jbyteArray storage) {
     std::unique_ptr<SkStream> stream(CreateJavaInputStreamAdaptor(env, inputStream, storage));
     if (!stream) {
@@ -186,19 +190,31 @@
     size_t bufferSize = 4096;
     size_t streamLen = 0;
     size_t len;
-    char* data = (char*)sk_malloc_throw(bufferSize);
+    char* data = (char*)malloc(bufferSize);
+    LOG_ALWAYS_FATAL_IF(!data);
 
     while ((len = stream->read(data + streamLen,
                                bufferSize - streamLen)) != 0) {
         streamLen += len;
         if (streamLen == bufferSize) {
             bufferSize *= 2;
-            data = (char*)sk_realloc_throw(data, bufferSize);
+            data = (char*)realloc(data, bufferSize);
+            LOG_ALWAYS_FATAL_IF(!data);
         }
     }
-    data = (char*)sk_realloc_throw(data, streamLen);
-
-    return SkData::MakeFromMalloc(data, streamLen);
+    if (streamLen == 0) {
+        // realloc with size 0 is unspecified behavior in C++11
+        free(data);
+        data = nullptr;
+    } else {
+        // Trim down the buffer to the actual size of the data.
+        LOG_FATAL_IF(streamLen > bufferSize);
+        data = (char*)realloc(data, streamLen);
+        LOG_ALWAYS_FATAL_IF(!data);
+    }
+    // Just in case sk_free differs from free, we ask Skia to use
+    // free to cleanup the buffer that SkData wraps.
+    return SkData::MakeWithProc(data, streamLen, free_pointer_skproc, nullptr);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/jni/MaskFilter.cpp b/libs/hwui/jni/MaskFilter.cpp
index 048ce02..cbd4520 100644
--- a/libs/hwui/jni/MaskFilter.cpp
+++ b/libs/hwui/jni/MaskFilter.cpp
@@ -1,6 +1,5 @@
 #include "GraphicsJNI.h"
 #include "SkMaskFilter.h"
-#include "SkBlurMask.h"
 #include "SkBlurMaskFilter.h"
 #include "SkBlurTypes.h"
 #include "SkTableMaskFilter.h"
@@ -11,6 +10,13 @@
     }
 }
 
+// From https://skia.googlesource.com/skia/+/d74c99a3cd5eef5f16b2eb226e6b45fe523c8552/src/core/SkBlurMask.cpp#28
+static constexpr float kBLUR_SIGMA_SCALE = 0.57735f;
+
+static float convertRadiusToSigma(float radius) {
+    return radius > 0 ? kBLUR_SIGMA_SCALE * radius + 0.5f : 0.0f;
+}
+
 class SkMaskFilterGlue {
 public:
     static void destructor(JNIEnv* env, jobject, jlong filterHandle) {
@@ -19,7 +25,7 @@
     }
 
     static jlong createBlur(JNIEnv* env, jobject, jfloat radius, jint blurStyle) {
-        SkScalar sigma = SkBlurMask::ConvertRadiusToSigma(radius);
+        SkScalar sigma = convertRadiusToSigma(radius);
         SkMaskFilter* filter = SkMaskFilter::MakeBlur((SkBlurStyle)blurStyle, sigma).release();
         ThrowIAE_IfNull(env, filter);
         return reinterpret_cast<jlong>(filter);
@@ -34,7 +40,7 @@
             direction[i] = values[i];
         }
 
-        SkScalar sigma = SkBlurMask::ConvertRadiusToSigma(radius);
+        SkScalar sigma = convertRadiusToSigma(radius);
         SkMaskFilter* filter =  SkBlurMaskFilter::MakeEmboss(sigma,
                 direction, ambient, specular).release();
         ThrowIAE_IfNull(env, filter);
diff --git a/location/java/android/location/GnssCapabilities.java b/location/java/android/location/GnssCapabilities.java
index c6f32c2..88f00dc 100644
--- a/location/java/android/location/GnssCapabilities.java
+++ b/location/java/android/location/GnssCapabilities.java
@@ -123,6 +123,21 @@
     @Retention(RetentionPolicy.SOURCE)
     public @interface SubHalPowerCapabilityFlags {}
 
+    /** The capability is unknown to be supported or not. */
+    public static final int CAPABILITY_UNKNOWN = 0;
+    /** The capability is supported. */
+    public static final int CAPABILITY_SUPPORTED = 1;
+    /** The capability is not supported. */
+    public static final int CAPABILITY_UNSUPPORTED = 2;
+
+    /** @hide */
+    @IntDef(flag = true, prefix = {"CAPABILITY_"}, value = {CAPABILITY_UNKNOWN,
+            CAPABILITY_SUPPORTED,
+            CAPABILITY_UNSUPPORTED})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface CapabilitySupportType {}
+
+
     /**
      * Returns an empty GnssCapabilities object.
      *
@@ -375,30 +390,25 @@
     }
 
     /**
-     * Returns {@code true} if GNSS chipset supports accumulated delta range, {@code false}
-     * otherwise.
-     *
-     * <p>The value is only known if {@link #isAccumulatedDeltaRangeCapabilityKnown()} is
-     * true.
+     * Returns {@link #CAPABILITY_SUPPORTED} if GNSS chipset supports accumulated delta
+     * range, {@link #CAPABILITY_UNSUPPORTED} if GNSS chipset does not support accumulated
+     * delta range, and {@link #CAPABILITY_UNKNOWN} if it is unknown, which means GNSS
+     * chipset may or may not support accumulated delta range.
      *
      * <p>The accumulated delta range information can be queried in
      * {@link android.location.GnssMeasurement#getAccumulatedDeltaRangeState()},
      * {@link android.location.GnssMeasurement#getAccumulatedDeltaRangeMeters()}, and
      * {@link android.location.GnssMeasurement#getAccumulatedDeltaRangeUncertaintyMeters()}.
      */
-    public boolean hasAccumulatedDeltaRange() {
+    public @CapabilitySupportType int hasAccumulatedDeltaRange() {
         if (!mIsAdrCapabilityKnown) {
-            throw new IllegalStateException("Accumulated delta range capability is unknown.");
+            return CAPABILITY_UNKNOWN;
         }
-        return (mTopFlags & TOP_HAL_CAPABILITY_ACCUMULATED_DELTA_RANGE) != 0;
-    }
-
-    /**
-     * Returns {@code true} if {@link #hasAccumulatedDeltaRange()} is known, {@code false}
-     * otherwise.
-     */
-    public boolean isAccumulatedDeltaRangeCapabilityKnown() {
-        return mIsAdrCapabilityKnown;
+        if ((mTopFlags & TOP_HAL_CAPABILITY_ACCUMULATED_DELTA_RANGE) != 0) {
+            return CAPABILITY_SUPPORTED;
+        } else {
+            return CAPABILITY_UNSUPPORTED;
+        }
     }
 
     /**
@@ -597,9 +607,9 @@
         if (hasMeasurementCorrectionsForDriving()) {
             builder.append("MEASUREMENT_CORRECTIONS_FOR_DRIVING ");
         }
-        if (mIsAdrCapabilityKnown && hasAccumulatedDeltaRange()) {
+        if (hasAccumulatedDeltaRange() == CAPABILITY_SUPPORTED) {
             builder.append("ACCUMULATED_DELTA_RANGE ");
-        } else if (!mIsAdrCapabilityKnown) {
+        } else if (hasAccumulatedDeltaRange() == CAPABILITY_UNKNOWN) {
             builder.append("ACCUMULATED_DELTA_RANGE(unknown) ");
         }
         if (hasMeasurementCorrectionsLosSats()) {
@@ -795,19 +805,17 @@
         /**
          * Sets accumulated delta range capability.
          */
-        public @NonNull Builder setHasAccumulatedDeltaRange(boolean capable) {
-            mIsAdrCapabilityKnown = true;
-            mTopFlags = setFlag(mTopFlags, TOP_HAL_CAPABILITY_ACCUMULATED_DELTA_RANGE,
-                    capable);
-            return this;
-        }
-
-        /**
-         * Clears accumulated delta range capability and sets it as unknown.
-         */
-        public @NonNull Builder clearIsAccumulatedDeltaRangeCapabilityKnown() {
-            mIsAdrCapabilityKnown = false;
-            mTopFlags = setFlag(mTopFlags, TOP_HAL_CAPABILITY_ACCUMULATED_DELTA_RANGE, false);
+        public @NonNull Builder setHasAccumulatedDeltaRange(@CapabilitySupportType int capable) {
+            if (capable == CAPABILITY_UNKNOWN) {
+                mIsAdrCapabilityKnown = false;
+                mTopFlags = setFlag(mTopFlags, TOP_HAL_CAPABILITY_ACCUMULATED_DELTA_RANGE, false);
+            } else if (capable == CAPABILITY_SUPPORTED) {
+                mIsAdrCapabilityKnown = true;
+                mTopFlags = setFlag(mTopFlags, TOP_HAL_CAPABILITY_ACCUMULATED_DELTA_RANGE, true);
+            } else if (capable == CAPABILITY_UNSUPPORTED) {
+                mIsAdrCapabilityKnown = true;
+                mTopFlags = setFlag(mTopFlags, TOP_HAL_CAPABILITY_ACCUMULATED_DELTA_RANGE, false);
+            }
             return this;
         }
 
diff --git a/packages/CredentialManager/res/values-de/strings.xml b/packages/CredentialManager/res/values-de/strings.xml
index 61b4ffa..103a3d2 100644
--- a/packages/CredentialManager/res/values-de/strings.xml
+++ b/packages/CredentialManager/res/values-de/strings.xml
@@ -47,7 +47,8 @@
     <string name="other_password_manager" msgid="565790221427004141">"Andere Passwortmanager"</string>
     <string name="close_sheet" msgid="1393792015338908262">"Tabellenblatt schließen"</string>
     <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Zurück zur vorherigen Seite"</string>
-    <string name="accessibility_close_button" msgid="1163435587545377687">"Schließen"</string>
+    <!-- no translation found for accessibility_close_button (1163435587545377687) -->
+    <skip />
     <!-- no translation found for accessibility_snackbar_dismiss (3456598374801836120) -->
     <skip />
     <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Gespeicherten Passkey für <xliff:g id="APP_NAME">%1$s</xliff:g> verwenden?"</string>
@@ -61,7 +62,8 @@
     <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Gesperrte Passwortmanager"</string>
     <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Zum Entsperren tippen"</string>
     <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="8131725029983174901">"Keine Anmeldedaten"</string>
-    <string name="no_sign_in_info_in" msgid="2641118151920288356">"Keine Anmeldedaten in <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+    <!-- no translation found for no_sign_in_info_in (2641118151920288356) -->
+    <skip />
     <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Anmeldedaten verwalten"</string>
     <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Von einem anderen Gerät"</string>
     <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Anderes Gerät verwenden"</string>
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/UninstallUninstalling.java b/packages/PackageInstaller/src/com/android/packageinstaller/UninstallUninstalling.java
index b60aba8..e6710ff 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/UninstallUninstalling.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/UninstallUninstalling.java
@@ -83,7 +83,7 @@
                 }
 
                 UserManager customUserManager = UninstallUninstalling.this
-                        .createContextAsUser(UserHandle.of(user.getIdentifier()), 0)
+                        .createContextAsUser(user, 0)
                         .getSystemService(UserManager.class);
                 if (customUserManager.isUserOfType(UserManager.USER_TYPE_PROFILE_CLONE)) {
                     isCloneUser = true;
@@ -117,7 +117,7 @@
                 int flags = allUsers ? PackageManager.DELETE_ALL_USERS : 0;
                 flags |= keepData ? PackageManager.DELETE_KEEP_DATA : 0;
 
-                getPackageManager().getPackageInstaller().uninstall(
+                createContextAsUser(user, 0).getPackageManager().getPackageInstaller().uninstall(
                         new VersionedPackage(mAppInfo.packageName,
                                 PackageManager.VERSION_CODE_HIGHEST),
                         flags, pendingIntent.getIntentSender());
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/UninstallerActivity.java b/packages/PackageInstaller/src/com/android/packageinstaller/UninstallerActivity.java
old mode 100755
new mode 100644
index 7250bdd..9c67817
--- a/packages/PackageInstaller/src/com/android/packageinstaller/UninstallerActivity.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/UninstallerActivity.java
@@ -367,10 +367,10 @@
                 int flags = mDialogInfo.allUsers ? PackageManager.DELETE_ALL_USERS : 0;
                 flags |= keepData ? PackageManager.DELETE_KEEP_DATA : 0;
 
-                getPackageManager().getPackageInstaller().uninstall(
-                        new VersionedPackage(mDialogInfo.appInfo.packageName,
-                                PackageManager.VERSION_CODE_HIGHEST),
-                        flags, pendingIntent.getIntentSender());
+                createContextAsUser(mDialogInfo.user, 0).getPackageManager().getPackageInstaller()
+                        .uninstall(new VersionedPackage(mDialogInfo.appInfo.packageName,
+                                PackageManager.VERSION_CODE_HIGHEST), flags,
+                                pendingIntent.getIntentSender());
             } catch (Exception e) {
                 notificationManager.cancel(uninstallId);
 
diff --git a/packages/SettingsLib/Spa/OWNERS b/packages/SettingsLib/Spa/OWNERS
index 2887872..464328e 100644
--- a/packages/SettingsLib/Spa/OWNERS
+++ b/packages/SettingsLib/Spa/OWNERS
@@ -4,3 +4,6 @@
 hanxu@google.com
 kellyz@google.com
 pierreqian@google.com
+lijun@google.com
+songchenxi@google.com
+cyl@google.com
diff --git a/packages/SettingsLib/res/values-hi/arrays.xml b/packages/SettingsLib/res/values-hi/arrays.xml
index 24efe28..be88620 100644
--- a/packages/SettingsLib/res/values-hi/arrays.xml
+++ b/packages/SettingsLib/res/values-hi/arrays.xml
@@ -63,17 +63,13 @@
     <item msgid="6336372935919715515">"चालू और फ़िल्टर किया गया"</item>
     <item msgid="2779123106632690576">"चालू है"</item>
   </string-array>
-  <string-array name="bt_hci_snoop_log_filters_entries">
-    <item msgid="195768089203590086">"सिर्फ़ ACL हेडर छोड़ दें"</item>
-    <item msgid="2776218217644557831">"A2DP मीडिया पैकेट फ़िल्टर करें"</item>
-    <item msgid="8163235976612675092">"RFCOMM चैनल फ़िल्टर करें"</item>
-  </string-array>
-  <string-array name="bt_hci_snoop_log_profile_filter_entries">
-    <item msgid="3961868665260627524">"बंद करें"</item>
-    <item msgid="2505973306504851132">"कैरेक्टर स्ट्रिंग डालें"</item>
-    <item msgid="5883011000629613855">"सिर्फ़ हेडर छोड़ दें"</item>
-    <item msgid="1051534112762023603">"पूरी तरह से हटाएं"</item>
-  </string-array>
+    <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (195768089203590086) -->
+    <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (2776218217644557831) -->
+    <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8163235976612675092) -->
+    <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (3961868665260627524) -->
+    <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (2505973306504851132) -->
+    <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (5883011000629613855) -->
+    <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1051534112762023603) -->
   <string-array name="bluetooth_avrcp_versions">
     <item msgid="6603880723315236832">"AVRCP 1.5 (डिफ़ॉल्ट)"</item>
     <item msgid="1637054408779685086">"AVRCP 1.3"</item>
diff --git a/packages/SettingsLib/res/values-ms/arrays.xml b/packages/SettingsLib/res/values-ms/arrays.xml
index 3ee7131..efdd879 100644
--- a/packages/SettingsLib/res/values-ms/arrays.xml
+++ b/packages/SettingsLib/res/values-ms/arrays.xml
@@ -63,17 +63,13 @@
     <item msgid="6336372935919715515">"Didayakan Ditapis"</item>
     <item msgid="2779123106632690576">"Didayakan"</item>
   </string-array>
-  <string-array name="bt_hci_snoop_log_filters_entries">
-    <item msgid="195768089203590086">"Tinggalkan pengepala ACL sahaja"</item>
-    <item msgid="2776218217644557831">"Tapis paket media A2DP"</item>
-    <item msgid="8163235976612675092">"Tapis saluran RFCOMM"</item>
-  </string-array>
-  <string-array name="bt_hci_snoop_log_profile_filter_entries">
-    <item msgid="3961868665260627524">"Lumpuhkan"</item>
-    <item msgid="2505973306504851132">"Isi dengan rentetan aksara"</item>
-    <item msgid="5883011000629613855">"Tinggalkan pengepala sahaja"</item>
-    <item msgid="1051534112762023603">"Alih keluar sepenuhnya"</item>
-  </string-array>
+    <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (195768089203590086) -->
+    <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (2776218217644557831) -->
+    <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8163235976612675092) -->
+    <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (3961868665260627524) -->
+    <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (2505973306504851132) -->
+    <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (5883011000629613855) -->
+    <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1051534112762023603) -->
   <string-array name="bluetooth_avrcp_versions">
     <item msgid="6603880723315236832">"AVRCP 1.5 (Lalai)"</item>
     <item msgid="1637054408779685086">"AVRCP 1.3"</item>
diff --git a/packages/SettingsLib/res/values-pt-rPT/arrays.xml b/packages/SettingsLib/res/values-pt-rPT/arrays.xml
index 5d23239..0553aac 100644
--- a/packages/SettingsLib/res/values-pt-rPT/arrays.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/arrays.xml
@@ -63,17 +63,13 @@
     <item msgid="6336372935919715515">"Filtrado ativado"</item>
     <item msgid="2779123106632690576">"Ativado"</item>
   </string-array>
-  <string-array name="bt_hci_snoop_log_filters_entries">
-    <item msgid="195768089203590086">"Deixe apenas cabeçalhos de LCA (Lista de controlo de acesso)"</item>
-    <item msgid="2776218217644557831">"Filtre pacotes de multimédia A2DP"</item>
-    <item msgid="8163235976612675092">"Filtre o canal RFCOMM"</item>
-  </string-array>
-  <string-array name="bt_hci_snoop_log_profile_filter_entries">
-    <item msgid="3961868665260627524">"Desativar"</item>
-    <item msgid="2505973306504851132">"Preencha com uma string de carateres"</item>
-    <item msgid="5883011000629613855">"Deixe apenas o cabeçalho"</item>
-    <item msgid="1051534112762023603">"Remova totalmente"</item>
-  </string-array>
+    <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (195768089203590086) -->
+    <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (2776218217644557831) -->
+    <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8163235976612675092) -->
+    <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (3961868665260627524) -->
+    <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (2505973306504851132) -->
+    <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (5883011000629613855) -->
+    <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1051534112762023603) -->
   <string-array name="bluetooth_avrcp_versions">
     <item msgid="6603880723315236832">"AVRCP 1.5 (predefinição)"</item>
     <item msgid="1637054408779685086">"AVRCP 1.3"</item>
diff --git a/packages/SettingsLib/res/values-uz/arrays.xml b/packages/SettingsLib/res/values-uz/arrays.xml
index 4b08f47..3e53ae6 100644
--- a/packages/SettingsLib/res/values-uz/arrays.xml
+++ b/packages/SettingsLib/res/values-uz/arrays.xml
@@ -63,17 +63,13 @@
     <item msgid="6336372935919715515">"Filtrlar yoniq"</item>
     <item msgid="2779123106632690576">"Yoniq"</item>
   </string-array>
-  <string-array name="bt_hci_snoop_log_filters_entries">
-    <item msgid="195768089203590086">"Faqat ACL sarlavhalari qolsin"</item>
-    <item msgid="2776218217644557831">"A2DP media paketlarni filtrlash"</item>
-    <item msgid="8163235976612675092">"RFCOMM kanalini filtrlash"</item>
-  </string-array>
-  <string-array name="bt_hci_snoop_log_profile_filter_entries">
-    <item msgid="3961868665260627524">"Faolsizlantirish"</item>
-    <item msgid="2505973306504851132">"Qatorni harflar bilan toʻldiring"</item>
-    <item msgid="5883011000629613855">"Faqat sarlavha qolsin"</item>
-    <item msgid="1051534112762023603">"Butunlay olib tashlash"</item>
-  </string-array>
+    <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (195768089203590086) -->
+    <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (2776218217644557831) -->
+    <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8163235976612675092) -->
+    <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (3961868665260627524) -->
+    <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (2505973306504851132) -->
+    <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (5883011000629613855) -->
+    <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1051534112762023603) -->
   <string-array name="bluetooth_avrcp_versions">
     <item msgid="6603880723315236832">"AVRCP 1.5 (asosiy)"</item>
     <item msgid="1637054408779685086">"AVRCP 1.3"</item>
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
index 684a9aa..c9e8312 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
@@ -31,7 +31,6 @@
 import static android.media.MediaRoute2Info.TYPE_USB_HEADSET;
 import static android.media.MediaRoute2Info.TYPE_WIRED_HEADPHONES;
 import static android.media.MediaRoute2Info.TYPE_WIRED_HEADSET;
-import static android.media.MediaRoute2ProviderService.REASON_UNKNOWN_ERROR;
 
 import static com.android.settingslib.media.LocalMediaManager.MediaDeviceState.STATE_SELECTED;
 
@@ -621,9 +620,11 @@
             dispatchConnectedDeviceChanged(id);
         }
 
+        /**
+         * Ignore callback here since we'll also receive {@link onRequestFailed} with reason code.
+         */
         @Override
         public void onTransferFailed(RoutingSessionInfo session, MediaRoute2Info route) {
-            dispatchOnRequestFailed(REASON_UNKNOWN_ERROR);
         }
 
         @Override
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java
index 6b9866b..a9d15f3 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java
@@ -33,7 +33,6 @@
 import static android.media.RouteListingPreference.Item.FLAG_ONGOING_SESSION;
 import static android.media.RouteListingPreference.Item.FLAG_ONGOING_SESSION_MANAGED;
 import static android.media.RouteListingPreference.Item.FLAG_SUGGESTED;
-import static android.media.RouteListingPreference.Item.SELECTION_BEHAVIOR_TRANSFER;
 import static android.media.RouteListingPreference.Item.SUBTEXT_AD_ROUTING_DISALLOWED;
 import static android.media.RouteListingPreference.Item.SUBTEXT_CUSTOM;
 import static android.media.RouteListingPreference.Item.SUBTEXT_DEVICE_LOW_POWER;
@@ -45,6 +44,7 @@
 import static android.media.RouteListingPreference.Item.SUBTEXT_UNAUTHORIZED;
 
 import static com.android.settingslib.media.LocalMediaManager.MediaDeviceState.STATE_SELECTED;
+import static com.android.settingslib.media.MediaDevice.SelectionBehavior.SELECTION_BEHAVIOR_TRANSFER;
 
 import android.annotation.SuppressLint;
 import android.content.Context;
@@ -95,6 +95,17 @@
         int TYPE_CAST_GROUP_DEVICE = 7;
     }
 
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({SelectionBehavior.SELECTION_BEHAVIOR_NONE,
+            SelectionBehavior.SELECTION_BEHAVIOR_TRANSFER,
+            SelectionBehavior.SELECTION_BEHAVIOR_GO_TO_APP
+    })
+    public @interface SelectionBehavior {
+        int SELECTION_BEHAVIOR_NONE = 0;
+        int SELECTION_BEHAVIOR_TRANSFER = 1;
+        int SELECTION_BEHAVIOR_GO_TO_APP = 2;
+    }
+
     @VisibleForTesting
     int mType;
 
@@ -213,7 +224,7 @@
      *
      * @return selection behavior of device
      */
-    @RouteListingPreference.Item.SubText
+    @SelectionBehavior
     public int getSelectionBehavior() {
         return Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE && mItem != null
                 ? mItem.getSelectionBehavior() : SELECTION_BEHAVIOR_TRANSFER;
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java
index f63c06a..270fda8 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java
@@ -30,6 +30,7 @@
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -799,12 +800,12 @@
     }
 
     @Test
-    public void onTransferFailed_shouldDispatchOnRequestFailed() {
+    public void onTransferFailed_notDispatchOnRequestFailed() {
         mInfoMediaManager.registerCallback(mCallback);
 
         mInfoMediaManager.mMediaRouterCallback.onTransferFailed(null, null);
 
-        verify(mCallback).onRequestFailed(REASON_UNKNOWN_ERROR);
+        verify(mCallback, never()).onRequestFailed(REASON_UNKNOWN_ERROR);
     }
 
     @Test
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
index c2a3ada..a631c81 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
@@ -211,6 +211,7 @@
         VALIDATORS.put(System.SHOW_BATTERY_PERCENT, BOOLEAN_VALIDATOR);
         VALIDATORS.put(System.NOTIFICATION_LIGHT_PULSE, BOOLEAN_VALIDATOR);
         VALIDATORS.put(System.WEAR_ACCESSIBILITY_GESTURE_ENABLED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(System.WEAR_ACCESSIBILITY_GESTURE_ENABLED_DURING_OOBE, BOOLEAN_VALIDATOR);
         VALIDATORS.put(System.CLOCKWORK_BLUETOOTH_SETTINGS_PREF, BOOLEAN_VALIDATOR);
         VALIDATORS.put(System.UNREAD_NOTIFICATION_DOT_INDICATOR, BOOLEAN_VALIDATOR);
         VALIDATORS.put(System.AUTO_LAUNCH_MEDIA_CONTROLS, BOOLEAN_VALIDATOR);
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 278ceb9..ec611cf 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -100,6 +100,7 @@
                     Settings.System.MIN_REFRESH_RATE, // depends on hardware capabilities
                     Settings.System.PEAK_REFRESH_RATE, // depends on hardware capabilities
                     Settings.System.SCREEN_BRIGHTNESS_FLOAT,
+                    Settings.System.WEAR_ACCESSIBILITY_GESTURE_ENABLED_DURING_OOBE,
                     Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ,
                     Settings.System.MULTI_AUDIO_FOCUS_ENABLED // form-factor/OEM specific
                     );
diff --git a/packages/SystemUI/monet/src/com/android/systemui/monet/dynamiccolor/MaterialDynamicColors.java b/packages/SystemUI/monet/src/com/android/systemui/monet/dynamiccolor/MaterialDynamicColors.java
index 26eefa9..377771f 100644
--- a/packages/SystemUI/monet/src/com/android/systemui/monet/dynamiccolor/MaterialDynamicColors.java
+++ b/packages/SystemUI/monet/src/com/android/systemui/monet/dynamiccolor/MaterialDynamicColors.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.monet.dynamiccolor;
 
+import android.os.SystemProperties;
+
 import com.android.systemui.monet.dislike.DislikeAnalyzer;
 import com.android.systemui.monet.dynamiccolor.DynamicColor;
 import com.android.systemui.monet.dynamiccolor.ToneDeltaConstraint;
@@ -28,7 +30,8 @@
 /** Named colors, otherwise known as tokens, or roles, in the Material Design system. */
 public final class MaterialDynamicColors {
     private static final double CONTAINER_ACCENT_TONE_DELTA = 15.0;
-
+    private static final boolean IS_FIDELITY_ON_ALL_VARIANTS = SystemProperties.getBoolean(
+            "persist.fidelity_on_theme_variants", false);
 
     private MaterialDynamicColors() {
     }
@@ -392,6 +395,9 @@
     }
 
     private static boolean isFidelity(DynamicScheme scheme) {
+        if (IS_FIDELITY_ON_ALL_VARIANTS) {
+            return scheme.variant != Variant.NEUTRAL && scheme.variant != Variant.MONOCHROME;
+        }
         return scheme.variant == Variant.FIDELITY || scheme.variant == Variant.CONTENT;
     }
 
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 2cedaa7..0e089c8 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -1018,7 +1018,7 @@
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"Données mobiles"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"Connecté"</string>
-    <string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Connexion temporaire"</string>
+    <string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Connectée temporairement"</string>
     <string name="mobile_data_poor_connection" msgid="819617772268371434">"Connexion médiocre"</string>
     <string name="mobile_data_off_summary" msgid="3663995422004150567">"Pas de connexion automatique des données mobiles"</string>
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"Aucune connexion"</string>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 44388dc..f62029a 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -198,7 +198,8 @@
     <skip />
     <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"அறிவிப்பு விவரம்."</string>
     <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"உடனடி அமைப்பு."</string>
-    <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"விரைவு அமைப்புகளும் அறிவிப்பு விவரமும்."</string>
+    <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) -->
+    <skip />
     <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"லாக் ஸ்கிரீன்."</string>
     <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"பணி லாக் ஸ்கிரீன்"</string>
     <string name="accessibility_desc_close" msgid="8293708213442107755">"மூடு"</string>
diff --git a/packages/SystemUI/res/values/flags.xml b/packages/SystemUI/res/values/flags.xml
index 6354752..763930d 100644
--- a/packages/SystemUI/res/values/flags.xml
+++ b/packages/SystemUI/res/values/flags.xml
@@ -30,9 +30,6 @@
 
     <bool name="flag_charging_ripple">false</bool>
 
-    <!-- Whether to show chipbar UI whenever the device is unlocked by ActiveUnlock. -->
-    <bool name="flag_active_unlock_chipbar">true</bool>
-
     <!--  Whether the user switcher chip shows in the status bar. When true, the multi user
       avatar will no longer show on the lockscreen -->
     <bool name="flag_user_switcher_chip">false</bool>
diff --git a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt
index fb2c02a..3af9ea3 100644
--- a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt
+++ b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt
@@ -629,7 +629,7 @@
                     "userId: $int1 " +
                     "old: $bool1, " +
                     "new: $bool2 " +
-                    "context: $context"
+                    "context: $str1"
             }
         )
     }
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/OWNERS b/packages/SystemUI/src/com/android/systemui/accessibility/OWNERS
new file mode 100644
index 0000000..1f66c91
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 44215
+
+include /core/java/android/view/accessibility/OWNERS
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index 3608b91..9264e6c 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -151,12 +151,6 @@
     val CUSTOMIZABLE_LOCK_SCREEN_QUICK_AFFORDANCES =
         releasedFlag(216, "customizable_lock_screen_quick_affordances")
 
-    /** Shows chipbar UI whenever the device is unlocked by ActiveUnlock (watch). */
-    // TODO(b/256513609): Tracking Bug
-    @JvmField
-    val ACTIVE_UNLOCK_CHIPBAR =
-        resourceBooleanFlag(217, R.bool.flag_active_unlock_chipbar, "active_unlock_chipbar")
-
     /**
      * Migrates control of the LightRevealScrim's reveal effect and amount from legacy code to the
      * new KeyguardTransitionRepository.
@@ -263,8 +257,7 @@
     /** Enables new QS Edit Mode visual refresh */
     // TODO(b/269787742): Tracking Bug
     @JvmField
-    val ENABLE_NEW_QS_EDIT_MODE =
-        unreleasedFlag(510, "enable_new_qs_edit_mode", teamfood = false)
+    val ENABLE_NEW_QS_EDIT_MODE = unreleasedFlag(510, "enable_new_qs_edit_mode", teamfood = false)
 
     // 600- status bar
 
@@ -600,8 +593,7 @@
     @JvmField val UDFPS_ELLIPSE_DETECTION = releasedFlag(2201, "udfps_ellipse_detection")
 
     // 2300 - stylus
-    @JvmField
-    val TRACK_STYLUS_EVER_USED = unreleasedFlag(2300, "track_stylus_ever_used", teamfood = true)
+    @JvmField val TRACK_STYLUS_EVER_USED = releasedFlag(2300, "track_stylus_ever_used")
     @JvmField
     val ENABLE_STYLUS_CHARGING_UI =
         unreleasedFlag(2301, "enable_stylus_charging_ui", teamfood = true)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractor.kt
index edd2897..7368a46 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractor.kt
@@ -21,8 +21,10 @@
 import android.hardware.biometrics.BiometricSourceType
 import android.os.Handler
 import android.os.Trace
-import android.view.View
+import android.os.UserHandle
+import android.os.UserManager
 import android.util.Log
+import android.view.View
 import com.android.keyguard.KeyguardConstants
 import com.android.keyguard.KeyguardSecurityModel
 import com.android.keyguard.KeyguardUpdateMonitor
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
index 00e9a79..9928c4f 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
@@ -16,17 +16,12 @@
 
 package com.android.systemui.media.dialog;
 
-import static android.media.RouteListingPreference.Item.SELECTION_BEHAVIOR_GO_TO_APP;
-import static android.media.RouteListingPreference.Item.SELECTION_BEHAVIOR_NONE;
-import static android.media.RouteListingPreference.Item.SELECTION_BEHAVIOR_TRANSFER;
-import static android.media.RouteListingPreference.Item.SUBTEXT_AD_ROUTING_DISALLOWED;
-import static android.media.RouteListingPreference.Item.SUBTEXT_DOWNLOADED_CONTENT_ROUTING_DISALLOWED;
-import static android.media.RouteListingPreference.Item.SUBTEXT_SUBSCRIPTION_REQUIRED;
+import static com.android.settingslib.media.MediaDevice.SelectionBehavior.SELECTION_BEHAVIOR_GO_TO_APP;
+import static com.android.settingslib.media.MediaDevice.SelectionBehavior.SELECTION_BEHAVIOR_NONE;
+import static com.android.settingslib.media.MediaDevice.SelectionBehavior.SELECTION_BEHAVIOR_TRANSFER;
 
 import android.content.Context;
 import android.content.res.ColorStateList;
-import android.graphics.PorterDuff;
-import android.graphics.PorterDuffColorFilter;
 import android.graphics.drawable.AnimatedVectorDrawable;
 import android.graphics.drawable.Drawable;
 import android.os.Build;
@@ -296,6 +291,8 @@
                             && mController.isAdvancedLayoutSupported()) {
                         //If device is connected and there's other selectable devices, layout as
                         // one of selected devices.
+                        updateTitleIcon(R.drawable.media_output_icon_volume,
+                                mController.getColorItemContent());
                         boolean isDeviceDeselectable = isDeviceIncluded(
                                 mController.getDeselectableMediaDevice(), device);
                         updateGroupableCheckBox(true, isDeviceDeselectable, device);
@@ -343,7 +340,7 @@
                             updateDeviceStatusIcon(deviceStatusIcon);
                             mStatusIcon.setVisibility(View.VISIBLE);
                         }
-                        updateTwoLineLayoutContentAlpha(
+                        updateSingleLineLayoutContentAlpha(
                                 updateClickActionBasedOnSelectionBehavior(device)
                                         ? DEVICE_CONNECTED_ALPHA : DEVICE_DISCONNECTED_ALPHA);
                     } else {
@@ -367,11 +364,18 @@
             mStatusIcon.setAlpha(alphaValue);
         }
 
+        private void updateSingleLineLayoutContentAlpha(float alphaValue) {
+            mTitleIcon.setAlpha(alphaValue);
+            mTitleText.setAlpha(alphaValue);
+            mStatusIcon.setAlpha(alphaValue);
+        }
+
         private void updateEndClickAreaAsSessionEditing(MediaDevice device) {
             mEndClickIcon.setOnClickListener(null);
             mEndTouchArea.setOnClickListener(null);
             updateEndClickAreaColor(mController.getColorSeekbarProgress());
-            mEndClickIcon.setColorFilter(mController.getColorItemContent());
+            mEndClickIcon.setImageTintList(
+                    ColorStateList.valueOf(mController.getColorItemContent()));
             mEndClickIcon.setOnClickListener(
                     v -> mController.tryToLaunchInAppRoutingIntent(device.getId(), v));
             mEndTouchArea.setOnClickListener(v -> mCheckBox.performClick());
@@ -379,8 +383,8 @@
 
         public void updateEndClickAreaColor(int color) {
             if (mController.isAdvancedLayoutSupported()) {
-                mEndTouchArea.getBackground().setColorFilter(
-                        new PorterDuffColorFilter(color, PorterDuff.Mode.SRC_IN));
+                mEndTouchArea.setBackgroundTintList(
+                        ColorStateList.valueOf(color));
             }
         }
 
@@ -394,22 +398,22 @@
         private void updateConnectionFailedStatusIcon() {
             mStatusIcon.setImageDrawable(
                     mContext.getDrawable(R.drawable.media_output_status_failed));
-            mStatusIcon.setColorFilter(mController.getColorItemContent());
+            mStatusIcon.setImageTintList(
+                    ColorStateList.valueOf(mController.getColorItemContent()));
         }
 
         private void updateDeviceStatusIcon(Drawable drawable) {
             mStatusIcon.setImageDrawable(drawable);
-            mStatusIcon.setColorFilter(mController.getColorItemContent());
+            mStatusIcon.setImageTintList(
+                    ColorStateList.valueOf(mController.getColorItemContent()));
             if (drawable instanceof AnimatedVectorDrawable) {
                 ((AnimatedVectorDrawable) drawable).start();
             }
         }
 
         private void updateProgressBarColor() {
-            mProgressBar.getIndeterminateDrawable().setColorFilter(
-                    new PorterDuffColorFilter(
-                            mController.getColorItemContent(),
-                            PorterDuff.Mode.SRC_IN));
+            mProgressBar.getIndeterminateDrawable().setTintList(
+                    ColorStateList.valueOf(mController.getColorItemContent()));
         }
 
         public void updateEndClickArea(MediaDevice device, boolean isDeviceDeselectable) {
@@ -419,9 +423,8 @@
             mEndTouchArea.setImportantForAccessibility(
                     View.IMPORTANT_FOR_ACCESSIBILITY_YES);
             if (mController.isAdvancedLayoutSupported()) {
-                mEndTouchArea.getBackground().setColorFilter(
-                        new PorterDuffColorFilter(mController.getColorItemBackground(),
-                                PorterDuff.Mode.SRC_IN));
+                mEndTouchArea.setBackgroundTintList(
+                        ColorStateList.valueOf(mController.getColorItemBackground()));
             }
             setUpContentDescriptionForView(mEndTouchArea, true, device);
         }
@@ -450,11 +453,11 @@
                 setSingleLineLayout(mContext.getText(R.string.media_output_dialog_pairing_new));
                 final Drawable addDrawable = mContext.getDrawable(R.drawable.ic_add);
                 mTitleIcon.setImageDrawable(addDrawable);
-                mTitleIcon.setColorFilter(mController.getColorItemContent());
+                mTitleIcon.setImageTintList(
+                        ColorStateList.valueOf(mController.getColorItemContent()));
                 if (mController.isAdvancedLayoutSupported()) {
-                    mIconAreaLayout.getBackground().setColorFilter(
-                            new PorterDuffColorFilter(mController.getColorItemBackground(),
-                                    PorterDuff.Mode.SRC_IN));
+                    mIconAreaLayout.setBackgroundTintList(
+                            ColorStateList.valueOf(mController.getColorItemBackground()));
                 }
                 mContainerLayout.setOnClickListener(mController::launchBluetoothPairing);
             }
@@ -534,11 +537,12 @@
         @DoNotInline
         static Drawable getDeviceStatusIconBasedOnSelectionBehavior(MediaDevice device,
                 Context context) {
-            switch (device.getSubtext()) {
-                case SUBTEXT_AD_ROUTING_DISALLOWED:
-                case SUBTEXT_DOWNLOADED_CONTENT_ROUTING_DISALLOWED:
+            switch (device.getSelectionBehavior()) {
+                case SELECTION_BEHAVIOR_NONE:
                     return context.getDrawable(R.drawable.media_output_status_failed);
-                case SUBTEXT_SUBSCRIPTION_REQUIRED:
+                case SELECTION_BEHAVIOR_TRANSFER:
+                    return null;
+                case SELECTION_BEHAVIOR_GO_TO_APP:
                     return context.getDrawable(R.drawable.media_output_status_help);
             }
             return null;
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
index 2a2cf63..f76f049 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
@@ -23,8 +23,7 @@
 import android.annotation.DrawableRes;
 import android.app.WallpaperColors;
 import android.content.Context;
-import android.graphics.PorterDuff;
-import android.graphics.PorterDuffColorFilter;
+import android.content.res.ColorStateList;
 import android.graphics.Typeface;
 import android.graphics.drawable.ClipDrawable;
 import android.graphics.drawable.Drawable;
@@ -196,9 +195,8 @@
                 mIconAreaLayout.setOnClickListener(null);
                 mVolumeValueText.setTextColor(mController.getColorItemContent());
             }
-            mSeekBar.getProgressDrawable().setColorFilter(
-                    new PorterDuffColorFilter(mController.getColorSeekbarProgress(),
-                            PorterDuff.Mode.SRC_IN));
+            mSeekBar.setProgressTintList(
+                    ColorStateList.valueOf(mController.getColorSeekbarProgress()));
         }
 
         abstract void onBind(int customizedItem);
@@ -224,16 +222,14 @@
                     updateSeekbarProgressBackground();
                 }
             }
-            mItemLayout.getBackground().setColorFilter(new PorterDuffColorFilter(
-                    isActive ? mController.getColorConnectedItemBackground()
-                            : mController.getColorItemBackground(),
-                    PorterDuff.Mode.SRC_IN));
+            mItemLayout.setBackgroundTintList(
+                    ColorStateList.valueOf(isActive ? mController.getColorConnectedItemBackground()
+                            : mController.getColorItemBackground()));
             if (mController.isAdvancedLayoutSupported()) {
-                mIconAreaLayout.getBackground().setColorFilter(new PorterDuffColorFilter(
-                        showSeekBar ? mController.getColorSeekbarProgress()
+                mIconAreaLayout.setBackgroundTintList(
+                        ColorStateList.valueOf(showSeekBar ? mController.getColorSeekbarProgress()
                                 : showProgressBar ? mController.getColorConnectedItemBackground()
-                                        : mController.getColorItemBackground(),
-                        PorterDuff.Mode.SRC_IN));
+                                        : mController.getColorItemBackground()));
             }
             mProgressBar.setVisibility(showProgressBar ? View.VISIBLE : View.GONE);
             mSeekBar.setAlpha(1);
@@ -251,7 +247,8 @@
                 params.rightMargin = showEndTouchArea ? mController.getItemMarginEndSelectable()
                         : mController.getItemMarginEndDefault();
             }
-            mTitleIcon.setColorFilter(mController.getColorItemContent());
+            mTitleIcon.setBackgroundTintList(
+                    ColorStateList.valueOf(mController.getColorItemContent()));
         }
 
         void setTwoLineLayout(MediaDevice device, boolean bFocused, boolean showSeekBar,
@@ -274,15 +271,14 @@
                 backgroundDrawable = mContext.getDrawable(
                         showSeekBar ? R.drawable.media_output_item_background_active
                                 : R.drawable.media_output_item_background).mutate();
-                backgroundDrawable.setColorFilter(new PorterDuffColorFilter(
+                backgroundDrawable.setTint(
                         showSeekBar ? mController.getColorConnectedItemBackground()
-                                : mController.getColorItemBackground(), PorterDuff.Mode.SRC_IN));
-                mIconAreaLayout.getBackground().setColorFilter(new PorterDuffColorFilter(
-                        showProgressBar || isFakeActive
+                                : mController.getColorItemBackground());
+                mIconAreaLayout.setBackgroundTintList(
+                        ColorStateList.valueOf(showProgressBar || isFakeActive
                                 ? mController.getColorConnectedItemBackground()
                                 : showSeekBar ? mController.getColorSeekbarProgress()
-                                        : mController.getColorItemBackground(),
-                        PorterDuff.Mode.SRC_IN));
+                                        : mController.getColorItemBackground()));
                 if (showSeekBar) {
                     updateSeekbarProgressBackground();
                 }
@@ -297,9 +293,7 @@
                 backgroundDrawable = mContext.getDrawable(
                                 R.drawable.media_output_item_background)
                         .mutate();
-                backgroundDrawable.setColorFilter(new PorterDuffColorFilter(
-                        mController.getColorItemBackground(),
-                        PorterDuff.Mode.SRC_IN));
+                backgroundDrawable.setTint(mController.getColorItemBackground());
             }
             mItemLayout.setBackground(backgroundDrawable);
             mProgressBar.setVisibility(showProgressBar ? View.VISIBLE : View.GONE);
@@ -442,11 +436,10 @@
 
         void updateTitleIcon(@DrawableRes int id, int color) {
             mTitleIcon.setImageDrawable(mContext.getDrawable(id));
-            mTitleIcon.setColorFilter(color);
+            mTitleIcon.setImageTintList(ColorStateList.valueOf(color));
             if (mController.isAdvancedLayoutSupported()) {
-                mIconAreaLayout.getBackground().setColorFilter(
-                        new PorterDuffColorFilter(mController.getColorSeekbarProgress(),
-                                PorterDuff.Mode.SRC_IN));
+                mIconAreaLayout.setBackgroundTintList(
+                        ColorStateList.valueOf(mController.getColorSeekbarProgress()));
             }
         }
 
@@ -462,9 +455,7 @@
             final Drawable backgroundDrawable = mContext.getDrawable(
                                     R.drawable.media_output_item_background_active)
                             .mutate();
-            backgroundDrawable.setColorFilter(
-                    new PorterDuffColorFilter(mController.getColorConnectedItemBackground(),
-                            PorterDuff.Mode.SRC_IN));
+            backgroundDrawable.setTint(mController.getColorConnectedItemBackground());
             mItemLayout.setBackground(backgroundDrawable);
         }
 
@@ -539,10 +530,8 @@
         Drawable getSpeakerDrawable() {
             final Drawable drawable = mContext.getDrawable(R.drawable.ic_speaker_group_black_24dp)
                     .mutate();
-            drawable.setColorFilter(
-                    new PorterDuffColorFilter(Utils.getColorStateListDefaultColor(mContext,
-                            R.color.media_dialog_item_main_content),
-                            PorterDuff.Mode.SRC_IN));
+            drawable.setTint(Utils.getColorStateListDefaultColor(mContext,
+                    R.color.media_dialog_item_main_content));
             return drawable;
         }
 
@@ -574,7 +563,9 @@
                         return;
                     }
                     mTitleIcon.setImageIcon(icon);
-                    mTitleIcon.setColorFilter(mController.getColorItemContent());
+                    icon.setTint(mController.getColorItemContent());
+                    mTitleIcon.setImageTintList(
+                            ColorStateList.valueOf(mController.getColorItemContent()));
                 });
             });
         }
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
index 2aedd36..9203897 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
@@ -395,7 +395,6 @@
             launchIntent.putExtra(EXTRA_ROUTE_ID, routeId);
             launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
             mCallback.dismissDialog();
-            mContext.startActivity(launchIntent);
             mActivityStarter.startActivity(launchIntent, true, controller);
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputMetricLogger.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputMetricLogger.java
index 2250d72..39d4e6e 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputMetricLogger.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputMetricLogger.java
@@ -80,6 +80,10 @@
             Log.d(TAG, "logOutputSuccess - selected device: " + selectedDeviceType);
         }
 
+        if (mSourceDevice == null && mTargetDevice == null) {
+            return;
+        }
+
         updateLoggingDeviceCount(deviceList);
 
         SysUiStatsLog.write(
@@ -105,6 +109,10 @@
             Log.d(TAG, "logOutputSuccess - selected device: " + selectedDeviceType);
         }
 
+        if (mSourceDevice == null && mTargetDevice == null) {
+            return;
+        }
+
         updateLoggingMediaItemCount(deviceItemList);
 
         SysUiStatsLog.write(
@@ -176,6 +184,10 @@
             Log.e(TAG, "logRequestFailed - " + reason);
         }
 
+        if (mSourceDevice == null && mTargetDevice == null) {
+            return;
+        }
+
         updateLoggingDeviceCount(deviceList);
 
         SysUiStatsLog.write(
@@ -201,6 +213,10 @@
             Log.e(TAG, "logRequestFailed - " + reason);
         }
 
+        if (mSourceDevice == null && mTargetDevice == null) {
+            return;
+        }
+
         updateLoggingMediaItemCount(deviceItemList);
 
         SysUiStatsLog.write(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
index 39e4000..4522e41 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
@@ -443,6 +443,7 @@
         CancellationSignal cancellationSignal = new CancellationSignal();
         cancellationSignal.setOnCancelListener(
                 () -> runningInflations.values().forEach(CancellationSignal::cancel));
+
         return cancellationSignal;
     }
 
@@ -783,6 +784,7 @@
     public static class AsyncInflationTask extends AsyncTask<Void, Void, InflationProgress>
             implements InflationCallback, InflationTask {
 
+        private static final long IMG_PRELOAD_TIMEOUT_MS = 1000L;
         private final NotificationEntry mEntry;
         private final Context mContext;
         private final boolean mInflateSynchronously;
@@ -876,7 +878,7 @@
                         recoveredBuilder, mIsLowPriority, mUsesIncreasedHeight,
                         mUsesIncreasedHeadsUpHeight, packageContext);
                 InflatedSmartReplyState previousSmartReplyState = mRow.getExistingSmartReplyState();
-                return inflateSmartReplyViews(
+                InflationProgress result = inflateSmartReplyViews(
                         inflationProgress,
                         mReInflateFlags,
                         mEntry,
@@ -884,6 +886,11 @@
                         packageContext,
                         previousSmartReplyState,
                         mSmartRepliesInflater);
+
+                // wait for image resolver to finish preloading
+                mRow.getImageResolver().waitForPreloadedImages(IMG_PRELOAD_TIMEOUT_MS);
+
+                return result;
             } catch (Exception e) {
                 mError = e;
                 return null;
@@ -918,6 +925,9 @@
                 mCallback.handleInflationException(mRow.getEntry(),
                         new InflationException("Couldn't inflate contentViews" + e));
             }
+
+            // Cancel any image loading tasks, not useful any more
+            mRow.getImageResolver().cancelRunningTasks();
         }
 
         @Override
@@ -944,6 +954,9 @@
             // Notify the resolver that the inflation task has finished,
             // try to purge unnecessary cached entries.
             mRow.getImageResolver().purgeCache();
+
+            // Cancel any image loading tasks that have not completed at this point
+            mRow.getImageResolver().cancelRunningTasks();
         }
 
         private static class RtlEnabledContext extends ContextWrapper {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageCache.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageCache.java
index 41eeada0..fe0b312 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageCache.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageCache.java
@@ -22,8 +22,11 @@
 import android.util.Log;
 
 import java.util.Set;
+import java.util.concurrent.CancellationException;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
 
 /**
  * A cache for inline images of image messages.
@@ -56,12 +59,13 @@
     }
 
     @Override
-    public Drawable get(Uri uri) {
+    public Drawable get(Uri uri, long timeoutMs) {
         Drawable result = null;
         try {
-            result = mCache.get(uri).get();
-        } catch (InterruptedException | ExecutionException ex) {
-            Log.d(TAG, "get: Failed get image from " + uri);
+            result = mCache.get(uri).get(timeoutMs, TimeUnit.MILLISECONDS);
+        } catch (InterruptedException | ExecutionException
+                | TimeoutException | CancellationException ex) {
+            Log.d(TAG, "get: Failed get image from " + uri + " " + ex);
         }
         return result;
     }
@@ -72,6 +76,15 @@
         mCache.entrySet().removeIf(entry -> !wantedSet.contains(entry.getKey()));
     }
 
+    @Override
+    public void cancelRunningTasks() {
+        mCache.forEach((key, value) -> {
+            if (value.getStatus() != AsyncTask.Status.FINISHED) {
+                value.cancel(true);
+            }
+        });
+    }
+
     private static class PreloadImageTask extends AsyncTask<Uri, Void, Drawable> {
         private final NotificationInlineImageResolver mResolver;
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolver.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolver.java
index b05e64ab..c620f44 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolver.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolver.java
@@ -23,6 +23,7 @@
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Parcelable;
+import android.os.SystemClock;
 import android.util.Log;
 
 import com.android.internal.R;
@@ -45,6 +46,9 @@
 public class NotificationInlineImageResolver implements ImageResolver {
     private static final String TAG = NotificationInlineImageResolver.class.getSimpleName();
 
+    // Timeout for loading images from ImageCache when calling from UI thread
+    private static final long MAX_UI_THREAD_TIMEOUT_MS = 100L;
+
     private final Context mContext;
     private final ImageCache mImageCache;
     private Set<Uri> mWantedUriSet;
@@ -123,17 +127,25 @@
         return null;
     }
 
+    /**
+     * Loads an image from the Uri.
+     * This method is synchronous and is usually called from the Main thread.
+     * It will time-out after MAX_UI_THREAD_TIMEOUT_MS.
+     *
+     * @param uri Uri of the target image.
+     * @return drawable of the image, null if loading failed/timeout
+     */
     @Override
     public Drawable loadImage(Uri uri) {
-        return hasCache() ? loadImageFromCache(uri) : resolveImage(uri);
+        return hasCache() ? loadImageFromCache(uri, MAX_UI_THREAD_TIMEOUT_MS) : resolveImage(uri);
     }
 
-    private Drawable loadImageFromCache(Uri uri) {
+    private Drawable loadImageFromCache(Uri uri, long timeoutMs) {
         // if the uri isn't currently cached, try caching it first
         if (!mImageCache.hasEntry(uri)) {
             mImageCache.preload((uri));
         }
-        return mImageCache.get(uri);
+        return mImageCache.get(uri, timeoutMs);
     }
 
     /**
@@ -208,6 +220,30 @@
     }
 
     /**
+     * Wait for a maximum timeout for images to finish preloading
+     * @param timeoutMs total timeout time
+     */
+    void waitForPreloadedImages(long timeoutMs) {
+        if (!hasCache()) {
+            return;
+        }
+        Set<Uri> preloadedUris = getWantedUriSet();
+        if (preloadedUris != null) {
+            // Decrement remaining timeout after each image check
+            long endTimeMs = SystemClock.elapsedRealtime() + timeoutMs;
+            preloadedUris.forEach(
+                    uri -> loadImageFromCache(uri, endTimeMs - SystemClock.elapsedRealtime()));
+        }
+    }
+
+    void cancelRunningTasks() {
+        if (!hasCache()) {
+            return;
+        }
+        mImageCache.cancelRunningTasks();
+    }
+
+    /**
      * A interface for internal cache implementation of this resolver.
      */
     interface ImageCache {
@@ -216,7 +252,7 @@
          * @param uri The uri of the image.
          * @return Drawable of the image.
          */
-        Drawable get(Uri uri);
+        Drawable get(Uri uri, long timeoutMs);
 
         /**
          * Set the image resolver that actually resolves image from specified uri.
@@ -241,6 +277,11 @@
          * Purge unnecessary entries in the cache.
          */
         void purge();
+
+        /**
+         * Cancel all unfinished image loading tasks
+         */
+        void cancelRunningTasks();
     }
 
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/OWNERS b/packages/SystemUI/tests/src/com/android/systemui/accessibility/OWNERS
new file mode 100644
index 0000000..a2001e6
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/view/accessibility/OWNERS
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java
index 56e060d..17d8799 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java
@@ -16,12 +16,13 @@
 
 package com.android.systemui.media.dialog;
 
-import static android.media.RouteListingPreference.Item.SELECTION_BEHAVIOR_GO_TO_APP;
-import static android.media.RouteListingPreference.Item.SELECTION_BEHAVIOR_NONE;
 import static android.media.RouteListingPreference.Item.SUBTEXT_AD_ROUTING_DISALLOWED;
 import static android.media.RouteListingPreference.Item.SUBTEXT_CUSTOM;
 import static android.media.RouteListingPreference.Item.SUBTEXT_SUBSCRIPTION_REQUIRED;
 
+import static com.android.settingslib.media.MediaDevice.SelectionBehavior.SELECTION_BEHAVIOR_GO_TO_APP;
+import static com.android.settingslib.media.MediaDevice.SelectionBehavior.SELECTION_BEHAVIOR_NONE;
+
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.Mockito.mock;
diff --git a/services/backup/OWNERS b/services/backup/OWNERS
index 79709a3..1176178 100644
--- a/services/backup/OWNERS
+++ b/services/backup/OWNERS
@@ -2,7 +2,6 @@
 
 set noparent
 
-bryanmawhinney@google.com
 jstemmer@google.com
 martinoh@google.com
 millmore@google.com
diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerService.java b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
index 7261709..287d713 100644
--- a/services/backup/java/com/android/server/backup/UserBackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
@@ -36,6 +36,7 @@
 import static com.android.server.backup.internal.BackupHandler.MSG_RUN_RESTORE;
 import static com.android.server.backup.internal.BackupHandler.MSG_SCHEDULE_BACKUP_PACKAGE;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
 import android.app.ActivityManager;
@@ -973,6 +974,7 @@
                 /* scheduler */ null);
     }
 
+    @NonNull
     private ArrayList<FullBackupEntry> readFullBackupSchedule() {
         boolean changed = false;
         ArrayList<FullBackupEntry> schedule = null;
@@ -986,11 +988,11 @@
                  DataInputStream in = new DataInputStream(bufStream)) {
                 int version = in.readInt();
                 if (version != SCHEDULE_FILE_VERSION) {
-                    Slog.e(
-                            TAG,
-                            addUserIdToLogMessage(
-                                    mUserId, "Unknown backup schedule version " + version));
-                    return null;
+                    // The file version doesn't match the expected value.
+                    // Since this is within a "try" block, this exception will be treated like
+                    // any other exception, and caught below.
+                    throw new IllegalArgumentException("Unknown backup schedule version "
+                            + version);
                 }
 
                 final int numPackages = in.readInt();
diff --git a/services/core/Android.bp b/services/core/Android.bp
index c8caab9..199fc22 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -74,8 +74,8 @@
         "{ ! (diff $(out) $(location :services.core.protolog.json) | grep -q '^<') || " +
         "{ echo -e '\\n\\n################################################################\\n#\\n" +
         "#  ERROR: ProtoLog viewer config is stale.  To update it, run:\\n#\\n" +
-        "#  cp $(location :generate-protolog.json) " +
-        "$(location :services.core.protolog.json)\\n#\\n" +
+        "#  cp $${ANDROID_BUILD_TOP}/$(location :generate-protolog.json) " +
+        "$${ANDROID_BUILD_TOP}/$(location :services.core.protolog.json)\\n#\\n" +
         "################################################################\\n\\n' >&2 && false; } }",
     out: ["services.core.protolog.json"],
 }
diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java
index 22ac22d..b673fb6 100644
--- a/services/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -49,6 +49,7 @@
 import com.android.server.pm.PackageList;
 import com.android.server.pm.PackageSetting;
 import com.android.server.pm.dex.DynamicCodeLogger;
+import com.android.server.pm.permission.LegacyPermissionSettings;
 import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.pm.pkg.SharedUserApi;
@@ -1075,6 +1076,11 @@
     public abstract void writePermissionSettings(@NonNull @UserIdInt int[] userIds, boolean async);
 
     /**
+     * Read legacy permission definitions for permissions migration to new permission subsystem.
+     */
+    public abstract LegacyPermissionSettings getLegacyPermissions();
+
+    /**
      * Returns {@code true} if the caller is the installer of record for the given package.
      * Otherwise, {@code false}.
      */
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 225afea..a60f06a 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -4945,10 +4945,6 @@
             if (intent.getClipData() == null) {
                 intent.setClipData(ClipData.newPlainText(null, null));
             }
-            intent.setFlags(intent.getFlags() & ~(Intent.FLAG_GRANT_READ_URI_PERMISSION
-                    | Intent.FLAG_GRANT_WRITE_URI_PERMISSION
-                    | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION
-                    | Intent.FLAG_GRANT_PREFIX_URI_PERMISSION));
             final long bid = Binder.clearCallingIdentity();
             try {
                 PackageManager pm = mContext.getPackageManager();
@@ -4994,7 +4990,19 @@
             if (intent == null) {
                 return (simulateIntent == null);
             }
-            return intent.filterEquals(simulateIntent);
+            if (!intent.filterEquals(simulateIntent)) {
+                return false;
+            }
+
+            if (intent.getSelector() != simulateIntent.getSelector()) {
+                return false;
+            }
+
+            int prohibitedFlags = Intent.FLAG_GRANT_READ_URI_PERMISSION
+                    | Intent.FLAG_GRANT_WRITE_URI_PERMISSION
+                    | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION
+                    | Intent.FLAG_GRANT_PREFIX_URI_PERMISSION;
+            return (simulateIntent.getFlags() & prohibitedFlags) == 0;
         }
 
         private boolean isExportedSystemActivity(ActivityInfo activityInfo) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 432c209..ccc218e 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -15574,16 +15574,6 @@
             return false;
         }
 
-        final ApplicationInfo sdkSandboxInfo;
-        try {
-            final PackageManager pm = mContext.getPackageManager();
-            sdkSandboxInfo = pm.getApplicationInfoAsUser(pm.getSdkSandboxPackageName(), 0, userId);
-        } catch (NameNotFoundException e) {
-            reportStartInstrumentationFailureLocked(
-                    watcher, className, "Can't find SdkSandbox package");
-            return false;
-        }
-
         final SdkSandboxManagerLocal sandboxManagerLocal =
                 LocalManagerRegistry.getManager(SdkSandboxManagerLocal.class);
         if (sandboxManagerLocal == null) {
@@ -15592,12 +15582,20 @@
             return false;
         }
 
-        final String processName = sandboxManagerLocal.getSdkSandboxProcessNameForInstrumentation(
-                sdkSandboxClientAppInfo);
+        final ApplicationInfo sdkSandboxInfo;
+        try {
+            sdkSandboxInfo =
+                    sandboxManagerLocal.getSdkSandboxApplicationInfoForInstrumentation(
+                            sdkSandboxClientAppInfo, userId);
+        } catch (NameNotFoundException e) {
+            reportStartInstrumentationFailureLocked(
+                    watcher, className, "Can't find SdkSandbox package");
+            return false;
+        }
 
         ActiveInstrumentation activeInstr = new ActiveInstrumentation(this);
         activeInstr.mClass = className;
-        activeInstr.mTargetProcesses = new String[]{processName};
+        activeInstr.mTargetProcesses = new String[]{sdkSandboxInfo.processName};
         activeInstr.mTargetInfo = sdkSandboxInfo;
         activeInstr.mProfileFile = profileFile;
         activeInstr.mArguments = arguments;
@@ -15631,7 +15629,7 @@
 
                 ProcessRecord app = addAppLocked(
                         sdkSandboxInfo,
-                        processName,
+                        sdkSandboxInfo.processName,
                         /* isolated= */ false,
                         /* isSdkSandbox= */ true,
                         sdkSandboxUid,
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 02c1b8b..2c79f8c 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -1063,16 +1063,26 @@
     }
 
     @NeverCompile
-    int runCompact(PrintWriter pw) {
+    int runCompact(PrintWriter pw) throws RemoteException {
         ProcessRecord app;
         String op = getNextArgRequired();
         boolean isFullCompact = op.equals("full");
         boolean isSomeCompact = op.equals("some");
         if (isFullCompact || isSomeCompact) {
             String processName = getNextArgRequired();
-            String uid = getNextArgRequired();
             synchronized (mInternal.mProcLock) {
-                app = mInternal.getProcessRecordLocked(processName, Integer.parseInt(uid));
+                // Default to current user
+                int userId = mInterface.getCurrentUserId();
+                String userOpt = getNextOption();
+                if (userOpt != null && "--user".equals(userOpt)) {
+                    int inputUserId = UserHandle.parseUserArg(getNextArgRequired());
+                    if (inputUserId != UserHandle.USER_CURRENT) {
+                        userId = inputUserId;
+                    }
+                }
+                final int uid =
+                        mInternal.getPackageManagerInternal().getPackageUid(processName, 0, userId);
+                app = mInternal.getProcessRecordLocked(processName, uid);
             }
             pw.println("Process record found pid: " + app.mPid);
             if (isFullCompact) {
@@ -1098,6 +1108,28 @@
                 mInternal.mOomAdjuster.mCachedAppOptimizer.compactAllSystem();
             }
             pw.println("Finished system compaction");
+        } else if (op.equals("native")) {
+            op = getNextArgRequired();
+            isFullCompact = op.equals("full");
+            isSomeCompact = op.equals("some");
+            int pid;
+            String pidStr = getNextArgRequired();
+            try {
+                pid = Integer.parseInt(pidStr);
+            } catch (Exception e) {
+                getErrPrintWriter().println("Error: failed to parse '" + pidStr + "' as a PID");
+                return -1;
+            }
+            if (isFullCompact) {
+                mInternal.mOomAdjuster.mCachedAppOptimizer.compactNative(
+                        CachedAppOptimizer.CompactProfile.FULL, pid);
+            } else if (isSomeCompact) {
+                mInternal.mOomAdjuster.mCachedAppOptimizer.compactNative(
+                        CachedAppOptimizer.CompactProfile.SOME, pid);
+            } else {
+                getErrPrintWriter().println("Error: unknown compaction type '" + op + "'");
+                return -1;
+            }
         } else {
             getErrPrintWriter().println("Error: unknown compact command '" + op + "'");
             return -1;
@@ -4007,11 +4039,17 @@
             pw.println("      --allow-background-activity-starts: The receiver may start activities");
             pw.println("          even if in the background.");
             pw.println("      --async: Send without waiting for the completion of the receiver.");
-            pw.println("  compact [some|full|system] <process_name> <Package UID>");
-            pw.println("      Force process compaction.");
+            pw.println("  compact [some|full] <process_name> [--user <USER_ID>]");
+            pw.println("      Perform a single process compaction.");
             pw.println("      some: execute file compaction.");
             pw.println("      full: execute anon + file compaction.");
             pw.println("      system: system compaction.");
+            pw.println("  compact system");
+            pw.println("      Perform a full system compaction.");
+            pw.println("  compact native [some|full] <pid>");
+            pw.println("      Perform a native compaction for process with <pid>.");
+            pw.println("      some: execute file compaction.");
+            pw.println("      full: execute anon + file compaction.");
             pw.println("  instrument [-r] [-e <NAME> <VALUE>] [-p <FILE>] [-w]");
             pw.println("          [--user <USER_ID> | current]");
             pw.println("          [--no-hidden-api-checks [--no-test-api-access]]");
diff --git a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
index 841b61e..3b386dd 100644
--- a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
+++ b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
@@ -1444,13 +1444,15 @@
 
     @Override
     public boolean isDelayBehindServices() {
-        // TODO: implement
+        // Modern queue does not alter the broadcasts delivery behavior based on background
+        // services, so ignore.
         return false;
     }
 
     @Override
     public void backgroundServicesFinishedLocked(int userId) {
-        // TODO: implement
+        // Modern queue does not alter the broadcasts delivery behavior based on background
+        // services, so ignore.
     }
 
     /**
diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java
index f4685f0..8675bfd 100644
--- a/services/core/java/com/android/server/am/CachedAppOptimizer.java
+++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java
@@ -66,8 +66,6 @@
     // Flags stored in the DeviceConfig API.
     @VisibleForTesting static final String KEY_USE_COMPACTION = "use_compaction";
     @VisibleForTesting static final String KEY_USE_FREEZER = "use_freezer";
-    @VisibleForTesting static final String KEY_COMPACT_ACTION_1 = "compact_action_1";
-    @VisibleForTesting static final String KEY_COMPACT_ACTION_2 = "compact_action_2";
     @VisibleForTesting static final String KEY_COMPACT_THROTTLE_1 = "compact_throttle_1";
     @VisibleForTesting static final String KEY_COMPACT_THROTTLE_2 = "compact_throttle_2";
     @VisibleForTesting static final String KEY_COMPACT_THROTTLE_3 = "compact_throttle_3";
@@ -99,15 +97,6 @@
     private static final int RSS_ANON_INDEX = 2;
     private static final int RSS_SWAP_INDEX = 3;
 
-    // Phenotype sends int configurations and we map them to the strings we'll use on device,
-    // preventing a weird string value entering the kernel.
-    private static final int COMPACT_ACTION_NONE = 0;
-    private static final int COMPACT_ACTION_FILE = 1;
-    private static final int COMPACT_ACTION_ANON = 2;
-    private static final int COMPACT_ACTION_ALL = 3;
-
-    private static final String COMPACT_ACTION_STRING[] = {"", "file", "anon", "all"};
-
     // Keeps these flags in sync with services/core/jni/com_android_server_am_CachedAppOptimizer.cpp
     private static final int COMPACT_ACTION_FILE_FLAG = 1;
     private static final int COMPACT_ACTION_ANON_FLAG = 2;
@@ -117,11 +106,11 @@
 
     private static final int FREEZE_BINDER_TIMEOUT_MS = 100;
 
+    @VisibleForTesting static final boolean ENABLE_FILE_COMPACT = false;
+
     // Defaults for phenotype flags.
     @VisibleForTesting static final Boolean DEFAULT_USE_COMPACTION = true;
     @VisibleForTesting static final Boolean DEFAULT_USE_FREEZER = true;
-    @VisibleForTesting static final int DEFAULT_COMPACT_ACTION_2 = COMPACT_ACTION_ALL;
-    @VisibleForTesting static final int DEFAULT_COMPACT_ACTION_1 = COMPACT_ACTION_FILE;
     @VisibleForTesting static final long DEFAULT_COMPACT_THROTTLE_1 = 5_000;
     @VisibleForTesting static final long DEFAULT_COMPACT_THROTTLE_2 = 10_000;
     @VisibleForTesting static final long DEFAULT_COMPACT_THROTTLE_3 = 500;
@@ -156,22 +145,15 @@
     @VisibleForTesting
     interface ProcessDependencies {
         long[] getRss(int pid);
-        void performCompaction(CompactAction action, int pid) throws IOException;
+        void performCompaction(CompactProfile action, int pid) throws IOException;
     }
 
     // This indicates the compaction we want to perform
     public enum CompactProfile {
-        SOME, // File compaction
-        FULL // File+anon compaction
-    }
-
-    // Low level actions that can be performed for compaction
-    // currently determined by the compaction profile
-    public enum CompactAction {
         NONE, // No compaction
-        FILE, // File+anon compaction
-        ANON,
-        ALL
+        SOME, // File compaction
+        ANON, // Anon compaction
+        FULL // File+anon compaction
     }
 
     // This indicates the process OOM memory state that initiated the compaction request
@@ -187,6 +169,7 @@
     static final int COMPACT_SYSTEM_MSG = 2;
     static final int SET_FROZEN_PROCESS_MSG = 3;
     static final int REPORT_UNFREEZE_MSG = 4;
+    static final int COMPACT_NATIVE_MSG = 5;
 
     // When free swap falls below this percentage threshold any full (file + anon)
     // compactions will be downgraded to file only compactions to reduce pressure
@@ -240,9 +223,6 @@
                         for (String name : properties.getKeyset()) {
                             if (KEY_USE_COMPACTION.equals(name)) {
                                 updateUseCompaction();
-                            } else if (KEY_COMPACT_ACTION_1.equals(name)
-                                    || KEY_COMPACT_ACTION_2.equals(name)) {
-                                updateCompactionActions();
                             } else if (KEY_COMPACT_THROTTLE_1.equals(name)
                                     || KEY_COMPACT_THROTTLE_2.equals(name)
                                     || KEY_COMPACT_THROTTLE_3.equals(name)
@@ -314,12 +294,6 @@
 
     // Configured by phenotype. Updates from the server take effect immediately.
     @GuardedBy("mPhenotypeFlagLock")
-    @VisibleForTesting
-    volatile CompactAction mCompactActionSome = compactActionIntToAction(DEFAULT_COMPACT_ACTION_1);
-    @GuardedBy("mPhenotypeFlagLock")
-    @VisibleForTesting
-    volatile CompactAction mCompactActionFull = compactActionIntToAction(DEFAULT_COMPACT_ACTION_2);
-    @GuardedBy("mPhenotypeFlagLock")
     @VisibleForTesting volatile long mCompactThrottleSomeSome = DEFAULT_COMPACT_THROTTLE_1;
     @GuardedBy("mPhenotypeFlagLock")
     @VisibleForTesting volatile long mCompactThrottleSomeFull = DEFAULT_COMPACT_THROTTLE_2;
@@ -542,7 +516,6 @@
                 CACHED_APP_FREEZER_ENABLED_URI, false, mSettingsObserver);
         synchronized (mPhenotypeFlagLock) {
             updateUseCompaction();
-            updateCompactionActions();
             updateCompactionThrottles();
             updateCompactStatsdSampleRate();
             updateFreezerStatsdSampleRate();
@@ -587,8 +560,6 @@
         pw.println("CachedAppOptimizer settings");
         synchronized (mPhenotypeFlagLock) {
             pw.println("  " + KEY_USE_COMPACTION + "=" + mUseCompaction);
-            pw.println("  " + KEY_COMPACT_ACTION_1 + "=" + mCompactActionSome);
-            pw.println("  " + KEY_COMPACT_ACTION_2 + "=" + mCompactActionFull);
             pw.println("  " + KEY_COMPACT_THROTTLE_1 + "=" + mCompactThrottleSomeSome);
             pw.println("  " + KEY_COMPACT_THROTTLE_2 + "=" + mCompactThrottleSomeFull);
             pw.println("  " + KEY_COMPACT_THROTTLE_3 + "=" + mCompactThrottleFullSome);
@@ -761,19 +732,9 @@
         return false;
     }
 
-    private CompactAction resolveCompactActionForProfile(CompactProfile profile) {
-        CompactAction action;
-        switch (profile) {
-            case SOME:
-                action = CompactAction.FILE;
-                break;
-            case FULL:
-                action = CompactAction.ALL;
-                break;
-            default:
-                action = CompactAction.NONE;
-        }
-        return action;
+    void compactNative(CompactProfile compactProfile, int pid) {
+        mCompactionHandler.sendMessage(mCompactionHandler.obtainMessage(
+                COMPACT_NATIVE_MSG, pid, compactProfile.ordinal()));
     }
 
     private AggregatedProcessCompactionStats getPerProcessAggregatedCompactStat(
@@ -1051,18 +1012,6 @@
     }
 
     @GuardedBy("mPhenotypeFlagLock")
-    private void updateCompactionActions() {
-        int compactAction1 = DeviceConfig.getInt(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
-                KEY_COMPACT_ACTION_1, DEFAULT_COMPACT_ACTION_1);
-
-        int compactAction2 = DeviceConfig.getInt(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
-                KEY_COMPACT_ACTION_2, DEFAULT_COMPACT_ACTION_2);
-
-        mCompactActionSome = compactActionIntToAction(compactAction1);
-        mCompactActionFull = compactActionIntToAction(compactAction2);
-    }
-
-    @GuardedBy("mPhenotypeFlagLock")
     private void updateCompactionThrottles() {
         boolean useThrottleDefaults = false;
         // TODO: improve efficiency by calling DeviceConfig only once for all flags.
@@ -1235,14 +1184,6 @@
         return true;
     }
 
-    static CompactAction compactActionIntToAction(int action) {
-        if (action < 0 || action >= CompactAction.values().length) {
-            return CompactAction.NONE;
-        }
-
-        return CompactAction.values()[action];
-    }
-
     // This will ensure app will be out of the freezer for at least mFreezerDebounceTimeout.
     @GuardedBy("mAm")
     void unfreezeTemporarily(ProcessRecord app, @OomAdjuster.OomAdjReason int reason) {
@@ -1475,8 +1416,10 @@
 
         if (oldAdj <= ProcessList.PERCEPTIBLE_APP_ADJ
                 && (newAdj == ProcessList.PREVIOUS_APP_ADJ || newAdj == ProcessList.HOME_APP_ADJ)) {
-            // Perform a minor compaction when a perceptible app becomes the prev/home app
-            compactApp(app, CompactProfile.SOME, CompactSource.APP, false);
+            if (ENABLE_FILE_COMPACT) {
+                // Perform a minor compaction when a perceptible app becomes the prev/home app
+                compactApp(app, CompactProfile.SOME, CompactSource.APP, false);
+            }
         } else if (oldAdj < ProcessList.CACHED_APP_MIN_ADJ
                 && newAdj >= ProcessList.CACHED_APP_MIN_ADJ
                 && newAdj <= ProcessList.CACHED_APP_MAX_ADJ) {
@@ -1486,23 +1429,37 @@
     }
 
     /**
-     * Applies a compaction downgrade when swap is low.
+     * Computes the final compaction profile to be used which depends on compaction
+     * features enabled and swap usage.
      */
-    CompactProfile downgradeCompactionIfRequired(CompactProfile profile) {
-        // Downgrade compaction under swap memory pressure
+    CompactProfile resolveCompactionProfile(CompactProfile profile) {
         if (profile == CompactProfile.FULL) {
             double swapFreePercent = getFreeSwapPercent();
+            // Downgrade compaction under swap memory pressure
             if (swapFreePercent < COMPACT_DOWNGRADE_FREE_SWAP_THRESHOLD) {
                 profile = CompactProfile.SOME;
+
                 ++mTotalCompactionDowngrades;
                 if (DEBUG_COMPACTION) {
                     Slog.d(TAG_AM,
-                            "Downgraded compaction to file only due to low swap."
+                            "Downgraded compaction to "+ profile +" due to low swap."
                                     + " Swap Free% " + swapFreePercent);
                 }
             }
         }
 
+        if (!ENABLE_FILE_COMPACT) {
+            if (profile == CompactProfile.SOME) {
+                profile = CompactProfile.NONE;
+            } else if (profile == CompactProfile.FULL) {
+                profile = CompactProfile.ANON;
+            }
+            if (DEBUG_COMPACTION) {
+                Slog.d(TAG_AM,
+                        "Final compaction profile "+ profile +" due to file compact disabled");
+            }
+        }
+
         return profile;
     }
 
@@ -1733,7 +1690,6 @@
                     ProcessRecord proc;
                     final ProcessCachedOptimizerRecord opt;
                     int pid;
-                    CompactAction resolvedAction;
                     final String name;
                     CompactProfile lastCompactProfile;
                     long lastCompactTime;
@@ -1811,17 +1767,24 @@
                     }
 
                     CompactProfile resolvedProfile =
-                            downgradeCompactionIfRequired(requestedProfile);
-                    resolvedAction = resolveCompactActionForProfile(resolvedProfile);
+                            resolveCompactionProfile(requestedProfile);
+                    if (resolvedProfile == CompactProfile.NONE) {
+                        // No point on issuing compaction call as we don't want to compact.
+                        if (DEBUG_COMPACTION) {
+                            Slog.d(TAG_AM, "Resolved no compaction for "+ name +
+                                    " requested profile="+requestedProfile);
+                        }
+                        return;
+                    }
 
                     try {
                         Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
-                                "Compact " + resolvedAction.name() + ": " + name
+                                "Compact " + resolvedProfile.name() + ": " + name
                                         + " lastOomAdjReason: " + oomAdjReason
                                         + " source: " + compactSource.name());
                         long zramUsedKbBefore = getUsedZramMemory();
                         long startCpuTime = threadCpuTimeNs();
-                        mProcessDependencies.performCompaction(resolvedAction, pid);
+                        mProcessDependencies.performCompaction(resolvedProfile, pid);
                         long endCpuTime = threadCpuTimeNs();
                         long[] rssAfter = mProcessDependencies.getRss(pid);
                         long end = SystemClock.uptimeMillis();
@@ -1877,7 +1840,7 @@
                                 return;
                         }
                         EventLog.writeEvent(EventLogTags.AM_COMPACT, pid, name,
-                                resolvedAction.name(), rssBefore[RSS_TOTAL_INDEX],
+                                resolvedProfile.name(), rssBefore[RSS_TOTAL_INDEX],
                                 rssBefore[RSS_FILE_INDEX], rssBefore[RSS_ANON_INDEX],
                                 rssBefore[RSS_SWAP_INDEX], deltaTotalRss, deltaFileRss,
                                 deltaAnonRss, deltaSwapRss, time, lastCompactProfile.name(),
@@ -1907,6 +1870,21 @@
                     Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                     break;
                 }
+                case COMPACT_NATIVE_MSG: {
+                    int pid = msg.arg1;
+                    CompactProfile compactProfile = CompactProfile.values()[msg.arg2];
+                    Slog.d(TAG_AM,
+                            "Performing native compaction for pid=" + pid
+                                    + " type=" + compactProfile.name());
+                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "compactSystem");
+                    try {
+                        mProcessDependencies.performCompaction(compactProfile, pid);
+                    } catch (Exception e) {
+                        Slog.d(TAG_AM, "Failed compacting native pid= " + pid);
+                    }
+                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
+                    break;
+                }
             }
         }
     }
@@ -2170,14 +2148,14 @@
 
         // Compact process.
         @Override
-        public void performCompaction(CompactAction action, int pid) throws IOException {
+        public void performCompaction(CompactProfile profile, int pid) throws IOException {
             mPidCompacting = pid;
-            if (action == CompactAction.ALL) {
-                    compactProcess(pid, COMPACT_ACTION_FILE_FLAG | COMPACT_ACTION_ANON_FLAG);
-            } else if (action == CompactAction.FILE) {
-                    compactProcess(pid, COMPACT_ACTION_FILE_FLAG);
-            } else if (action == CompactAction.ANON) {
-                    compactProcess(pid, COMPACT_ACTION_ANON_FLAG);
+            if (profile == CompactProfile.FULL) {
+                compactProcess(pid, COMPACT_ACTION_FILE_FLAG | COMPACT_ACTION_ANON_FLAG);
+            } else if (profile == CompactProfile.SOME) {
+                compactProcess(pid, COMPACT_ACTION_FILE_FLAG);
+            } else if (profile == CompactProfile.ANON) {
+                compactProcess(pid, COMPACT_ACTION_ANON_FLAG);
             }
             mPidCompacting = -1;
         }
diff --git a/services/core/java/com/android/server/am/ContentProviderHelper.java b/services/core/java/com/android/server/am/ContentProviderHelper.java
index 48df1494..bb5f31a 100644
--- a/services/core/java/com/android/server/am/ContentProviderHelper.java
+++ b/services/core/java/com/android/server/am/ContentProviderHelper.java
@@ -250,7 +250,6 @@
                 if (r != null && cpr.canRunHere(r)) {
                     checkAssociationAndPermissionLocked(r, cpi, callingUid, userId, checkCrossUser,
                             cpr.name.flattenToShortString(), startTime);
-                    enforceContentProviderRestrictionsForSdkSandbox(cpi);
 
                     // This provider has been published or is in the process
                     // of being published...  but it is also allowed to run
@@ -445,7 +444,6 @@
                     // info and allow the caller to instantiate it.  Only do
                     // this if the provider is the same user as the caller's
                     // process, or can run as root (so can be in any process).
-                    enforceContentProviderRestrictionsForSdkSandbox(cpi);
                     return cpr.newHolder(null, true);
                 }
 
@@ -594,8 +592,6 @@
                 // Return a holder instance even if we are waiting for the publishing of the
                 // provider, client will check for the holder.provider to see if it needs to wait
                 // for it.
-                //todo(b/265965249) Need to perform cleanup before calling enforce method here
-                enforceContentProviderRestrictionsForSdkSandbox(cpi);
                 return cpr.newHolder(conn, false);
             }
         }
@@ -657,7 +653,6 @@
                     + " caller=" + callerName + "/" + Binder.getCallingUid());
             return null;
         }
-        enforceContentProviderRestrictionsForSdkSandbox(cpi);
         return cpr.newHolder(conn, false);
     }
 
@@ -1136,7 +1131,6 @@
             appName = r.toString();
         }
 
-        enforceContentProviderRestrictionsForSdkSandbox(cpi);
         return checkContentProviderPermission(cpi, callingPid, Binder.getCallingUid(),
                 userId, checkUser, appName);
     }
@@ -1511,11 +1505,17 @@
 
     /**
      * Check if {@link ProcessRecord} has a possible chance at accessing the
-     * given {@link ProviderInfo}. Final permission checking is always done
+     * given {@link ProviderInfo}. First permission checking is for enforcing
+     * ContentProvider Restrictions from SdkSandboxManager.
+     * Final permission checking is always done
      * in {@link ContentProvider}.
      */
     private String checkContentProviderPermission(ProviderInfo cpi, int callingPid, int callingUid,
             int userId, boolean checkUser, String appName) {
+        if (!canAccessContentProviderFromSdkSandbox(cpi, callingUid)) {
+            return "ContentProvider access not allowed from sdk sandbox UID. "
+                    + "ProviderInfo: " + cpi.toString();
+        }
         boolean checkedGrants = false;
         if (checkUser) {
             // Looking for cross-user grants before enforcing the typical cross-users permissions
@@ -1905,11 +1905,10 @@
         }
     }
 
-    // Binder.clearCallingIdentity() shouldn't be called before this method
-    // as Binder should have its original callingUid for the check
-    private void enforceContentProviderRestrictionsForSdkSandbox(ProviderInfo cpi) {
-        if (!Process.isSdkSandboxUid(Binder.getCallingUid())) {
-            return;
+    private boolean canAccessContentProviderFromSdkSandbox(ProviderInfo cpi,
+                                                                    int callingUid) {
+        if (!Process.isSdkSandboxUid(callingUid)) {
+            return true;
         }
         final SdkSandboxManagerLocal sdkSandboxManagerLocal =
                 LocalManagerRegistry.getManager(SdkSandboxManagerLocal.class);
@@ -1918,11 +1917,7 @@
                     + "when checking whether SDK sandbox uid may "
                     + "access the contentprovider.");
         }
-        if (!sdkSandboxManagerLocal
-                .canAccessContentProviderFromSdkSandbox(cpi)) {
-            throw new SecurityException(
-                    "SDK sandbox uid may not access contentprovider " + cpi.name);
-        }
+        return sdkSandboxManagerLocal.canAccessContentProviderFromSdkSandbox(cpi);
     }
 
     /**
diff --git a/services/core/java/com/android/server/am/DropboxRateLimiter.java b/services/core/java/com/android/server/am/DropboxRateLimiter.java
index 3792625..9ff2cd0 100644
--- a/services/core/java/com/android/server/am/DropboxRateLimiter.java
+++ b/services/core/java/com/android/server/am/DropboxRateLimiter.java
@@ -31,11 +31,17 @@
     // process/eventType) further entries will be rejected until RATE_LIMIT_BUFFER_DURATION has
     // elapsed, after which the current count for this breakdown will be reset.
     private static final long RATE_LIMIT_BUFFER_DURATION = 10 * DateUtils.MINUTE_IN_MILLIS;
-    // The time duration after which the rate limit buffer will be cleared.
-    private static final long RATE_LIMIT_BUFFER_EXPIRY = 3 * RATE_LIMIT_BUFFER_DURATION;
+    // Indicated how many buffer durations to wait before the rate limit buffer will be cleared.
+    // E.g. if set to 3 will wait 3xRATE_LIMIT_BUFFER_DURATION before clearing the buffer.
+    private static final long RATE_LIMIT_BUFFER_EXPIRY_FACTOR = 3;
     // The number of entries to keep per breakdown of process/eventType.
     private static final int RATE_LIMIT_ALLOWED_ENTRIES = 6;
 
+    // If a process is rate limited twice in a row we consider it crash-looping and rate limit it
+    // more aggressively.
+    private static final int STRICT_RATE_LIMIT_ALLOWED_ENTRIES = 1;
+    private static final long STRICT_RATE_LIMIT_BUFFER_DURATION = 60 * DateUtils.MINUTE_IN_MILLIS;
+
     @GuardedBy("mErrorClusterRecords")
     private final ArrayMap<String, ErrorRecord> mErrorClusterRecords = new ArrayMap<>();
     private final Clock mClock;
@@ -71,15 +77,27 @@
                 return new RateLimitResult(false, 0);
             }
 
-            if (now - errRecord.getStartTime() > RATE_LIMIT_BUFFER_DURATION) {
+            final long timeSinceFirstError = now - errRecord.getStartTime();
+            if (timeSinceFirstError > errRecord.getBufferDuration()) {
                 final int errCount = recentlyDroppedCount(errRecord);
                 errRecord.setStartTime(now);
                 errRecord.setCount(1);
+
+                // If this error happened exactly the next "rate limiting cycle" after the last
+                // error and the previous cycle was rate limiting then increment the successive
+                // rate limiting cycle counter. If a full "cycle" has passed since the last error
+                // then this is no longer a continuous occurrence and will be rate limited normally.
+                if (errCount > 0 && timeSinceFirstError < 2 * errRecord.getBufferDuration()) {
+                    errRecord.incrementSuccessiveRateLimitCycles();
+                } else {
+                    errRecord.setSuccessiveRateLimitCycles(0);
+                }
+
                 return new RateLimitResult(false, errCount);
             }
 
             errRecord.incrementCount();
-            if (errRecord.getCount() > RATE_LIMIT_ALLOWED_ENTRIES) {
+            if (errRecord.getCount() > errRecord.getAllowedEntries()) {
                 return new RateLimitResult(true, recentlyDroppedCount(errRecord));
             }
         }
@@ -91,16 +109,19 @@
      * dropped. Resets every RATE_LIMIT_BUFFER_DURATION if events are still actively created or
      * RATE_LIMIT_BUFFER_EXPIRY if not. */
     private int recentlyDroppedCount(ErrorRecord errRecord) {
-        if (errRecord == null || errRecord.getCount() < RATE_LIMIT_ALLOWED_ENTRIES) return 0;
-        return errRecord.getCount() - RATE_LIMIT_ALLOWED_ENTRIES;
+        if (errRecord == null || errRecord.getCount() < errRecord.getAllowedEntries()) return 0;
+        return errRecord.getCount() - errRecord.getAllowedEntries();
     }
 
 
-    private void maybeRemoveExpiredRecords(long now) {
-        if (now - mLastMapCleanUp <= RATE_LIMIT_BUFFER_EXPIRY) return;
+    private void maybeRemoveExpiredRecords(long currentTime) {
+        if (currentTime - mLastMapCleanUp
+                <= RATE_LIMIT_BUFFER_EXPIRY_FACTOR * RATE_LIMIT_BUFFER_DURATION) {
+            return;
+        }
 
         for (int i = mErrorClusterRecords.size() - 1; i >= 0; i--) {
-            if (now - mErrorClusterRecords.valueAt(i).getStartTime() > RATE_LIMIT_BUFFER_EXPIRY) {
+            if (mErrorClusterRecords.valueAt(i).hasExpired(currentTime)) {
                 Counter.logIncrement(
                         "stability_errors.value_dropbox_buffer_expired_count",
                         mErrorClusterRecords.valueAt(i).getCount());
@@ -108,7 +129,7 @@
             }
         }
 
-        mLastMapCleanUp = now;
+        mLastMapCleanUp = currentTime;
     }
 
     /** Resets the rate limiter memory. */
@@ -153,10 +174,12 @@
     private class ErrorRecord {
         long mStartTime;
         int mCount;
+        int mSuccessiveRateLimitCycles;
 
         ErrorRecord(long startTime, int count) {
             mStartTime = startTime;
             mCount = count;
+            mSuccessiveRateLimitCycles = 0;
         }
 
         public void setStartTime(long startTime) {
@@ -171,6 +194,14 @@
             mCount++;
         }
 
+        public void setSuccessiveRateLimitCycles(int successiveRateLimitCycles) {
+            mSuccessiveRateLimitCycles = successiveRateLimitCycles;
+        }
+
+        public void incrementSuccessiveRateLimitCycles() {
+            mSuccessiveRateLimitCycles++;
+        }
+
         public long getStartTime() {
             return mStartTime;
         }
@@ -178,6 +209,27 @@
         public int getCount() {
             return mCount;
         }
+
+        public int getSuccessiveRateLimitCycles() {
+            return mSuccessiveRateLimitCycles;
+        }
+
+        public boolean isRepeated() {
+            return mSuccessiveRateLimitCycles >= 2;
+        }
+
+        public int getAllowedEntries() {
+            return isRepeated() ? STRICT_RATE_LIMIT_ALLOWED_ENTRIES : RATE_LIMIT_ALLOWED_ENTRIES;
+        }
+
+        public long getBufferDuration() {
+            return isRepeated() ? STRICT_RATE_LIMIT_BUFFER_DURATION : RATE_LIMIT_BUFFER_DURATION;
+        }
+
+        public boolean hasExpired(long currentTime) {
+            long bufferExpiry = RATE_LIMIT_BUFFER_EXPIRY_FACTOR * getBufferDuration();
+            return currentTime - mStartTime > bufferExpiry;
+        }
     }
 
     private static class DefaultClock implements Clock {
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 0d0e576..1f24eb3 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -3928,8 +3928,10 @@
     }
 
     @Override
-    @android.annotation.EnforcePermission(anyOf =
-            {"MODIFY_AUDIO_ROUTING", "MODIFY_AUDIO_SETTINGS_PRIVILEGED"})
+    @android.annotation.EnforcePermission(anyOf = {
+            android.Manifest.permission.MODIFY_AUDIO_ROUTING,
+            android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED
+    })
     /** @see AudioDeviceVolumeManager#setDeviceVolume(VolumeInfo, AudioDeviceAttributes)
      * Part of service interface, check permissions and parameters here
      * Note calling package is for logging purposes only, not to be trusted
@@ -4945,8 +4947,10 @@
     }
 
     @Override
-    @android.annotation.EnforcePermission(anyOf =
-            {"MODIFY_AUDIO_ROUTING", "MODIFY_AUDIO_SETTINGS_PRIVILEGED"})
+    @android.annotation.EnforcePermission(anyOf = {
+            android.Manifest.permission.MODIFY_AUDIO_ROUTING,
+            android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED
+    })
     /**
      * @see AudioDeviceVolumeManager#getDeviceVolume(VolumeInfo, AudioDeviceAttributes)
      */
@@ -7214,8 +7218,10 @@
      * @param device the audio device to be affected
      * @param deviceVolumeBehavior one of the device behaviors
      */
-    @android.annotation.EnforcePermission(anyOf =
-            {"MODIFY_AUDIO_ROUTING", "MODIFY_AUDIO_SETTINGS_PRIVILEGED"})
+    @android.annotation.EnforcePermission(anyOf = {
+            android.Manifest.permission.MODIFY_AUDIO_ROUTING,
+            android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED
+    })
     public void setDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device,
             @AudioManager.DeviceVolumeBehavior int deviceVolumeBehavior, @Nullable String pkgName) {
         // verify permissions
@@ -7295,8 +7301,11 @@
      * @param device the audio output device type
      * @return the volume behavior for the device
      */
-    @android.annotation.EnforcePermission(anyOf =
-            {"MODIFY_AUDIO_ROUTING", "QUERY_AUDIO_STATE", "MODIFY_AUDIO_SETTINGS_PRIVILEGED"})
+    @android.annotation.EnforcePermission(anyOf = {
+            android.Manifest.permission.MODIFY_AUDIO_ROUTING,
+            android.Manifest.permission.QUERY_AUDIO_STATE,
+            android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED
+    })
     public @AudioManager.DeviceVolumeBehavior
     int getDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device) {
         // verify permissions
diff --git a/services/core/java/com/android/server/cpu/CpuInfoReader.java b/services/core/java/com/android/server/cpu/CpuInfoReader.java
index ca97a98..ce68edbb 100644
--- a/services/core/java/com/android/server/cpu/CpuInfoReader.java
+++ b/services/core/java/com/android/server/cpu/CpuInfoReader.java
@@ -21,8 +21,10 @@
 
 import android.annotation.IntDef;
 import android.annotation.Nullable;
+import android.os.SystemClock;
 import android.system.Os;
 import android.system.OsConstants;
+import android.util.IndentingPrintWriter;
 import android.util.IntArray;
 import android.util.LongSparseLongArray;
 import android.util.SparseArray;
@@ -50,6 +52,9 @@
     private static final String POLICY_DIR_PREFIX = "policy";
     private static final String RELATED_CPUS_FILE = "related_cpus";
     private static final String AFFECTED_CPUS_FILE = "affected_cpus";
+    // TODO(b/263154344): Avoid reading from cpuinfo_cur_freq because non-root users don't have
+    //  read permission for this file. The file permissions are set by the Kernel. Instead, read
+    //  the current frequency only from scaling_cur_freq.
     private static final String CUR_CPUFREQ_FILE = "cpuinfo_cur_freq";
     private static final String MAX_CPUFREQ_FILE = "cpuinfo_max_freq";
     private static final String CUR_SCALING_FREQ_FILE = "scaling_cur_freq";
@@ -70,16 +75,18 @@
     private static final Pattern TIME_IN_STATE_PATTERN =
             Pattern.compile("(?<freqKHz>[0-9]+)\\s(?<time>[0-9]+)");
     private static final long MILLIS_PER_CLOCK_TICK = 1000L / Os.sysconf(OsConstants._SC_CLK_TCK);
+    private static final long MIN_READ_INTERVAL_MILLISECONDS = 500;
 
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(prefix = {"FLAG_CPUSET_CATEGORY_"}, flag = true, value = {
             FLAG_CPUSET_CATEGORY_TOP_APP,
             FLAG_CPUSET_CATEGORY_BACKGROUND
     })
-    private @interface CpusetCategory{}
+    /** package **/ @interface CpusetCategory{}
 
     // TODO(b/242722241): Protect updatable variables with a local lock.
     private final File mCpusetDir;
+    private final long mMinReadIntervalMillis;
     private final SparseIntArray mCpusetCategoriesByCpus = new SparseIntArray();
     private final SparseArray<File> mCpuFreqPolicyDirsById = new SparseArray<>();
     private final SparseArray<StaticPolicyInfo> mStaticPolicyInfoById = new SparseArray<>();
@@ -90,16 +97,20 @@
     private SparseArray<CpuUsageStats> mCumulativeCpuUsageStats = new SparseArray<>();
     private boolean mIsEnabled;
     private boolean mHasTimeInStateFile;
+    private long mLastReadUptimeMillis;
+    private SparseArray<CpuInfo> mLastReadCpuInfos;
 
     public CpuInfoReader() {
-        this(new File(CPUSET_DIR_PATH), new File(CPUFREQ_DIR_PATH), new File(PROC_STAT_FILE_PATH));
+        this(new File(CPUSET_DIR_PATH), new File(CPUFREQ_DIR_PATH), new File(PROC_STAT_FILE_PATH),
+                MIN_READ_INTERVAL_MILLISECONDS);
     }
 
     @VisibleForTesting
-    CpuInfoReader(File cpusetDir, File cpuFreqDir, File procStatFile) {
+    CpuInfoReader(File cpusetDir, File cpuFreqDir, File procStatFile, long minReadIntervalMillis) {
         mCpusetDir = cpusetDir;
         mCpuFreqDir = cpuFreqDir;
         mProcStatFile = procStatFile;
+        mMinReadIntervalMillis = minReadIntervalMillis;
     }
 
     /**
@@ -167,6 +178,16 @@
         if (!mIsEnabled) {
             return null;
         }
+        long uptimeMillis = SystemClock.uptimeMillis();
+        if (mLastReadUptimeMillis > 0
+                && uptimeMillis - mLastReadUptimeMillis < mMinReadIntervalMillis) {
+            Slogf.w(TAG, "Skipping reading from device and returning the last read CpuInfos. "
+                    + "Last read was %d ms ago, min read interval is %d ms",
+                    uptimeMillis - mLastReadUptimeMillis, mMinReadIntervalMillis);
+            return mLastReadCpuInfos;
+        }
+        mLastReadUptimeMillis = uptimeMillis;
+        mLastReadCpuInfos = null;
         SparseArray<CpuUsageStats> cpuUsageStatsByCpus = readLatestCpuUsageStats();
         if (cpuUsageStatsByCpus == null || cpuUsageStatsByCpus.size() == 0) {
             Slogf.e(TAG, "Failed to read latest CPU usage stats");
@@ -202,6 +223,12 @@
                         + " policy ID %d", policyId);
                 continue;
             }
+            if (curFreqKHz > maxFreqKHz) {
+                Slogf.w(TAG, "Current CPU frequency (%d) is greater than maximum CPU frequency"
+                        + " (%d) for policy ID (%d). Skipping CPU frequency policy", curFreqKHz,
+                        maxFreqKHz, policyId);
+                continue;
+            }
             for (int coreIdx = 0; coreIdx < staticPolicyInfo.relatedCpuCores.size(); coreIdx++) {
                 int relatedCpuCore = staticPolicyInfo.relatedCpuCores.get(coreIdx);
                 CpuInfo prevCpuInfo = cpuInfoByCpus.get(relatedCpuCore);
@@ -241,9 +268,73 @@
                 }
             }
         }
+        mLastReadCpuInfos = cpuInfoByCpus;
         return cpuInfoByCpus;
     }
 
+    /** Dumps the current state. */
+    public void dump(IndentingPrintWriter writer) {
+        writer.printf("*%s*\n", getClass().getSimpleName());
+        writer.increaseIndent();    // Add intend for the outermost block.
+
+        writer.printf("mCpusetDir = %s\n", mCpusetDir.getAbsolutePath());
+        writer.printf("mCpuFreqDir = %s\n", mCpuFreqDir.getAbsolutePath());
+        writer.printf("mProcStatFile = %s\n", mProcStatFile.getAbsolutePath());
+        writer.printf("mIsEnabled = %s\n", mIsEnabled);
+        writer.printf("mHasTimeInStateFile = %s\n", mHasTimeInStateFile);
+        writer.printf("mLastReadUptimeMillis = %d\n", mLastReadUptimeMillis);
+        writer.printf("mMinReadIntervalMillis = %d\n", mMinReadIntervalMillis);
+
+        writer.printf("Cpuset categories by CPU core:\n");
+        writer.increaseIndent();
+        for (int i = 0; i < mCpusetCategoriesByCpus.size(); i++) {
+            writer.printf("CPU core id = %d, %s\n", mCpusetCategoriesByCpus.keyAt(i),
+                    toCpusetCategoriesStr(mCpusetCategoriesByCpus.valueAt(i)));
+        }
+        writer.decreaseIndent();
+
+        writer.println("Cpu frequency policy directories by policy id:");
+        writer.increaseIndent();
+        for (int i = 0; i < mCpuFreqPolicyDirsById.size(); i++) {
+            writer.printf("Policy id = %d, Dir = %s\n", mCpuFreqPolicyDirsById.keyAt(i),
+                    mCpuFreqPolicyDirsById.valueAt(i));
+        }
+        writer.decreaseIndent();
+
+        writer.println("Static cpu frequency policy infos by policy id:");
+        writer.increaseIndent();
+        for (int i = 0; i < mStaticPolicyInfoById.size(); i++) {
+            writer.printf("Policy id = %d, %s\n", mStaticPolicyInfoById.keyAt(i),
+                    mStaticPolicyInfoById.valueAt(i));
+        }
+        writer.decreaseIndent();
+
+        writer.println("Cpu time in frequency state by policy id:");
+        writer.increaseIndent();
+        for (int i = 0; i < mTimeInStateByPolicyId.size(); i++) {
+            writer.printf("Policy id = %d, Time(millis) in state by CPU frequency(KHz) = %s\n",
+                    mTimeInStateByPolicyId.keyAt(i), mTimeInStateByPolicyId.valueAt(i));
+        }
+        writer.decreaseIndent();
+
+        writer.println("Last read CPU infos:");
+        writer.increaseIndent();
+        for (int i = 0; i < mLastReadCpuInfos.size(); i++) {
+            writer.printf("%s\n", mLastReadCpuInfos.valueAt(i));
+        }
+        writer.decreaseIndent();
+
+        writer.println("Latest cumulative CPU usage stats by CPU core:");
+        writer.increaseIndent();
+        for (int i = 0; i < mCumulativeCpuUsageStats.size(); i++) {
+            writer.printf("CPU core id = %d, %s\n", mCumulativeCpuUsageStats.keyAt(i),
+                    mCumulativeCpuUsageStats.valueAt(i));
+        }
+        writer.decreaseIndent();
+
+        writer.decreaseIndent();    // Remove intend for the outermost block.
+    }
+
     /**
      * Sets the CPU frequency for testing.
      *
@@ -496,6 +587,9 @@
         for (int i = 0; i < timeInState.size(); i++) {
             totalTimeInState += timeInState.valueAt(i);
         }
+        if (totalTimeInState == 0) {
+            return CpuInfo.MISSING_FREQUENCY;
+        }
         double avgFreqKHz = 0;
         for (int i = 0; i < timeInState.size(); i++) {
             avgFreqKHz += (timeInState.keyAt(i) * timeInState.valueAt(i)) / totalTimeInState;
@@ -624,16 +718,29 @@
         @CpusetCategory
         public final int cpusetCategories;
         public final boolean isOnline;
+        public final long maxCpuFreqKHz;
         // Values in the below fields may be missing when a CPU core is offline.
         public final long curCpuFreqKHz;
-        public final long maxCpuFreqKHz;
         public final long avgTimeInStateCpuFreqKHz;
         @Nullable
         public final CpuUsageStats latestCpuUsageStats;
 
+        private long mNormalizedAvailableCpuFreqKHz;
+
         CpuInfo(int cpuCore, @CpusetCategory int cpusetCategories, boolean isOnline,
                 long curCpuFreqKHz, long maxCpuFreqKHz, long avgTimeInStateCpuFreqKHz,
                 CpuUsageStats latestCpuUsageStats) {
+            this(cpuCore, cpusetCategories, isOnline, curCpuFreqKHz, maxCpuFreqKHz,
+                    avgTimeInStateCpuFreqKHz, /* normalizedAvailableCpuFreqKHz= */ 0,
+                    latestCpuUsageStats);
+            this.mNormalizedAvailableCpuFreqKHz = computeNormalizedAvailableCpuFreqKHz();
+        }
+
+        // Should be used only for testing.
+        @VisibleForTesting
+        CpuInfo(int cpuCore, @CpusetCategory int cpusetCategories, boolean isOnline,
+                long curCpuFreqKHz, long maxCpuFreqKHz, long avgTimeInStateCpuFreqKHz,
+                long normalizedAvailableCpuFreqKHz, CpuUsageStats latestCpuUsageStats) {
             this.cpuCore = cpuCore;
             this.cpusetCategories = cpusetCategories;
             this.isOnline = isOnline;
@@ -641,6 +748,11 @@
             this.maxCpuFreqKHz = maxCpuFreqKHz;
             this.avgTimeInStateCpuFreqKHz = avgTimeInStateCpuFreqKHz;
             this.latestCpuUsageStats = latestCpuUsageStats;
+            this.mNormalizedAvailableCpuFreqKHz = normalizedAvailableCpuFreqKHz;
+        }
+
+        public long getNormalizedAvailableCpuFreqKHz() {
+            return mNormalizedAvailableCpuFreqKHz;
         }
 
         @Override
@@ -657,6 +769,8 @@
                     .append(avgTimeInStateCpuFreqKHz == MISSING_FREQUENCY ? "missing"
                             : avgTimeInStateCpuFreqKHz)
                     .append(", latestCpuUsageStats = ").append(latestCpuUsageStats)
+                    .append(", mNormalizedAvailableCpuFreqKHz = ")
+                    .append(mNormalizedAvailableCpuFreqKHz)
                     .append(" }").toString();
         }
 
@@ -673,13 +787,32 @@
                     && isOnline == other.isOnline  && curCpuFreqKHz == other.curCpuFreqKHz
                     && maxCpuFreqKHz == other.maxCpuFreqKHz
                     && avgTimeInStateCpuFreqKHz == other.avgTimeInStateCpuFreqKHz
-                    && latestCpuUsageStats.equals(other.latestCpuUsageStats);
+                    && latestCpuUsageStats.equals(other.latestCpuUsageStats)
+                    && mNormalizedAvailableCpuFreqKHz == other.mNormalizedAvailableCpuFreqKHz;
         }
 
         @Override
         public int hashCode() {
             return Objects.hash(cpuCore, cpusetCategories, isOnline, curCpuFreqKHz, maxCpuFreqKHz,
-                    avgTimeInStateCpuFreqKHz, latestCpuUsageStats);
+                    avgTimeInStateCpuFreqKHz, latestCpuUsageStats, mNormalizedAvailableCpuFreqKHz);
+        }
+
+        private long computeNormalizedAvailableCpuFreqKHz() {
+            if (!isOnline) {
+                return MISSING_FREQUENCY;
+            }
+            long totalTimeMillis = latestCpuUsageStats.getTotalTimeMillis();
+            if (totalTimeMillis == 0) {
+                Slogf.wtf(TAG, "Total CPU time millis is 0. This shouldn't happen unless stats are"
+                        + " polled too frequently");
+                return MISSING_FREQUENCY;
+            }
+            double nonIdlePercent = 100.0 * (totalTimeMillis
+                    - (double) latestCpuUsageStats.idleTimeMillis) / totalTimeMillis;
+            long curFreqKHz = avgTimeInStateCpuFreqKHz == MISSING_FREQUENCY
+                    ? curCpuFreqKHz : avgTimeInStateCpuFreqKHz;
+            double availablePercent = 100.0 - (nonIdlePercent * curFreqKHz / maxCpuFreqKHz);
+            return (long) ((availablePercent * maxCpuFreqKHz) / 100.0);
         }
     }
 
@@ -712,7 +845,7 @@
             this.guestNiceTimeMillis = guestNiceTimeMillis;
         }
 
-        public long getTotalTime() {
+        public long getTotalTimeMillis() {
             return userTimeMillis + niceTimeMillis + systemTimeMillis + idleTimeMillis
                     + iowaitTimeMillis + irqTimeMillis + softirqTimeMillis + stealTimeMillis
                     + guestTimeMillis + guestNiceTimeMillis;
@@ -796,8 +929,8 @@
 
         @Override
         public String toString() {
-            return "FrequencyPair{cpuFreqKHz=" + cpuFreqKHz + ", scalingFreqKHz=" + scalingFreqKHz
-                    + '}';
+            return "FrequencyPair{cpuFreqKHz = " + cpuFreqKHz + ", scalingFreqKHz = "
+                    + scalingFreqKHz + '}';
         }
     }
 
@@ -812,7 +945,7 @@
 
         @Override
         public String toString() {
-            return "StaticPolicyInfo{maxCpuFreqPair=" + maxCpuFreqPair + ", relatedCpuCores="
+            return "StaticPolicyInfo{maxCpuFreqPair = " + maxCpuFreqPair + ", relatedCpuCores = "
                     + relatedCpuCores + '}';
         }
     }
@@ -831,9 +964,9 @@
 
         @Override
         public String toString() {
-            return "DynamicPolicyInfo{curCpuFreqPair=" + curCpuFreqPair
-                    + ", avgTimeInStateCpuFreqKHz=" + avgTimeInStateCpuFreqKHz
-                    + ", affectedCpuCores=" + affectedCpuCores + '}';
+            return "DynamicPolicyInfo{curCpuFreqPair = " + curCpuFreqPair
+                    + ", avgTimeInStateCpuFreqKHz = " + avgTimeInStateCpuFreqKHz
+                    + ", affectedCpuCores = " + affectedCpuCores + '}';
         }
     }
 }
diff --git a/services/core/java/com/android/server/location/LocationManagerService.java b/services/core/java/com/android/server/location/LocationManagerService.java
index 1cc958b..fa2ba21 100644
--- a/services/core/java/com/android/server/location/LocationManagerService.java
+++ b/services/core/java/com/android/server/location/LocationManagerService.java
@@ -296,6 +296,8 @@
                 refreshAppOpsRestrictions(userId);
             }
         });
+        mInjector.getEmergencyHelper().addOnEmergencyStateChangedListener(
+                this::onEmergencyStateChanged);
 
         // set up passive provider first since it will be required for all other location providers,
         // which are loaded later once the system is ready.
@@ -567,6 +569,11 @@
         refreshAppOpsRestrictions(userId);
     }
 
+    private void onEmergencyStateChanged() {
+        boolean isInEmergency = mInjector.getEmergencyHelper().isInEmergency(Long.MIN_VALUE);
+        mInjector.getLocationUsageLogger().logEmergencyStateChanged(isInEmergency);
+    }
+
     private void logLocationEnabledState() {
         boolean locationEnabled = false;
         // Location setting is considered on if it is enabled for any one user
diff --git a/services/core/java/com/android/server/location/gnss/GnssConfiguration.java b/services/core/java/com/android/server/location/gnss/GnssConfiguration.java
index 77cd673..a081dff 100644
--- a/services/core/java/com/android/server/location/gnss/GnssConfiguration.java
+++ b/services/core/java/com/android/server/location/gnss/GnssConfiguration.java
@@ -92,6 +92,8 @@
     // Represents an HAL interface version. Instances of this class are created in the JNI layer
     // and returned through native methods.
     static class HalInterfaceVersion {
+        // mMajor being this value denotes AIDL HAL. In this case, mMinor denotes the AIDL version.
+        static final int AIDL_INTERFACE = 3;
         final int mMajor;
         final int mMinor;
 
diff --git a/services/core/java/com/android/server/location/gnss/GnssMeasurementsProvider.java b/services/core/java/com/android/server/location/gnss/GnssMeasurementsProvider.java
index 6c4c829..041f11d 100644
--- a/services/core/java/com/android/server/location/gnss/GnssMeasurementsProvider.java
+++ b/services/core/java/com/android/server/location/gnss/GnssMeasurementsProvider.java
@@ -21,6 +21,7 @@
 import static com.android.server.location.gnss.GnssManagerService.D;
 import static com.android.server.location.gnss.GnssManagerService.TAG;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.AppOpsManager;
 import android.location.GnssMeasurementRequest;
@@ -31,6 +32,7 @@
 import android.stats.location.LocationStatsEnums;
 import android.util.Log;
 
+import com.android.server.location.gnss.GnssConfiguration.HalInterfaceVersion;
 import com.android.server.location.gnss.hal.GnssNative;
 import com.android.server.location.injector.AppOpsHelper;
 import com.android.server.location.injector.Injector;
@@ -115,16 +117,6 @@
         if (request.getIntervalMillis() == GnssMeasurementRequest.PASSIVE_INTERVAL) {
             return true;
         }
-        // The HAL doc does not specify if consecutive start() calls will be allowed.
-        // Some vendors may ignore the 2nd start() call if stop() is not called.
-        // Thus, here we always call stop() before calling start() to avoid being ignored.
-        if (mGnssNative.stopMeasurementCollection()) {
-            if (D) {
-                Log.d(TAG, "stopping gnss measurements");
-            }
-        } else {
-            Log.e(TAG, "error stopping gnss measurements");
-        }
         if (mGnssNative.startMeasurementCollection(request.isFullTracking(),
                 request.isCorrelationVectorOutputsEnabled(),
                 request.getIntervalMillis())) {
@@ -139,6 +131,28 @@
     }
 
     @Override
+    protected boolean reregisterWithService(GnssMeasurementRequest old,
+            GnssMeasurementRequest request,
+            @NonNull Collection<GnssListenerRegistration> registrations) {
+        if (request.getIntervalMillis() == GnssMeasurementRequest.PASSIVE_INTERVAL) {
+            unregisterWithService();
+            return true;
+        }
+        HalInterfaceVersion halInterfaceVersion =
+                mGnssNative.getConfiguration().getHalInterfaceVersion();
+        boolean aidlV3Plus = halInterfaceVersion.mMajor == HalInterfaceVersion.AIDL_INTERFACE
+                && halInterfaceVersion.mMinor >= 3;
+        if (!aidlV3Plus) {
+            // The HAL doc does not specify if consecutive start() calls will be allowed.
+            // Some vendors may ignore the 2nd start() call if stop() is not called.
+            // Thus, here we always call stop() before calling start() to avoid being ignored.
+            // AIDL v3+ is free from this issue.
+            unregisterWithService();
+        }
+        return registerWithService(request, registrations);
+    }
+
+    @Override
     protected void unregisterWithService() {
         if (mGnssNative.stopMeasurementCollection()) {
             if (D) {
diff --git a/services/core/java/com/android/server/location/gnss/NetworkTimeHelper.java b/services/core/java/com/android/server/location/gnss/NetworkTimeHelper.java
index f5114b7..01c108b 100644
--- a/services/core/java/com/android/server/location/gnss/NetworkTimeHelper.java
+++ b/services/core/java/com/android/server/location/gnss/NetworkTimeHelper.java
@@ -37,7 +37,7 @@
      * a platform bug. This switch will be removed in a future release. If there are problems with
      * the new impl we'd like to hear about them.
      */
-    static final boolean USE_TIME_DETECTOR_IMPL = false;
+    static final boolean USE_TIME_DETECTOR_IMPL = true;
 
     /**
      * The callback interface used by {@link NetworkTimeHelper} to report the time to {@link
diff --git a/services/core/java/com/android/server/location/injector/EmergencyHelper.java b/services/core/java/com/android/server/location/injector/EmergencyHelper.java
index be4bf50..10cf714 100644
--- a/services/core/java/com/android/server/location/injector/EmergencyHelper.java
+++ b/services/core/java/com/android/server/location/injector/EmergencyHelper.java
@@ -16,14 +16,55 @@
 
 package com.android.server.location.injector;
 
+import java.util.concurrent.CopyOnWriteArrayList;
+
 /**
  * Provides helpers for emergency sessions.
  */
 public abstract class EmergencyHelper {
 
+    private final CopyOnWriteArrayList<EmergencyStateChangedListener> mListeners;
+
+    protected EmergencyHelper() {
+        mListeners = new CopyOnWriteArrayList<>();
+    }
+
+    /**
+     * Listener for emergency state changes.
+     */
+    public interface EmergencyStateChangedListener {
+        /**
+         * Called when state changes.
+         */
+        void onStateChanged();
+    }
+
     /**
      * Returns true if the device is in an emergency session, or if an emergency session ended
      * within the given extension time.
      */
     public abstract boolean isInEmergency(long extensionTimeMs);
+
+    /**
+     * Add a listener for changes to the emergency location state.
+     */
+    public void addOnEmergencyStateChangedListener(EmergencyStateChangedListener listener) {
+        mListeners.add(listener);
+    }
+
+    /**
+     * Remove a listener for changes to the emergency location state.
+     */
+    public void removeOnEmergencyStateChangedListener(EmergencyStateChangedListener listener) {
+        mListeners.remove(listener);
+    }
+
+    /**
+     * Notify listeners for emergency state of state change
+     */
+    protected final void dispatchEmergencyStateChanged() {
+        for (EmergencyStateChangedListener listener : mListeners) {
+            listener.onStateChanged();
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/location/injector/Injector.java b/services/core/java/com/android/server/location/injector/Injector.java
index b2c8672..4a0c4b2 100644
--- a/services/core/java/com/android/server/location/injector/Injector.java
+++ b/services/core/java/com/android/server/location/injector/Injector.java
@@ -16,13 +16,11 @@
 
 package com.android.server.location.injector;
 
-import com.android.internal.annotations.VisibleForTesting;
 import com.android.server.location.settings.LocationSettings;
 
 /**
  * Injects various location dependencies so that they may be controlled by tests.
  */
-@VisibleForTesting
 public interface Injector {
 
     /** Returns a UserInfoHelper. */
diff --git a/services/core/java/com/android/server/location/injector/LocationUsageLogger.java b/services/core/java/com/android/server/location/injector/LocationUsageLogger.java
index a9701b3..9319e89 100644
--- a/services/core/java/com/android/server/location/injector/LocationUsageLogger.java
+++ b/services/core/java/com/android/server/location/injector/LocationUsageLogger.java
@@ -129,6 +129,13 @@
         FrameworkStatsLog.write(FrameworkStatsLog.LOCATION_ENABLED_STATE_CHANGED, enabled);
     }
 
+    /**
+     * Log emergency location state change event
+     */
+    public synchronized void logEmergencyStateChanged(boolean isInEmergency) {
+        FrameworkStatsLog.write(FrameworkStatsLog.EMERGENCY_STATE_CHANGED, isInEmergency);
+    }
+
     private static int bucketizeProvider(String provider) {
         if (LocationManager.NETWORK_PROVIDER.equals(provider)) {
             return LocationStatsEnums.PROVIDER_NETWORK;
diff --git a/services/core/java/com/android/server/location/injector/SystemEmergencyHelper.java b/services/core/java/com/android/server/location/injector/SystemEmergencyHelper.java
index 1fb00ef..c772e08 100644
--- a/services/core/java/com/android/server/location/injector/SystemEmergencyHelper.java
+++ b/services/core/java/com/android/server/location/injector/SystemEmergencyHelper.java
@@ -27,6 +27,7 @@
 import android.telephony.TelephonyManager;
 import android.util.Log;
 
+import com.android.internal.telephony.TelephonyIntents;
 import com.android.server.FgThread;
 
 import java.util.Objects;
@@ -73,12 +74,25 @@
                     try {
                         mIsInEmergencyCall = mTelephonyManager.isEmergencyNumber(
                                 intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER));
+                        dispatchEmergencyStateChanged();
                     } catch (IllegalStateException e) {
                         Log.w(TAG, "Failed to call TelephonyManager.isEmergencyNumber().", e);
                     }
                 }
             }
         }, new IntentFilter(Intent.ACTION_NEW_OUTGOING_CALL));
+
+        mContext.registerReceiver(new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                if (!TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED.equals(
+                        intent.getAction())) {
+                    return;
+                }
+
+                dispatchEmergencyStateChanged();
+            }
+        }, new IntentFilter(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED));
     }
 
     @Override
@@ -108,6 +122,7 @@
                     if (mIsInEmergencyCall) {
                         mEmergencyCallEndRealtimeMs = SystemClock.elapsedRealtime();
                         mIsInEmergencyCall = false;
+                        dispatchEmergencyStateChanged();
                     }
                 }
             }
diff --git a/services/core/java/com/android/server/location/provider/LocationProviderManager.java b/services/core/java/com/android/server/location/provider/LocationProviderManager.java
index 925ab65..7aaf915 100644
--- a/services/core/java/com/android/server/location/provider/LocationProviderManager.java
+++ b/services/core/java/com/android/server/location/provider/LocationProviderManager.java
@@ -64,6 +64,7 @@
 import android.location.LocationManagerInternal.ProviderEnabledListener;
 import android.location.LocationRequest;
 import android.location.LocationResult;
+import android.location.altitude.AltitudeConverter;
 import android.location.provider.IProviderRequestListener;
 import android.location.provider.ProviderProperties;
 import android.location.provider.ProviderRequest;
@@ -81,6 +82,7 @@
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.os.WorkSource;
+import android.provider.DeviceConfig;
 import android.stats.location.LocationStatsEnums;
 import android.text.TextUtils;
 import android.util.ArraySet;
@@ -94,6 +96,7 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.Preconditions;
 import com.android.server.FgThread;
+import com.android.server.IoThread;
 import com.android.server.LocalServices;
 import com.android.server.location.LocationPermissions;
 import com.android.server.location.LocationPermissions.PermissionLevel;
@@ -122,6 +125,7 @@
 import com.android.server.location.settings.LocationUserSettings;
 
 import java.io.FileDescriptor;
+import java.io.IOException;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
@@ -1441,6 +1445,10 @@
     @GuardedBy("mMultiplexerLock")
     @Nullable private StateChangedListener mStateChangedListener;
 
+    /** Enables missing MSL altitudes to be added on behalf of the provider. */
+    private final AltitudeConverter mAltitudeConverter = new AltitudeConverter();
+    private volatile boolean mIsAltitudeConverterIdle = true;
+
     public LocationProviderManager(Context context, Injector injector,
             String name, @Nullable PassiveLocationProviderManager passiveManager) {
         this(context, injector, name, passiveManager, Collections.emptyList());
@@ -2512,33 +2520,18 @@
     @GuardedBy("mMultiplexerLock")
     @Override
     public void onReportLocation(LocationResult locationResult) {
-        LocationResult filtered;
+        LocationResult processed;
         if (mPassiveManager != null) {
-            filtered = locationResult.filter(location -> {
-                if (!location.isMock()) {
-                    if (location.getLatitude() == 0 && location.getLongitude() == 0) {
-                        Log.e(TAG, "blocking 0,0 location from " + mName + " provider");
-                        return false;
-                    }
-                }
-
-                if (!location.isComplete()) {
-                    Log.e(TAG, "blocking incomplete location from " + mName + " provider");
-                    return false;
-                }
-
-                return true;
-            });
-
-            if (filtered == null) {
+            processed = processReportedLocation(locationResult);
+            if (processed == null) {
                 return;
             }
 
             // don't log location received for passive provider because it's spammy
-            EVENT_LOG.logProviderReceivedLocations(mName, filtered.size());
+            EVENT_LOG.logProviderReceivedLocations(mName, processed.size());
         } else {
-            // passive provider should get already filtered results as input
-            filtered = locationResult;
+            // passive provider should get already processed results as input
+            processed = locationResult;
         }
 
         // check for non-monotonic locations if we're not the passive manager. the passive manager
@@ -2554,20 +2547,78 @@
         }
 
         // update last location
-        setLastLocation(filtered.getLastLocation(), UserHandle.USER_ALL);
+        setLastLocation(processed.getLastLocation(), UserHandle.USER_ALL);
 
         // attempt listener delivery
         deliverToListeners(registration -> {
-            return registration.acceptLocationChange(filtered);
+            return registration.acceptLocationChange(processed);
         });
 
         // notify passive provider
         if (mPassiveManager != null) {
-            mPassiveManager.updateLocation(filtered);
+            mPassiveManager.updateLocation(processed);
         }
     }
 
     @GuardedBy("mMultiplexerLock")
+    @Nullable
+    private LocationResult processReportedLocation(LocationResult locationResult) {
+        LocationResult processed = locationResult.filter(location -> {
+            if (!location.isMock()) {
+                if (location.getLatitude() == 0 && location.getLongitude() == 0) {
+                    Log.e(TAG, "blocking 0,0 location from " + mName + " provider");
+                    return false;
+                }
+            }
+
+            if (!location.isComplete()) {
+                Log.e(TAG, "blocking incomplete location from " + mName + " provider");
+                return false;
+            }
+
+            return true;
+        });
+        if (processed == null) {
+            return null;
+        }
+
+        // Attempt to add a missing MSL altitude on behalf of the provider.
+        if (DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_LOCATION,
+                "enable_location_provider_manager_msl", false)) {
+            return processed.map(location -> {
+                if (!location.hasMslAltitude() && location.hasAltitude()) {
+                    try {
+                        Location locationCopy = new Location(location);
+                        if (mAltitudeConverter.addMslAltitudeToLocation(locationCopy)) {
+                            return locationCopy;
+                        }
+                        // Only queue up one IO thread runnable.
+                        if (mIsAltitudeConverterIdle) {
+                            mIsAltitudeConverterIdle = false;
+                            IoThread.getExecutor().execute(() -> {
+                                try {
+                                    // Results added to the location copy are essentially discarded.
+                                    // We only rely on the side effect of loading altitude assets
+                                    // into the converter's memory cache.
+                                    mAltitudeConverter.addMslAltitudeToLocation(mContext,
+                                            locationCopy);
+                                } catch (IOException e) {
+                                    Log.e(TAG, "not loading MSL altitude assets: " + e);
+                                }
+                                mIsAltitudeConverterIdle = true;
+                            });
+                        }
+                    } catch (IllegalArgumentException e) {
+                        Log.e(TAG, "not adding MSL altitude to location: " + e);
+                    }
+                }
+                return location;
+            });
+        }
+        return processed;
+    }
+
+    @GuardedBy("mMultiplexerLock")
     private void onUserStarted(int userId) {
         if (userId == UserHandle.USER_NULL) {
             return;
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 4f28432..0476f2c 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -2141,17 +2141,6 @@
                 // credential has matched
                 mBiometricDeferredQueue.addPendingLockoutResetForUser(userId,
                         authResult.syntheticPassword.deriveGkPassword());
-
-                // perform verifyChallenge with synthetic password which generates the real GK auth
-                // token and response for the current user
-                response = mSpManager.verifyChallenge(getGateKeeperService(),
-                        authResult.syntheticPassword, 0L /* challenge */, userId);
-                if (response.getResponseCode() != VerifyCredentialResponse.RESPONSE_OK) {
-                    // This shouldn't really happen: the unwrapping of SP succeeds, but SP doesn't
-                    // match the recorded GK password handle.
-                    Slog.wtf(TAG, "verifyChallenge with SP failed.");
-                    return VerifyCredentialResponse.ERROR;
-                }
             }
         }
         if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
@@ -2768,7 +2757,7 @@
      *
      * Also maintains the invariants described in {@link SyntheticPasswordManager} by
      * setting/clearing the protection (by the SP) on the user's auth-bound Keystore keys when the
-     * LSKF is added/removed, respectively.  If the new LSKF is nonempty, then the Gatekeeper auth
+     * LSKF is added/removed, respectively.  If an LSKF is being added, then the Gatekeeper auth
      * token is also refreshed.
      */
     @GuardedBy("mSpManager")
@@ -2785,9 +2774,7 @@
             // not needed by synchronizeUnifiedWorkChallengeForProfiles()
             profilePasswords = null;
 
-            if (mSpManager.hasSidForUser(userId)) {
-                mSpManager.verifyChallenge(getGateKeeperService(), sp, 0L, userId);
-            } else {
+            if (!mSpManager.hasSidForUser(userId)) {
                 mSpManager.newSidForUser(getGateKeeperService(), sp, userId);
                 mSpManager.verifyChallenge(getGateKeeperService(), sp, 0L, userId);
                 setKeystorePassword(sp.deriveKeyStorePassword(), userId);
diff --git a/services/core/java/com/android/server/pm/Computer.java b/services/core/java/com/android/server/pm/Computer.java
index c232b36..19575a3 100644
--- a/services/core/java/com/android/server/pm/Computer.java
+++ b/services/core/java/com/android/server/pm/Computer.java
@@ -59,7 +59,6 @@
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
-import java.util.Collection;
 import java.util.List;
 import java.util.Set;
 
@@ -677,5 +676,5 @@
     UserInfo[] getUserInfos();
 
     @NonNull
-    Collection<SharedUserSetting> getAllSharedUsers();
+    ArrayMap<String, ? extends SharedUserApi> getSharedUsers();
 }
diff --git a/services/core/java/com/android/server/pm/ComputerEngine.java b/services/core/java/com/android/server/pm/ComputerEngine.java
index 5984360..14b72ff 100644
--- a/services/core/java/com/android/server/pm/ComputerEngine.java
+++ b/services/core/java/com/android/server/pm/ComputerEngine.java
@@ -301,8 +301,8 @@
         }
 
         @NonNull
-        public Collection<SharedUserSetting> getAllSharedUsers() {
-            return mSettings.getAllSharedUsersLPw();
+        ArrayMap<String, ? extends SharedUserApi> getSharedUsers() {
+            return mSettings.getSharedUsersLocked().untrackedStorage();
         }
 
         @Nullable
@@ -5484,8 +5484,8 @@
     @Override
     public SparseArray<String> getAppsWithSharedUserIds() {
         final SparseArray<String> sharedUserIds = new SparseArray<>();
-        for (SharedUserSetting setting : mSettings.getAllSharedUsers()) {
-            sharedUserIds.put(UserHandle.getAppId(setting.mAppId), setting.name);
+        for (SharedUserApi sharedUser : mSettings.getSharedUsers().values()) {
+            sharedUserIds.put(UserHandle.getAppId(sharedUser.getAppId()), sharedUser.getName());
         }
         return sharedUserIds;
     }
@@ -5785,8 +5785,8 @@
 
     @Override
     @NonNull
-    public Collection<SharedUserSetting> getAllSharedUsers() {
-        return mSettings.getAllSharedUsers();
+    public ArrayMap<String, ? extends SharedUserApi> getSharedUsers() {
+        return mSettings.getSharedUsers();
     }
 
     @Override
diff --git a/services/core/java/com/android/server/pm/PackageManagerLocal.java b/services/core/java/com/android/server/pm/PackageManagerLocal.java
index 935c4dd..6266ef3 100644
--- a/services/core/java/com/android/server/pm/PackageManagerLocal.java
+++ b/services/core/java/com/android/server/pm/PackageManagerLocal.java
@@ -24,6 +24,7 @@
 import android.os.UserHandle;
 
 import com.android.server.pm.pkg.PackageState;
+import com.android.server.pm.pkg.SharedUserApi;
 
 import java.io.IOException;
 import java.lang.annotation.Retention;
@@ -150,6 +151,16 @@
         Map<String, PackageState> getPackageStates();
 
         /**
+         * Returns a map of all {@link SharedUserApi SharedUsers} on the device.
+         *
+         * @return Mapping of shared user name to {@link SharedUserApi}.
+         *
+         * @hide Pending API
+         */
+        @NonNull
+        Map<String, SharedUserApi> getSharedUsers();
+
+        /**
          * Returns a map of all disabled system {@link PackageState PackageStates} on the device.
          *
          * @return Mapping of package name to disabled system {@link PackageState}.
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index de5f0c4..b157781 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -218,6 +218,7 @@
 import com.android.server.pm.parsing.pkg.ParsedPackage;
 import com.android.server.pm.permission.LegacyPermissionManagerInternal;
 import com.android.server.pm.permission.LegacyPermissionManagerService;
+import com.android.server.pm.permission.LegacyPermissionSettings;
 import com.android.server.pm.permission.PermissionManagerService;
 import com.android.server.pm.permission.PermissionManagerServiceInternal;
 import com.android.server.pm.pkg.AndroidPackage;
@@ -6746,6 +6747,13 @@
         }
 
         @Override
+        public LegacyPermissionSettings getLegacyPermissions() {
+            synchronized (mLock) {
+                return mSettings.mPermissions;
+            }
+        }
+
+        @Override
         @SuppressWarnings("GuardedBy")
         public boolean isPermissionUpgradeNeeded(int userId) {
             return mSettings.isPermissionUpgradeNeeded(userId);
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index b6557d0..4675a7c 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -110,6 +110,7 @@
 import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.pm.pkg.PackageUserState;
 import com.android.server.pm.pkg.PackageUserStateInternal;
+import com.android.server.pm.pkg.SharedUserApi;
 import com.android.server.pm.pkg.SuspendParams;
 import com.android.server.pm.pkg.component.ParsedComponent;
 import com.android.server.pm.pkg.component.ParsedIntentInfo;
@@ -867,6 +868,10 @@
         return s;
     }
 
+    WatchedArrayMap<String, ? extends SharedUserApi> getSharedUsersLocked() {
+        return mSharedUsers;
+    }
+
     Collection<SharedUserSetting> getAllSharedUsersLPw() {
         return mSharedUsers.values();
     }
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 2f98d34..1a486dc 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -2422,41 +2422,58 @@
     @Override
     public boolean setUserEphemeral(@UserIdInt int userId, boolean enableEphemeral) {
         checkCreateUsersPermission("update ephemeral user flag");
-        UserData userToUpdate = null;
+        return enableEphemeral
+                ? UserManager.isRemoveResultSuccessful(setUserEphemeralUnchecked(userId))
+                : setUserNonEphemeralUnchecked(userId);
+    }
+
+    private boolean setUserNonEphemeralUnchecked(@UserIdInt int userId) {
         synchronized (mPackagesLock) {
+            final UserData userData;
             synchronized (mUsersLock) {
-                final UserData userData = mUsers.get(userId);
+                userData = mUsers.get(userId);
                 if (userData == null) {
-                    Slog.e(LOG_TAG, "User not found for setting ephemeral mode: u" + userId);
+                    Slog.e(LOG_TAG, TextUtils.formatSimple(
+                            "Cannot set user %d non-ephemeral, invalid user id provided.", userId));
                     return false;
                 }
-                boolean isEphemeralUser = (userData.info.flags & UserInfo.FLAG_EPHEMERAL) != 0;
-                boolean isEphemeralOnCreateUser =
-                        (userData.info.flags & UserInfo.FLAG_EPHEMERAL_ON_CREATE) != 0;
-                // when user is created in ephemeral mode via FLAG_EPHEMERAL
-                // its state cannot be changed to non ephemeral.
-                // FLAG_EPHEMERAL_ON_CREATE is used to keep track of this state
-                if (isEphemeralOnCreateUser && !enableEphemeral) {
-                    Slog.e(LOG_TAG, "Failed to change user state to non-ephemeral for user "
-                            + userId);
+                if (!userData.info.isEphemeral()) {
+                    return true;
+                }
+
+                if ((userData.info.flags & UserInfo.FLAG_EPHEMERAL_ON_CREATE) != 0) {
+                    // when user is created in ephemeral mode via FLAG_EPHEMERAL
+                    // its state cannot be changed to non-ephemeral.
+                    // FLAG_EPHEMERAL_ON_CREATE is used to keep track of this state
+                    Slog.e(LOG_TAG, TextUtils.formatSimple("User %d can not be changed to "
+                            + "non-ephemeral because it was set ephemeral on create.", userId));
                     return false;
                 }
-                if (isEphemeralUser != enableEphemeral) {
-                    if (enableEphemeral) {
-                        userData.info.flags |= UserInfo.FLAG_EPHEMERAL;
-                    } else {
-                        userData.info.flags &= ~UserInfo.FLAG_EPHEMERAL;
-                    }
-                    userToUpdate = userData;
-                }
             }
-            if (userToUpdate != null) {
-                writeUserLP(userToUpdate);
-            }
+            userData.info.flags &= ~UserInfo.FLAG_EPHEMERAL;
+            writeUserLP(userData);
         }
         return true;
     }
 
+    private @UserManager.RemoveResult int setUserEphemeralUnchecked(@UserIdInt int userId) {
+        synchronized (mPackagesLock) {
+            final UserData userData;
+            synchronized (mUsersLock) {
+                final int userRemovability = getUserRemovabilityLocked(userId, "set as ephemeral");
+                if (userRemovability != UserManager.REMOVE_RESULT_USER_IS_REMOVABLE) {
+                    return userRemovability;
+                }
+                userData = mUsers.get(userId);
+            }
+            userData.info.flags |= UserInfo.FLAG_EPHEMERAL;
+            writeUserLP(userData);
+        }
+        Slog.i(LOG_TAG, TextUtils.formatSimple(
+                "User %d is set ephemeral and will be removed on user switch or reboot.", userId));
+        return UserManager.REMOVE_RESULT_DEFERRED;
+    }
+
     @Override
     public void setUserIcon(@UserIdInt int userId, Bitmap bitmap) {
         try {
@@ -5407,23 +5424,37 @@
     }
 
     private boolean removeUserWithProfilesUnchecked(@UserIdInt int userId) {
-        UserInfo userInfo = getUserInfoNoChecks(userId);
-
-        if (userInfo == null) {
-            Slog.e(LOG_TAG, TextUtils.formatSimple(
-                    "Cannot remove user %d, invalid user id provided.", userId));
-            return false;
+        final UserData userData;
+        final boolean isProfile;
+        final IntArray profileIds;
+        synchronized (mUsersLock) {
+            final int userRemovability = getUserRemovabilityLocked(userId, "removed");
+            if (userRemovability != UserManager.REMOVE_RESULT_USER_IS_REMOVABLE) {
+                return UserManager.isRemoveResultSuccessful(userRemovability);
+            }
+            userData = mUsers.get(userId);
+            isProfile = userData.info.isProfile();
+            profileIds = isProfile ? null : getProfileIdsLU(userId, null, false);
         }
 
-        if (!userInfo.isProfile()) {
-            int[] profileIds = getProfileIds(userId, false);
-            for (int profileId : profileIds) {
+        if (!isProfile) {
+            Pair<Integer, Integer> currentAndTargetUserIds = getCurrentAndTargetUserIds();
+            if (userId == currentAndTargetUserIds.first) {
+                Slog.w(LOG_TAG, "Current user cannot be removed.");
+                return false;
+            }
+            if (userId == currentAndTargetUserIds.second) {
+                Slog.w(LOG_TAG, "Target user of an ongoing user switch cannot be removed.");
+                return false;
+            }
+            for (int i = profileIds.size() - 1; i >= 0; i--) {
+                int profileId = profileIds.get(i);
                 if (profileId == userId) {
                     //Remove the associated profiles first and then remove the user
                     continue;
                 }
                 Slog.i(LOG_TAG, "removing profile:" + profileId
-                        + "associated with user:" + userId);
+                        + " associated with user:" + userId);
                 if (!removeUserUnchecked(profileId)) {
                     // If the profile was not immediately removed, make sure it is marked as
                     // ephemeral. Don't mark as disabled since, per UserInfo.FLAG_DISABLED
@@ -5470,45 +5501,16 @@
         final long ident = Binder.clearCallingIdentity();
         try {
             final UserData userData;
-            Pair<Integer, Integer> currentAndTargetUserIds = getCurrentAndTargetUserIds();
-            if (userId == currentAndTargetUserIds.first) {
-                Slog.w(LOG_TAG, "Current user cannot be removed.");
-                return false;
-            }
-            if (userId == currentAndTargetUserIds.second) {
-                Slog.w(LOG_TAG, "Target user of an ongoing user switch cannot be removed.");
-                return false;
-            }
             synchronized (mPackagesLock) {
                 synchronized (mUsersLock) {
+                    final int userRemovability = getUserRemovabilityLocked(userId, "removed");
+                    if (userRemovability != UserManager.REMOVE_RESULT_USER_IS_REMOVABLE) {
+                        return UserManager.isRemoveResultSuccessful(userRemovability);
+                    }
                     userData = mUsers.get(userId);
-                    if (userId == UserHandle.USER_SYSTEM) {
-                        Slog.e(LOG_TAG, "System user cannot be removed.");
-                        return false;
-                    }
-
-                    if (userData == null) {
-                        Slog.e(LOG_TAG, TextUtils.formatSimple(
-                                "Cannot remove user %d, invalid user id provided.", userId));
-                        return false;
-                    }
-
-                    if (isNonRemovableMainUser(userData.info)) {
-                        Slog.e(LOG_TAG, "Main user cannot be removed when "
-                                + "it's a permanent admin user.");
-                        return false;
-                    }
-
-                    if (mRemovingUserIds.get(userId)) {
-                        Slog.e(LOG_TAG, TextUtils.formatSimple(
-                                "User %d is already scheduled for removal.", userId));
-                        return false;
-                    }
-
                     Slog.i(LOG_TAG, "Removing user " + userId);
                     addRemovingUserIdLocked(userId);
                 }
-
                 // Set this to a partially created user, so that the user will be purged
                 // on next startup, in case the runtime stops now before stopping and
                 // removing the user completely.
@@ -5577,6 +5579,7 @@
     @Override
     public @UserManager.RemoveResult int removeUserWhenPossible(@UserIdInt int userId,
             boolean overrideDevicePolicy) {
+        Slog.i(LOG_TAG, "removeUserWhenPossible u" + userId);
         checkCreateUsersPermission("Only the system can remove users");
 
         if (!overrideDevicePolicy) {
@@ -5586,65 +5589,47 @@
                 return UserManager.REMOVE_RESULT_ERROR_USER_RESTRICTION;
             }
         }
+        Slog.i(LOG_TAG, "Attempting to immediately remove user " + userId);
+        if (removeUserWithProfilesUnchecked(userId)) {
+            return UserManager.REMOVE_RESULT_REMOVED;
+        }
+        Slog.i(LOG_TAG, TextUtils.formatSimple(
+                "Unable to immediately remove user %d. Now trying to set it ephemeral.", userId));
+        return setUserEphemeralUnchecked(userId);
+    }
+
+    /**
+     * Returns the user's removability status.
+     * User is removable if the return value is {@link UserManager#REMOVE_RESULT_USER_IS_REMOVABLE}.
+     * If the user is not removable this method also prints the reason.
+     * See also {@link UserManager#isRemoveResultSuccessful}.
+     */
+    @GuardedBy("mUsersLock")
+    private @UserManager.RemoveResult int getUserRemovabilityLocked(@UserIdInt int userId,
+            String msg) {
+        String prefix = TextUtils.formatSimple("User %d can not be %s, ", userId, msg);
         if (userId == UserHandle.USER_SYSTEM) {
-            Slog.e(LOG_TAG, "System user cannot be removed.");
+            Slog.e(LOG_TAG, prefix + "system user cannot be removed.");
             return UserManager.REMOVE_RESULT_ERROR_SYSTEM_USER;
         }
-
-        final long ident = Binder.clearCallingIdentity();
-        try {
-            final UserData userData;
-            synchronized (mPackagesLock) {
-                synchronized (mUsersLock) {
-                    userData = mUsers.get(userId);
-                    if (userData == null) {
-                        Slog.e(LOG_TAG,
-                                "Cannot remove user " + userId + ", invalid user id provided.");
-                        return UserManager.REMOVE_RESULT_ERROR_USER_NOT_FOUND;
-                    }
-
-                    if (isNonRemovableMainUser(userData.info)) {
-                        Slog.e(LOG_TAG, "Main user cannot be removed when "
-                                + "it's a permanent admin user.");
-                        return UserManager.REMOVE_RESULT_ERROR_MAIN_USER_PERMANENT_ADMIN;
-                    }
-
-                    if (mRemovingUserIds.get(userId)) {
-                        Slog.e(LOG_TAG, "User " + userId + " is already scheduled for removal.");
-                        return UserManager.REMOVE_RESULT_ALREADY_BEING_REMOVED;
-                    }
-                }
-
-                // Attempt to immediately remove a non-current and non-target user
-                Pair<Integer, Integer> currentAndTargetUserIds = getCurrentAndTargetUserIds();
-                if (userId != currentAndTargetUserIds.first
-                        && userId != currentAndTargetUserIds.second) {
-                    // Attempt to remove the user. This will fail if the user is the current user
-                    if (removeUserWithProfilesUnchecked(userId)) {
-                        return UserManager.REMOVE_RESULT_REMOVED;
-                    }
-                }
-                // If the user was not immediately removed, make sure it is marked as ephemeral.
-                // Don't mark as disabled since, per UserInfo.FLAG_DISABLED documentation, an
-                // ephemeral user should only be marked as disabled when its removal is in progress.
-                Slog.i(LOG_TAG, TextUtils.formatSimple("Unable to immediately remove user %d "
-                                + "(%s is %d). User is set as ephemeral and will be removed on "
-                                + "user switch or reboot.",
-                        userId,
-                        userId == currentAndTargetUserIds.first
-                                ? "current user"
-                                : "target user of an ongoing user switch",
-                        userId));
-                userData.info.flags |= UserInfo.FLAG_EPHEMERAL;
-                writeUserLP(userData);
-
-                return UserManager.REMOVE_RESULT_DEFERRED;
-            }
-        } finally {
-            Binder.restoreCallingIdentity(ident);
+        final UserData userData = mUsers.get(userId);
+        if (userData == null) {
+            Slog.e(LOG_TAG, prefix + "invalid user id provided.");
+            return UserManager.REMOVE_RESULT_ERROR_USER_NOT_FOUND;
         }
+        if (isNonRemovableMainUser(userData.info)) {
+            Slog.e(LOG_TAG, prefix
+                    + "main user cannot be removed when it's a permanent admin user.");
+            return UserManager.REMOVE_RESULT_ERROR_MAIN_USER_PERMANENT_ADMIN;
+        }
+        if (mRemovingUserIds.get(userId)) {
+            Slog.w(LOG_TAG, prefix + "it is already scheduled for removal.");
+            return UserManager.REMOVE_RESULT_ALREADY_BEING_REMOVED;
+        }
+        return UserManager.REMOVE_RESULT_USER_IS_REMOVABLE;
     }
 
+
     private void finishRemoveUser(final @UserIdInt int userId) {
         Slog.i(LOG_TAG, "finishRemoveUser " + userId);
 
diff --git a/services/core/java/com/android/server/pm/local/PackageManagerLocalImpl.java b/services/core/java/com/android/server/pm/local/PackageManagerLocalImpl.java
index 4e0a11d..8d05450 100644
--- a/services/core/java/com/android/server/pm/local/PackageManagerLocalImpl.java
+++ b/services/core/java/com/android/server/pm/local/PackageManagerLocalImpl.java
@@ -28,6 +28,7 @@
 import com.android.server.pm.PackageManagerLocal;
 import com.android.server.pm.PackageManagerService;
 import com.android.server.pm.pkg.PackageState;
+import com.android.server.pm.pkg.SharedUserApi;
 import com.android.server.pm.snapshot.PackageDataSnapshot;
 
 import java.io.IOException;
@@ -105,6 +106,9 @@
         private Map<String, PackageState> mCachedUnmodifiablePackageStates;
 
         @Nullable
+        private Map<String, SharedUserApi> mCachedUnmodifiableSharedUsers;
+
+        @Nullable
         private Map<String, PackageState> mCachedUnmodifiableDisabledSystemPackageStates;
 
         private UnfilteredSnapshotImpl(@NonNull PackageDataSnapshot snapshot) {
@@ -132,6 +136,19 @@
         @SuppressWarnings("RedundantSuppression")
         @NonNull
         @Override
+        public Map<String, SharedUserApi> getSharedUsers() {
+            checkClosed();
+
+            if (mCachedUnmodifiableSharedUsers == null) {
+                mCachedUnmodifiableSharedUsers =
+                        Collections.unmodifiableMap(mSnapshot.getSharedUsers());
+            }
+            return mCachedUnmodifiableSharedUsers;
+        }
+
+        @SuppressWarnings("RedundantSuppression")
+        @NonNull
+        @Override
         public Map<String, PackageState> getDisabledSystemPackageStates() {
             checkClosed();
 
diff --git a/services/core/java/com/android/server/pm/permission/PermissionMigrationHelper.java b/services/core/java/com/android/server/pm/permission/PermissionMigrationHelper.java
new file mode 100644
index 0000000..e91ddfd
--- /dev/null
+++ b/services/core/java/com/android/server/pm/permission/PermissionMigrationHelper.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm.permission;
+
+import android.annotation.NonNull;
+import android.content.pm.PermissionInfo;
+
+import java.util.Map;
+
+/**
+ * In-process api for permissions migration.
+ *
+ * @hide
+ */
+public interface PermissionMigrationHelper {
+    /**
+     * @return legacy permission definitions.
+     */
+    @NonNull
+    Map<String, LegacyPermission> getLegacyPermissions();
+
+    /**
+     * @return legacy permission trees.
+     */
+    @NonNull
+    Map<String, LegacyPermission> getLegacyPermissionTrees();
+
+    /**
+     * @return legacy permissions state for a user.
+     */
+    @NonNull
+    Map<Integer, Map<String, LegacyPermissionState>> getLegacyPermissionStates(int userId);
+
+    /**
+     * Legacy permission definition.
+     */
+    final class LegacyPermission {
+        private final PermissionInfo mPermissionInfo;
+        private final int mType;
+
+        LegacyPermission(PermissionInfo permissionInfo, int type) {
+            mPermissionInfo = permissionInfo;
+            mType = type;
+        }
+
+        @NonNull
+        public PermissionInfo getPermissionInfo() {
+            return mPermissionInfo;
+        }
+
+        public int getType() {
+            return mType;
+        }
+    }
+
+    /**
+     * State of a legacy permission.
+     */
+    final class LegacyPermissionState {
+        private final boolean mGranted;
+        private final int mFlags;
+
+        LegacyPermissionState(boolean granted, int flags) {
+            mGranted = granted;
+            mFlags = flags;
+        }
+
+        /**
+         * @return Whether the permission is granted or not.
+         */
+        public boolean isGranted() {
+            return mGranted;
+        }
+
+        /**
+         * @return Permission flags.
+         */
+        public int getFlags() {
+            return mFlags;
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/pm/permission/PermissionMigrationHelperImpl.java b/services/core/java/com/android/server/pm/permission/PermissionMigrationHelperImpl.java
new file mode 100644
index 0000000..91b4aaa
--- /dev/null
+++ b/services/core/java/com/android/server/pm/permission/PermissionMigrationHelperImpl.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm.permission;
+
+import android.annotation.NonNull;
+import android.content.pm.PackageManagerInternal;
+import android.os.UserHandle;
+import android.util.ArrayMap;
+import android.util.Log;
+
+import com.android.permission.persistence.RuntimePermissionsPersistence;
+import com.android.permission.persistence.RuntimePermissionsState;
+import com.android.server.LocalManagerRegistry;
+import com.android.server.LocalServices;
+import com.android.server.pm.PackageManagerLocal;
+import com.android.server.pm.pkg.PackageState;
+import com.android.server.pm.pkg.SharedUserApi;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Provider of legacy permissions data for new permission subsystem.
+ *
+ * @hide
+ */
+public class PermissionMigrationHelperImpl implements PermissionMigrationHelper {
+    private static final String LOG_TAG = PermissionMigrationHelperImpl.class.getSimpleName();
+
+    /**
+     * @return legacy permission definitions.
+     */
+    @NonNull
+    public Map<String, LegacyPermission> getLegacyPermissions() {
+        PackageManagerInternal mPackageManagerInternal =
+                LocalServices.getService(PackageManagerInternal.class);
+        return toLegacyPermissions(
+                mPackageManagerInternal.getLegacyPermissions().getPermissions());
+    }
+
+    /**
+     * @return legacy permission trees.
+     */
+    @NonNull
+    public Map<String, LegacyPermission> getLegacyPermissionTrees() {
+        PackageManagerInternal mPackageManagerInternal =
+                LocalServices.getService(PackageManagerInternal.class);
+        return toLegacyPermissions(
+                mPackageManagerInternal.getLegacyPermissions().getPermissionTrees());
+    }
+
+    @NonNull
+    private Map<String, LegacyPermission> toLegacyPermissions(
+            List<com.android.server.pm.permission.LegacyPermission> legacyPermissions) {
+        Map<String, LegacyPermission> permissions = new ArrayMap<>();
+        legacyPermissions.forEach(legacyPermission -> {
+            LegacyPermission permission = new LegacyPermission(legacyPermission.getPermissionInfo(),
+                    legacyPermission.getType());
+            permissions.put(legacyPermission.getPermissionInfo().name, permission);
+        });
+
+        return permissions;
+    }
+
+    /**
+     * @return permissions state for a user, i.e. map of appId to map of permission name and state.
+     */
+    @NonNull
+    public Map<Integer, Map<String, LegacyPermissionState>> getLegacyPermissionStates(int userId) {
+        RuntimePermissionsPersistence legacyPersistence =
+                RuntimePermissionsPersistence.createInstance();
+        Map<Integer, Map<String, LegacyPermissionState>> appIdPermissionStates = new ArrayMap<>();
+
+        RuntimePermissionsState legacyState = legacyPersistence.readForUser(UserHandle.of(userId));
+        PackageManagerLocal packageManagerLocal =
+                LocalManagerRegistry.getManager(PackageManagerLocal.class);
+
+        try (PackageManagerLocal.UnfilteredSnapshot snapshot =
+                     packageManagerLocal.withUnfilteredSnapshot()) {
+            Map<String, PackageState> packageStates = snapshot.getPackageStates();
+            legacyState.getPackagePermissions().forEach((packageName, permissionStates) -> {
+                PackageState packageState = packageStates.get(packageName);
+                if (packageState != null) {
+                    int appId = packageState.getAppId();
+                    appIdPermissionStates.put(appId, toLegacyPermissionStates(permissionStates));
+                } else {
+                    Log.w(LOG_TAG, "Package " + packageName + " not found.");
+                }
+            });
+
+            Map<String, SharedUserApi> sharedUsers = snapshot.getSharedUsers();
+            legacyState.getSharedUserPermissions().forEach((sharedUserName, permissionStates) -> {
+                SharedUserApi sharedUser = sharedUsers.get(sharedUserName);
+                if (sharedUser != null) {
+                    int appId = sharedUser.getAppId();
+                    appIdPermissionStates.put(appId, toLegacyPermissionStates(permissionStates));
+                } else {
+                    Log.w(LOG_TAG, "Shared user " + sharedUserName + " not found.");
+                }
+            });
+        }
+        return appIdPermissionStates;
+    }
+
+    @NonNull
+    private Map<String, LegacyPermissionState> toLegacyPermissionStates(
+            List<RuntimePermissionsState.PermissionState> permissions) {
+        Map<String, LegacyPermissionState> legacyPermissions = new ArrayMap<>();
+
+        final int size = permissions.size();
+        for (int i = 0; i < size; i++) {
+            RuntimePermissionsState.PermissionState permState = permissions.get(i);
+            legacyPermissions.put(permState.getName(), new LegacyPermissionState(
+                    permState.isGranted(), permState.getFlags()));
+        }
+
+        return legacyPermissions;
+    }
+}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 45dc49d..92dd95a 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -68,6 +68,7 @@
 import static android.view.WindowManagerGlobal.ADD_PERMISSION_DENIED;
 
 import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.SCREENSHOT_KEYCHORD_DELAY;
+import static com.android.internal.util.FrameworkStatsLog.ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__A11Y_WEAR_TRIPLE_PRESS_GESTURE;
 import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_COVERED;
 import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_COVER_ABSENT;
 import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_UNCOVERED;
@@ -190,6 +191,7 @@
 
 import com.android.internal.R;
 import com.android.internal.accessibility.AccessibilityShortcutController;
+import com.android.internal.accessibility.util.AccessibilityStatsLogUtils;
 import com.android.internal.accessibility.util.AccessibilityUtils;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.AssistUtils;
@@ -1400,7 +1402,18 @@
                 if (DEBUG_INPUT) {
                     Slog.d(TAG, "Executing stem primary triple press action behavior.");
                 }
-                toggleTalkBack();
+
+                if (Settings.System.getIntForUser(mContext.getContentResolver(),
+                        Settings.System.WEAR_ACCESSIBILITY_GESTURE_ENABLED,
+                        /* def= */ 0, UserHandle.USER_CURRENT) == 1) {
+                    /** Toggle talkback begin */
+                    ComponentName componentName = getTalkbackComponent();
+                    if (componentName != null && toggleTalkBack(componentName)) {
+                        /** log stem triple press telemetry if it's a talkback enabled event */
+                        logStemTriplePressAccessibilityTelemetry(componentName);
+                    }
+                    /** Toggle talkback end */
+                }
                 break;
         }
     }
@@ -1419,17 +1432,39 @@
         }
     }
 
-    private void toggleTalkBack() {
-        final ComponentName componentName = getTalkbackComponent();
-        if (componentName == null) {
-            return;
-        }
-
+    /**
+     * A function that toggles talkback service
+     *
+     * @return {@code true} if talkback is enabled, {@code false} if talkback is disabled
+     */
+    private boolean toggleTalkBack(ComponentName componentName) {
         final Set<ComponentName> enabledServices =
                 AccessibilityUtils.getEnabledServicesFromSettings(mContext, mCurrentUserId);
 
+        boolean isTalkbackAlreadyEnabled = enabledServices.contains(componentName);
         AccessibilityUtils.setAccessibilityServiceState(mContext, componentName,
-                !enabledServices.contains(componentName));
+                !isTalkbackAlreadyEnabled);
+        /** if isTalkbackAlreadyEnabled is true, then it's a disabled event so return false
+         * and if isTalkbackAlreadyEnabled is false, return true as it's an enabled event */
+        return !isTalkbackAlreadyEnabled;
+    }
+
+    /**
+     * A function that logs stem triple press accessibility telemetry
+     * If the user setup (Oobe) is not completed, set the
+     * WEAR_ACCESSIBILITY_GESTURE_ENABLED_DURING_OOBE
+     * setting which will be later logged via Settings Snapshot
+     * else, log ACCESSIBILITY_SHORTCUT_REPORTED atom
+     */
+    private void logStemTriplePressAccessibilityTelemetry(ComponentName componentName) {
+        if (!AccessibilityUtils.isUserSetupCompleted(mContext)) {
+            Settings.Secure.putInt(mContext.getContentResolver(),
+                    Settings.System.WEAR_ACCESSIBILITY_GESTURE_ENABLED_DURING_OOBE, 1);
+        } else {
+            AccessibilityStatsLogUtils.logAccessibilityShortcutActivated(mContext, componentName,
+                    ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__A11Y_WEAR_TRIPLE_PRESS_GESTURE,
+                    /* serviceEnabled= */ true);
+        }
     }
 
     private ComponentName getTalkbackComponent() {
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
index 85f1357..646dc4e 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
@@ -29,6 +29,7 @@
 import com.android.internal.policy.IKeyguardService;
 import com.android.server.UiThread;
 import com.android.server.policy.WindowManagerPolicy.OnKeyguardExitResult;
+import com.android.server.wm.EventLogTags;
 
 import java.io.PrintWriter;
 
@@ -255,6 +256,11 @@
     public void setOccluded(boolean isOccluded, boolean notify) {
         if (mKeyguardService != null && notify) {
             if (DEBUG) Log.v(TAG, "setOccluded(" + isOccluded + ")");
+            EventLogTags.writeWmSetKeyguardOccluded(
+                    isOccluded ? 1 : 0,
+                    0 /* animate */,
+                    0 /* transit */,
+                    "setOccluded");
             mKeyguardService.setOccluded(isOccluded, false /* animate */);
         }
         mKeyguardState.occluded = isOccluded;
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 2e8a150..ea494db 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -6644,6 +6644,13 @@
         }
     }
 
+    @VisibleForTesting
+    int getPowerGroupSize() {
+        synchronized (mLock) {
+            return mPowerGroups.size();
+        }
+    }
+
     @GoToSleepReason
     private int getLastSleepReasonInternal() {
         synchronized (mLock) {
diff --git a/services/core/java/com/android/server/power/ShutdownThread.java b/services/core/java/com/android/server/power/ShutdownThread.java
index 5096ad1..a5ca7ac 100644
--- a/services/core/java/com/android/server/power/ShutdownThread.java
+++ b/services/core/java/com/android/server/power/ShutdownThread.java
@@ -17,6 +17,7 @@
 
 package com.android.server.power;
 
+import android.app.ActivityManagerInternal;
 import android.app.AlertDialog;
 import android.app.Dialog;
 import android.app.IActivityManager;
@@ -25,10 +26,11 @@
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.DialogInterface;
+import android.content.IIntentReceiver;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.PackageManagerInternal;
-import android.media.AudioAttributes;
+import android.os.Bundle;
 import android.os.FileUtils;
 import android.os.Handler;
 import android.os.PowerManager;
@@ -41,6 +43,8 @@
 import android.os.Trace;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.os.VibrationAttributes;
+import android.os.VibrationEffect;
 import android.os.Vibrator;
 import android.telephony.TelephonyManager;
 import android.util.ArrayMap;
@@ -51,7 +55,6 @@
 
 import com.android.server.LocalServices;
 import com.android.server.RescueParty;
-import com.android.server.pm.PackageManagerService;
 import com.android.server.statusbar.StatusBarManagerInternal;
 
 import java.io.File;
@@ -99,11 +102,6 @@
     // static instance of this thread
     private static final ShutdownThread sInstance = new ShutdownThread();
 
-    private static final AudioAttributes VIBRATION_ATTRIBUTES = new AudioAttributes.Builder()
-            .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
-            .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
-            .build();
-
     // Metrics that will be reported to tron after reboot
     private static final ArrayMap<String, Long> TRON_METRICS = new ArrayMap<>();
 
@@ -448,13 +446,6 @@
                 new File(CHECK_POINTS_FILE_BASENAME));
         dumpCheckPointsThread.start();
 
-        BroadcastReceiver br = new BroadcastReceiver() {
-            @Override public void onReceive(Context context, Intent intent) {
-                // We don't allow apps to cancel this, so ignore the result.
-                actionDone();
-            }
-        };
-
         /*
          * Write a system property in case the system_server reboots before we
          * get to the actual hardware restart. If that happens, we'll retry at
@@ -490,8 +481,16 @@
         mActionDone = false;
         Intent intent = new Intent(Intent.ACTION_SHUTDOWN);
         intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND | Intent.FLAG_RECEIVER_REGISTERED_ONLY);
-        mContext.sendOrderedBroadcastAsUser(intent,
-                UserHandle.ALL, null, br, mHandler, 0, null, null);
+        final ActivityManagerInternal activityManagerInternal = LocalServices.getService(
+                ActivityManagerInternal.class);
+        activityManagerInternal.broadcastIntentWithCallback(intent,
+                new IIntentReceiver.Stub() {
+                    @Override
+                    public void performReceive(Intent intent, int resultCode, String data,
+                            Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
+                        mHandler.post(ShutdownThread.this::actionDone);
+                    }
+                }, null, UserHandle.USER_ALL, null, null, null);
 
         final long endTime = SystemClock.elapsedRealtime() + MAX_BROADCAST_TIME;
         synchronized (mActionDoneSync) {
@@ -700,7 +699,10 @@
             // vibrate before shutting down
             Vibrator vibrator = new SystemVibrator(context);
             try {
-                vibrator.vibrate(SHUTDOWN_VIBRATE_MS, VIBRATION_ATTRIBUTES);
+                vibrator.vibrate(
+                        VibrationEffect.createOneShot(
+                                SHUTDOWN_VIBRATE_MS, VibrationEffect.DEFAULT_AMPLITUDE),
+                        VibrationAttributes.createForUsage(VibrationAttributes.USAGE_TOUCH));
             } catch (Exception e) {
                 // Failure to vibrate shouldn't interrupt shutdown.  Just log it.
                 Log.w(TAG, "Failed to vibrate during shutdown.", e);
diff --git a/services/core/java/com/android/server/security/FileIntegrity.java b/services/core/java/com/android/server/security/FileIntegrity.java
index 7b87d99..b8f187e 100644
--- a/services/core/java/com/android/server/security/FileIntegrity.java
+++ b/services/core/java/com/android/server/security/FileIntegrity.java
@@ -16,6 +16,8 @@
 
 package com.android.server.security;
 
+import static android.os.ParcelFileDescriptor.MODE_READ_ONLY;
+
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.os.ParcelFileDescriptor;
@@ -36,18 +38,26 @@
     private FileIntegrity() {}
 
     /**
-     * Enables fs-verity, if supported by the filesystem.
+     * Enables fs-verity, if supported by the filesystem. This operation is atomic, i.e. it's either
+     * enabled or not, even in case of power failure during or after the call.
      * @see <a href="https://www.kernel.org/doc/html/latest/filesystems/fsverity.html">
+     *
      * @hide
      */
     @SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
     public static void setUpFsVerity(@NonNull File file) throws IOException {
-        VerityUtils.setUpFsverity(file.getAbsolutePath());
+        try (ParcelFileDescriptor pfd = ParcelFileDescriptor.open(file, MODE_READ_ONLY)) {
+            setUpFsVerity(pfd);
+        }
     }
 
     /**
-     * Enables fs-verity, if supported by the filesystem.
+     * Enables fs-verity, if supported by the filesystem. This operation is atomic, i.e. it's either
+     * enabled or not, even in case of power failure during or after the call.
      * @see <a href="https://www.kernel.org/doc/html/latest/filesystems/fsverity.html">
+     *
+     * @param parcelFileDescriptor an FD opened in {@link ParcelFileDescriptor#MODE_READ_ONLY}.
+     *
      * @hide
      */
     @SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
diff --git a/services/core/java/com/android/server/vibrator/VibratorManagerService.java b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
index cb7e54d..bf99772 100644
--- a/services/core/java/com/android/server/vibrator/VibratorManagerService.java
+++ b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
@@ -412,7 +412,7 @@
             if (attrs.isFlagSet(VibrationAttributes.FLAG_INVALIDATE_SETTINGS_CACHE)) {
                 // Force update of user settings before checking if this vibration effect should
                 // be ignored or scaled.
-                mVibrationSettings.mSettingObserver.onChange(false);
+                mVibrationSettings.update();
             }
 
             synchronized (mLock) {
diff --git a/services/core/java/com/android/server/wm/EventLogTags.logtags b/services/core/java/com/android/server/wm/EventLogTags.logtags
index 594929b..244656c 100644
--- a/services/core/java/com/android/server/wm/EventLogTags.logtags
+++ b/services/core/java/com/android/server/wm/EventLogTags.logtags
@@ -49,7 +49,7 @@
 30066 wm_add_to_stopping (User|1|5),(Token|1|5),(Component Name|3),(Reason|3)
 
 # Keyguard status changed
-30067 wm_set_keyguard_shown (Display Id|1|5),(keyguardShowing|1),(aodShowing|1),(keyguardGoingAway|1),(Reason|3)
+30067 wm_set_keyguard_shown (Display Id|1|5),(keyguardShowing|1),(aodShowing|1),(keyguardGoingAway|1),(occluded|1),(Reason|3)
 
 # Out of memory for surfaces.
 31000 wm_no_surface_memory (Window|3),(PID|1|5),(Operation|3)
@@ -65,6 +65,8 @@
 
 # bootanim finished:
 31007 wm_boot_animation_done (time|2|3)
+# Notify keyguard occlude statuc change to SysUI.
+31008 wm_set_keyguard_occluded (occluded|1),(animate|1),(transit|1),(Channel|3)
 
 # Back navigation.
 31100 wm_back_navi_canceled (Reason|3)
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index 32b3ccf..08a6358 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -188,6 +188,7 @@
                 keyguardShowing ? 1 : 0,
                 aodShowing ? 1 : 0,
                 state.mKeyguardGoingAway ? 1 : 0,
+                state.mOccluded ? 1 : 0,
                 "setKeyguardShown");
 
         // Update the task snapshot if the screen will not be turned off. To make sure that the
@@ -253,9 +254,10 @@
         try {
             EventLogTags.writeWmSetKeyguardShown(
                     displayId,
-                    1 /* keyguardShowing */,
+                    state.mKeyguardShowing ? 1 : 0,
                     state.mAodShowing ? 1 : 0,
                     1 /* keyguardGoingAway */,
+                    state.mOccluded ? 1 : 0,
                     "keyguardGoingAway");
             final int transitFlags = convertTransitFlags(flags);
             final DisplayContent dc = mRootWindowContainer.getDefaultDisplay();
@@ -669,6 +671,15 @@
 
             boolean hasChange = false;
             if (lastOccluded != mOccluded) {
+                if (mDisplayId == DEFAULT_DISPLAY) {
+                    EventLogTags.writeWmSetKeyguardShown(
+                            mDisplayId,
+                            mKeyguardShowing ? 1 : 0,
+                            mAodShowing ? 1 : 0,
+                            mKeyguardGoingAway ? 1 : 0,
+                            mOccluded ? 1 : 0,
+                            "updateVisibility");
+                }
                 controller.handleOccludedChanged(mDisplayId, mTopOccludesActivity);
                 hasChange = true;
             } else if (!lastKeyguardGoingAway && mKeyguardGoingAway) {
diff --git a/services/core/java/com/android/server/wm/RemoteAnimationController.java b/services/core/java/com/android/server/wm/RemoteAnimationController.java
index 3635ebb..b879d1a 100644
--- a/services/core/java/com/android/server/wm/RemoteAnimationController.java
+++ b/services/core/java/com/android/server/wm/RemoteAnimationController.java
@@ -16,6 +16,8 @@
 
 package com.android.server.wm;
 
+import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_UNOCCLUDE;
+
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_REMOTE_ANIMATIONS;
 import static com.android.server.wm.AnimationAdapterProto.REMOTE;
 import static com.android.server.wm.RemoteAnimationAdapterWrapperProto.TARGET;
@@ -195,6 +197,13 @@
                                 + " transit=%s, apps=%d, wallpapers=%d, nonApps=%d",
                         AppTransition.appTransitionOldToString(transit), appTargets.length,
                         wallpaperTargets.length, nonAppTargets.length);
+                if (AppTransition.isKeyguardOccludeTransitOld(transit)) {
+                    EventLogTags.writeWmSetKeyguardOccluded(
+                            transit == TRANSIT_OLD_KEYGUARD_UNOCCLUDE ? 0 : 1,
+                            1 /* animate */,
+                            transit,
+                            "onAnimationStart");
+                }
                 mRemoteAnimationAdapter.getRunner().onAnimationStart(transit, appTargets,
                         wallpaperTargets, nonAppTargets, mFinishedCallback);
             } catch (RemoteException e) {
@@ -356,6 +365,11 @@
         final boolean isKeyguardOccluded = mDisplayContent.isKeyguardOccluded();
 
         try {
+            EventLogTags.writeWmSetKeyguardOccluded(
+                    isKeyguardOccluded ? 1 : 0,
+                    0 /* animate */,
+                    0 /* transit */,
+                    "onAnimationCancelled");
             mRemoteAnimationAdapter.getRunner().onAnimationCancelled(isKeyguardOccluded);
         } catch (RemoteException e) {
             Slog.e(TAG, "Failed to notify cancel", e);
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index a30ab11..5e8b115 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -53,6 +53,7 @@
 import static android.window.TransitionInfo.FLAG_NO_ANIMATION;
 import static android.window.TransitionInfo.FLAG_OCCLUDES_KEYGUARD;
 import static android.window.TransitionInfo.FLAG_SHOW_WALLPAPER;
+import static android.window.TransitionInfo.FLAG_TASK_LAUNCHING_BEHIND;
 import static android.window.TransitionInfo.FLAG_TRANSLUCENT;
 import static android.window.TransitionInfo.FLAG_WILL_IME_SHOWN;
 
@@ -2239,6 +2240,10 @@
                             .isMonitorTransitionTarget(topActivity)) {
                         flags |= TransitionInfo.FLAG_BACK_GESTURE_ANIMATED;
                     }
+                    if (topActivity != null && topActivity.mLaunchTaskBehind) {
+                        Slog.e(TAG, "Unexpected launch-task-behind operation in shell transition");
+                        flags |= FLAG_TASK_LAUNCHING_BEHIND;
+                    }
                 } else {
                     if (task.mAtmService.mBackNavigationController
                             .isMonitorTransitionTarget(task)) {
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index b9cb59a..87da85e 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -18,7 +18,7 @@
 
 import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
 import static android.app.ActivityManager.isStartResultSuccessful;
-import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 import static android.app.WindowConfiguration.WINDOW_CONFIG_BOUNDS;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.window.TaskFragmentOperation.OP_TYPE_CLEAR_ADJACENT_TASK_FRAGMENTS;
@@ -541,9 +541,9 @@
                 // setWindowingMode call in force-hidden.
                 boolean forceHiddenForPip = false;
                 if (wc.asTask() != null && wc.inPinnedWindowingMode()
-                        && entry.getValue().getWindowingMode() == WINDOWING_MODE_UNDEFINED) {
-                    // We are in pip and going to undefined. Now search hierarchy ops to determine
-                    // whether we are removing pip or expanding pip.
+                        && entry.getValue().getWindowingMode() != WINDOWING_MODE_PINNED) {
+                    // We are going out of pip. Now search hierarchy ops to determine whether we
+                    // are removing pip or expanding pip.
                     for (int i = 0; i < hopSize; ++i) {
                         final WindowContainerTransaction.HierarchyOp hop = hops.get(i);
                         if (hop.getType() != HIERARCHY_OP_TYPE_REORDER) continue;
@@ -679,7 +679,7 @@
                         + " windowing mode during locked task mode.");
             }
 
-            if (windowingMode == WindowConfiguration.WINDOWING_MODE_PINNED) {
+            if (windowingMode == WINDOWING_MODE_PINNED) {
                 // Do not directly put the container into PINNED mode as it may not support it or
                 // the app may not want to enter it. Instead, send a signal to request PIP
                 // mode to the app if they wish to support it below in #applyTaskChanges.
@@ -731,7 +731,7 @@
             tr.mDisplayContent.mPinnedTaskController.setEnterPipBounds(enterPipBounds);
         }
 
-        if (c.getWindowingMode() == WindowConfiguration.WINDOWING_MODE_PINNED
+        if (c.getWindowingMode() == WINDOWING_MODE_PINNED
                 && !tr.inPinnedWindowingMode()) {
             final ActivityRecord activity = tr.getTopNonFinishingActivity();
             if (activity != null) {
diff --git a/services/core/jni/gnss/GnssConfiguration.cpp b/services/core/jni/gnss/GnssConfiguration.cpp
index 3677641..b57e451 100644
--- a/services/core/jni/gnss/GnssConfiguration.cpp
+++ b/services/core/jni/gnss/GnssConfiguration.cpp
@@ -67,7 +67,7 @@
       : mIGnssConfiguration(iGnssConfiguration) {}
 
 jobject GnssConfiguration::getVersion(JNIEnv* env) {
-    return createHalInterfaceVersionJavaObject(env, 3, 0);
+    return createHalInterfaceVersionJavaObject(env, 3, mIGnssConfiguration->getInterfaceVersion());
 }
 
 jboolean GnssConfiguration::setEmergencySuplPdn(jint enable) {
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 850b5b6..321a71e 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -173,6 +173,8 @@
 import com.android.server.pm.ShortcutService;
 import com.android.server.pm.UserManagerService;
 import com.android.server.pm.dex.OdsignStatsLogger;
+import com.android.server.pm.permission.PermissionMigrationHelper;
+import com.android.server.pm.permission.PermissionMigrationHelperImpl;
 import com.android.server.pm.verify.domain.DomainVerificationService;
 import com.android.server.policy.AppOpsPolicy;
 import com.android.server.policy.PermissionPolicyService;
@@ -1132,6 +1134,8 @@
 
         // Start AccessCheckingService which provides new implementation for permission and app op.
         t.traceBegin("StartAccessCheckingService");
+        LocalServices.addService(PermissionMigrationHelper.class,
+                new PermissionMigrationHelperImpl());
         mSystemServiceManager.startService(AccessCheckingService.class);
         t.traceEnd();
 
diff --git a/services/permission/java/com/android/server/permission/access/AccessPersistence.kt b/services/permission/java/com/android/server/permission/access/AccessPersistence.kt
index a25b720..5b1e4ef 100644
--- a/services/permission/java/com/android/server/permission/access/AccessPersistence.kt
+++ b/services/permission/java/com/android/server/permission/access/AccessPersistence.kt
@@ -53,6 +53,9 @@
         writeHandler = WriteHandler(BackgroundThread.getHandler().looper)
     }
 
+    /**
+     * Reads the state either from the disk or migrate legacy data when the data files are missing.
+     */
     fun read(state: AccessState) {
         readSystemState(state)
         state.systemState.userIds.forEachIndexed { _, userId ->
@@ -61,28 +64,50 @@
     }
 
     private fun readSystemState(state: AccessState) {
-        systemFile.parse {
+        val fileExists = systemFile.parse {
             // This is the canonical way to call an extension function in a different class.
             // TODO(b/259469752): Use context receiver for this when it becomes stable.
             with(policy) { parseSystemState(state) }
         }
-    }
 
-    private fun readUserState(state: AccessState, userId: Int) {
-        getUserFile(userId).parse {
-            with(policy) { parseUserState(state, userId) }
+        if (!fileExists) {
+            policy.migrateSystemState(state)
+            state.systemState.apply {
+                requestWrite()
+                write(state, UserHandle.USER_ALL)
+            }
         }
     }
 
-    private inline fun File.parse(block: BinaryXmlPullParser.() -> Unit) {
+
+    private fun readUserState(state: AccessState, userId: Int) {
+        val fileExists = getUserFile(userId).parse {
+            with(policy) { parseUserState(state, userId) }
+        }
+
+        if (!fileExists) {
+            policy.migrateUserState(state, userId)
+            state.userStates[userId].apply {
+                requestWrite()
+                write(state, userId)
+            }
+        }
+    }
+
+    /**
+     * @return {@code true} if the file is successfully read from the disk; {@code false} if
+     * the file doesn't exist yet.
+     */
+    private inline fun File.parse(block: BinaryXmlPullParser.() -> Unit): Boolean =
         try {
             AtomicFile(this).read { it.parseBinaryXml(block) }
+            true
         } catch (e: FileNotFoundException) {
             Log.i(LOG_TAG, "$this not found")
+            false
         } catch (e: Exception) {
             throw IllegalStateException("Failed to read $this", e)
         }
-    }
 
     fun write(state: AccessState) {
         state.systemState.write(state, UserHandle.USER_ALL)
diff --git a/services/permission/java/com/android/server/permission/access/AccessPolicy.kt b/services/permission/java/com/android/server/permission/access/AccessPolicy.kt
index 07a5e72..f453e79 100644
--- a/services/permission/java/com/android/server/permission/access/AccessPolicy.kt
+++ b/services/permission/java/com/android/server/permission/access/AccessPolicy.kt
@@ -21,9 +21,9 @@
 import com.android.modules.utils.BinaryXmlSerializer
 import com.android.server.SystemConfig
 import com.android.server.permission.access.appop.PackageAppOpPolicy
-import com.android.server.permission.access.appop.UidAppOpPolicy
+import com.android.server.permission.access.appop.AppIdAppOpPolicy
 import com.android.server.permission.access.collection.* // ktlint-disable no-wildcard-imports
-import com.android.server.permission.access.permission.UidPermissionPolicy
+import com.android.server.permission.access.permission.AppIdPermissionPolicy
 import com.android.server.permission.access.util.forEachTag
 import com.android.server.permission.access.util.tag
 import com.android.server.permission.access.util.tagName
@@ -37,8 +37,8 @@
         IndexedMap<String, IndexedMap<String, SchemePolicy>>().apply {
             fun addPolicy(policy: SchemePolicy) =
                 getOrPut(policy.subjectScheme) { IndexedMap() }.put(policy.objectScheme, policy)
-            addPolicy(UidPermissionPolicy())
-            addPolicy(UidAppOpPolicy())
+            addPolicy(AppIdPermissionPolicy())
+            addPolicy(AppIdAppOpPolicy())
             addPolicy(PackageAppOpPolicy())
         }
     )
@@ -262,6 +262,19 @@
         }
     }
 
+    fun migrateSystemState(state: AccessState) {
+        forEachSchemePolicy {
+            with(it) { migrateSystemState(state) }
+        }
+    }
+
+    fun migrateUserState(state: AccessState, userId: Int) {
+        forEachSchemePolicy {
+            with(it) { migrateUserState(state, userId) }
+        }
+    }
+
+
     fun BinaryXmlPullParser.parseSystemState(state: AccessState) {
         forEachTag {
             when (tagName) {
@@ -371,6 +384,10 @@
 
     open fun MutateStateScope.onSystemReady() {}
 
+    open fun migrateSystemState(state: AccessState) {}
+
+    open fun migrateUserState(state: AccessState, userId: Int) {}
+
     open fun BinaryXmlPullParser.parseSystemState(state: AccessState) {}
 
     open fun BinaryXmlSerializer.serializeSystemState(state: AccessState) {}
diff --git a/services/permission/java/com/android/server/permission/access/AccessState.kt b/services/permission/java/com/android/server/permission/access/AccessState.kt
index 5532311..0b4d6e9 100644
--- a/services/permission/java/com/android/server/permission/access/AccessState.kt
+++ b/services/permission/java/com/android/server/permission/access/AccessState.kt
@@ -98,9 +98,9 @@
 
 class UserState private constructor(
     // A map of (appId to a map of (permissionName to permissionFlags))
-    val uidPermissionFlags: IntMap<IndexedMap<String, Int>>,
+    val appIdPermissionFlags: IntMap<IndexedMap<String, Int>>,
     // appId -> opName -> opCode
-    val uidAppOpModes: IntMap<IndexedMap<String, Int>>,
+    val appIdAppOpModes: IntMap<IndexedMap<String, Int>>,
     // packageName -> opName -> opCode
     val packageAppOpModes: IndexedMap<String, IndexedMap<String, Int>>
 ) : WritableState() {
@@ -111,8 +111,8 @@
     )
 
     fun copy(): UserState = UserState(
-        uidPermissionFlags.copy { it.copy { it } },
-        uidAppOpModes.copy { it.copy { it } },
+        appIdPermissionFlags.copy { it.copy { it } },
+        appIdAppOpModes.copy { it.copy { it } },
         packageAppOpModes.copy { it.copy { it } }
     )
 }
diff --git a/services/permission/java/com/android/server/permission/access/appop/UidAppOpPersistence.kt b/services/permission/java/com/android/server/permission/access/appop/AppIdAppOpPersistence.kt
similarity index 79%
rename from services/permission/java/com/android/server/permission/access/appop/UidAppOpPersistence.kt
rename to services/permission/java/com/android/server/permission/access/appop/AppIdAppOpPersistence.kt
index 7a965d4..c29f30c8 100644
--- a/services/permission/java/com/android/server/permission/access/appop/UidAppOpPersistence.kt
+++ b/services/permission/java/com/android/server/permission/access/appop/AppIdAppOpPersistence.kt
@@ -28,15 +28,15 @@
 import com.android.server.permission.access.util.tag
 import com.android.server.permission.access.util.tagName
 
-class UidAppOpPersistence : BaseAppOpPersistence() {
+class AppIdAppOpPersistence : BaseAppOpPersistence() {
     override fun BinaryXmlPullParser.parseUserState(state: AccessState, userId: Int) {
         when (tagName) {
-            TAG_UID_APP_OPS -> parseUidAppOps(state, userId)
+            TAG_APP_ID_APP_OPS -> parseAppIdAppOps(state, userId)
             else -> {}
         }
     }
 
-    private fun BinaryXmlPullParser.parseUidAppOps(state: AccessState, userId: Int) {
+    private fun BinaryXmlPullParser.parseAppIdAppOps(state: AccessState, userId: Int) {
         val userState = state.userStates[userId]
         forEachTag {
             when (tagName) {
@@ -44,7 +44,7 @@
                 else -> Log.w(LOG_TAG, "Ignoring unknown tag $name when parsing app-op state")
             }
         }
-        userState.uidAppOpModes.retainAllIndexed { _, appId, _ ->
+        userState.appIdAppOpModes.retainAllIndexed { _, appId, _ ->
             val hasAppId = appId in state.systemState.appIds
             if (!hasAppId) {
                 Log.w(LOG_TAG, "Dropping unknown app ID $appId when parsing app-op state")
@@ -56,17 +56,17 @@
     private fun BinaryXmlPullParser.parseAppId(userState: UserState) {
         val appId = getAttributeIntOrThrow(ATTR_ID)
         val appOpModes = IndexedMap<String, Int>()
-        userState.uidAppOpModes[appId] = appOpModes
+        userState.appIdAppOpModes[appId] = appOpModes
         parseAppOps(appOpModes)
     }
 
     override fun BinaryXmlSerializer.serializeUserState(state: AccessState, userId: Int) {
-        serializeUidAppOps(state.userStates[userId])
+        serializeAppIdAppOps(state.userStates[userId])
     }
 
-    private fun BinaryXmlSerializer.serializeUidAppOps(userState: UserState) {
-        tag(TAG_UID_APP_OPS) {
-            userState.uidAppOpModes.forEachIndexed { _, appId, appOpModes ->
+    private fun BinaryXmlSerializer.serializeAppIdAppOps(userState: UserState) {
+        tag(TAG_APP_ID_APP_OPS) {
+            userState.appIdAppOpModes.forEachIndexed { _, appId, appOpModes ->
                 serializeAppId(appId, appOpModes)
             }
         }
@@ -83,10 +83,10 @@
     }
 
     companion object {
-        private val LOG_TAG = UidAppOpPersistence::class.java.simpleName
+        private val LOG_TAG = AppIdAppOpPersistence::class.java.simpleName
 
         private const val TAG_APP_ID = "app-id"
-        private const val TAG_UID_APP_OPS = "uid-app-ops"
+        private const val TAG_APP_ID_APP_OPS = "app-id-app-ops"
 
         private const val ATTR_ID = "id"
     }
diff --git a/services/permission/java/com/android/server/permission/access/appop/UidAppOpPolicy.kt b/services/permission/java/com/android/server/permission/access/appop/AppIdAppOpPolicy.kt
similarity index 90%
rename from services/permission/java/com/android/server/permission/access/appop/UidAppOpPolicy.kt
rename to services/permission/java/com/android/server/permission/access/appop/AppIdAppOpPolicy.kt
index 0ba9a1e..5a2522e 100644
--- a/services/permission/java/com/android/server/permission/access/appop/UidAppOpPolicy.kt
+++ b/services/permission/java/com/android/server/permission/access/appop/AppIdAppOpPolicy.kt
@@ -24,7 +24,7 @@
 import com.android.server.permission.access.UidUri
 import com.android.server.permission.access.collection.* // ktlint-disable no-wildcard-imports
 
-class UidAppOpPolicy : BaseAppOpPolicy(UidAppOpPersistence()) {
+class AppIdAppOpPolicy : BaseAppOpPolicy(AppIdAppOpPersistence()) {
     @Volatile
     private var onAppOpModeChangedListeners = IndexedListSet<OnAppOpModeChangedListener>()
     private val onAppOpModeChangedListenersLock = Any()
@@ -54,18 +54,18 @@
 
     override fun MutateStateScope.onAppIdRemoved(appId: Int) {
         newState.userStates.forEachIndexed { _, _, userState ->
-            userState.uidAppOpModes -= appId
+            userState.appIdAppOpModes -= appId
             userState.requestWrite()
             // Skip notifying the change listeners since the app ID no longer exists.
         }
     }
 
     fun GetStateScope.getAppOpModes(appId: Int, userId: Int): IndexedMap<String, Int>? =
-        state.userStates[userId].uidAppOpModes[appId]
+        state.userStates[userId].appIdAppOpModes[appId]
 
     fun MutateStateScope.removeAppOpModes(appId: Int, userId: Int): Boolean {
         val userState = newState.userStates[userId]
-        val isChanged = userState.uidAppOpModes.removeReturnOld(appId) != null
+        val isChanged = userState.appIdAppOpModes.removeReturnOld(appId) != null
         if (isChanged) {
             userState.requestWrite()
         }
@@ -73,7 +73,7 @@
     }
 
     fun GetStateScope.getAppOpMode(appId: Int, userId: Int, appOpName: String): Int =
-        state.userStates[userId].uidAppOpModes[appId]
+        state.userStates[userId].appIdAppOpModes[appId]
             .getWithDefault(appOpName, AppOpsManager.opToDefaultMode(appOpName))
 
     fun MutateStateScope.setAppOpMode(
@@ -83,8 +83,8 @@
         mode: Int
     ): Boolean {
         val userState = newState.userStates[userId]
-        val uidAppOpModes = userState.uidAppOpModes
-        var appOpModes = uidAppOpModes[appId]
+        val appIdAppOpModes = userState.appIdAppOpModes
+        var appOpModes = appIdAppOpModes[appId]
         val defaultMode = AppOpsManager.opToDefaultMode(appOpName)
         val oldMode = appOpModes.getWithDefault(appOpName, defaultMode)
         if (oldMode == mode) {
@@ -92,11 +92,11 @@
         }
         if (appOpModes == null) {
             appOpModes = IndexedMap()
-            uidAppOpModes[appId] = appOpModes
+            appIdAppOpModes[appId] = appOpModes
         }
         appOpModes.putWithDefault(appOpName, mode, defaultMode)
         if (appOpModes.isEmpty()) {
-            uidAppOpModes -= appId
+            appIdAppOpModes -= appId
         }
         userState.requestWrite()
         onAppOpModeChangedListeners.forEachIndexed { _, it ->
diff --git a/services/permission/java/com/android/server/permission/access/appop/AppOpService.kt b/services/permission/java/com/android/server/permission/access/appop/AppOpService.kt
index af85eba..4caf6cc 100644
--- a/services/permission/java/com/android/server/permission/access/appop/AppOpService.kt
+++ b/services/permission/java/com/android/server/permission/access/appop/AppOpService.kt
@@ -47,7 +47,7 @@
     private val packagePolicy = service.getSchemePolicy(PackageUri.SCHEME, AppOpUri.SCHEME)
         as PackageAppOpPolicy
     private val uidPolicy = service.getSchemePolicy(UidUri.SCHEME, AppOpUri.SCHEME)
-        as UidAppOpPolicy
+        as AppIdAppOpPolicy
 
     private val context = service.context
     private lateinit var handler: Handler
diff --git a/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionMigration.kt b/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionMigration.kt
new file mode 100644
index 0000000..0a2fad9
--- /dev/null
+++ b/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionMigration.kt
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.permission.access.permission
+
+import android.util.Log
+import com.android.server.LocalServices
+import com.android.server.permission.access.AccessState
+import com.android.server.permission.access.collection.* // ktlint-disable no-wildcard-imports
+import com.android.server.pm.permission.PermissionMigrationHelper
+
+/**
+ * This class migrate legacy permissions to unified permission subsystem
+ */
+class AppIdPermissionMigration {
+    internal fun migrateSystemState(state: AccessState) {
+        val legacyPermissionsManager =
+            LocalServices.getService(PermissionMigrationHelper::class.java)!!
+        migratePermissions(state.systemState.permissions,
+            legacyPermissionsManager.legacyPermissions)
+        migratePermissions(state.systemState.permissionTrees,
+            legacyPermissionsManager.legacyPermissionTrees, true)
+    }
+
+    private fun migratePermissions(
+        permissions: IndexedMap<String, Permission>,
+        legacyPermissions: Map<String, PermissionMigrationHelper.LegacyPermission>,
+        isPermissionTree: Boolean = false
+    ) {
+        legacyPermissions.forEach { (_, legacyPermission) ->
+            val permission = Permission(
+                legacyPermission.permissionInfo, false, legacyPermission.type, 0
+            )
+            permissions[permission.name] = permission
+            if (DEBUG_MIGRATION) {
+                Log.v(LOG_TAG, "Migrated permission: ${permission.name}, type: " +
+                    "${permission.type}, appId: ${permission.appId}, protectionLevel: " +
+                    "${permission.protectionLevel}, tree: $isPermissionTree"
+                )
+            }
+        }
+    }
+
+    internal fun migrateUserState(state: AccessState, userId: Int) {
+        val legacyPermissionsManager =
+            LocalServices.getService(PermissionMigrationHelper::class.java)!!
+        val permissionStates = legacyPermissionsManager.getLegacyPermissionStates(userId)
+
+        permissionStates.forEach { (appId, permissionStates) ->
+            migratePermissionStates(appId, state, permissionStates, userId)
+        }
+    }
+
+    private fun migratePermissionStates(
+        appId: Int,
+        state: AccessState,
+        legacyPermissionStates: Map<String, PermissionMigrationHelper.LegacyPermissionState>,
+        userId: Int
+    ) {
+        val permissionFlags =
+            state.userStates[userId].appIdPermissionFlags.getOrPut(appId) { IndexedMap() }
+
+        legacyPermissionStates.forEach forEachPermission@ { (permissionName, permissionState) ->
+            val permission = state.systemState.permissions[permissionName]
+                ?: return@forEachPermission
+
+            var flags = when {
+                permission.isNormal -> if (permissionState.isGranted) {
+                    PermissionFlags.INSTALL_GRANTED
+                } else {
+                    PermissionFlags.INSTALL_REVOKED
+                }
+                permission.isSignature || permission.isInternal ->
+                    if (permissionState.isGranted) {
+                        if (permission.isDevelopment || permission.isRole) {
+                            PermissionFlags.PROTECTION_GRANTED or PermissionFlags.RUNTIME_GRANTED
+                        } else {
+                            PermissionFlags.PROTECTION_GRANTED
+                        }
+                    } else {
+                        0
+                    }
+                permission.isRuntime ->
+                    if (permissionState.isGranted) PermissionFlags.RUNTIME_GRANTED else 0
+                else -> 0
+            }
+            flags = PermissionFlags.updateFlags(
+                permission, flags, permissionState.flags, permissionState.flags
+            )
+            permissionFlags[permissionName] = flags
+
+            if (DEBUG_MIGRATION) {
+                val oldFlagString = PermissionFlags.apiFlagsToString(permissionState.flags)
+                val newFlagString = PermissionFlags.toString(flags)
+                val oldGrantState = permissionState.isGranted
+                val newGrantState = PermissionFlags.isPermissionGranted(flags)
+                val flagsMismatch = permissionState.flags != PermissionFlags.toApiFlags(flags)
+                Log.v(
+                    LOG_TAG, "Migrated appId: $appId, permission: " +
+                        "${permission.name}, user: $userId, oldGrantState: $oldGrantState" +
+                        ", oldFlags: $oldFlagString, newFlags: $newFlagString, grantMismatch: " +
+                        "${oldGrantState != newGrantState}, flagsMismatch: $flagsMismatch"
+                )
+            }
+        }
+    }
+
+    companion object {
+        private val LOG_TAG = AppIdPermissionMigration::class.java.simpleName
+
+        private const val DEBUG_MIGRATION = false
+    }
+}
diff --git a/services/permission/java/com/android/server/permission/access/permission/UidPermissionPersistence.kt b/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPersistence.kt
similarity index 86%
rename from services/permission/java/com/android/server/permission/access/permission/UidPermissionPersistence.kt
rename to services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPersistence.kt
index 35cdbce..552dda1 100644
--- a/services/permission/java/com/android/server/permission/access/permission/UidPermissionPersistence.kt
+++ b/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPersistence.kt
@@ -37,7 +37,7 @@
 import com.android.server.permission.access.util.tag
 import com.android.server.permission.access.util.tagName
 
-class UidPermissionPersistence {
+class AppIdPermissionPersistence {
     fun BinaryXmlPullParser.parseSystemState(state: AccessState) {
         val systemState = state.systemState
         when (tagName) {
@@ -126,12 +126,12 @@
 
     fun BinaryXmlPullParser.parseUserState(state: AccessState, userId: Int) {
         when (tagName) {
-            TAG_PERMISSIONS -> parsePermissionFlags(state, userId)
+            TAG_APP_ID_PERMISSIONS -> parseAppIdPermissions(state, userId)
             else -> {}
         }
     }
 
-    private fun BinaryXmlPullParser.parsePermissionFlags(state: AccessState, userId: Int) {
+    private fun BinaryXmlPullParser.parseAppIdPermissions(state: AccessState, userId: Int) {
         val userState = state.userStates[userId]
         forEachTag {
             when (tagName) {
@@ -139,7 +139,7 @@
                 else -> Log.w(LOG_TAG, "Ignoring unknown tag $name when parsing permission state")
             }
         }
-        userState.uidPermissionFlags.retainAllIndexed { _, appId, _ ->
+        userState.appIdPermissionFlags.retainAllIndexed { _, appId, _ ->
             val hasAppId = appId in state.systemState.appIds
             if (!hasAppId) {
                 Log.w(LOG_TAG, "Dropping unknown app ID $appId when parsing permission state")
@@ -151,34 +151,34 @@
     private fun BinaryXmlPullParser.parseAppId(userState: UserState) {
         val appId = getAttributeIntOrThrow(ATTR_ID)
         val permissionFlags = IndexedMap<String, Int>()
-        userState.uidPermissionFlags[appId] = permissionFlags
-        parseAppIdPermissions(permissionFlags)
+        userState.appIdPermissionFlags[appId] = permissionFlags
+        parsePermissionStates(permissionFlags)
     }
 
-    private fun BinaryXmlPullParser.parseAppIdPermissions(
+    private fun BinaryXmlPullParser.parsePermissionStates(
         permissionFlags: IndexedMap<String, Int>
     ) {
         forEachTag {
             when (tagName) {
-                TAG_PERMISSION -> parseAppIdPermission(permissionFlags)
+                TAG_PERMISSION -> parsePermissionState(permissionFlags)
                 else -> Log.w(LOG_TAG, "Ignoring unknown tag $name when parsing permission state")
             }
         }
     }
 
-    private fun BinaryXmlPullParser.parseAppIdPermission(permissionFlags: IndexedMap<String, Int>) {
+    private fun BinaryXmlPullParser.parsePermissionState(permissionFlags: IndexedMap<String, Int>) {
         val name = getAttributeValueOrThrow(ATTR_NAME).intern()
         val flags = getAttributeIntOrThrow(ATTR_FLAGS)
         permissionFlags[name] = flags
     }
 
     fun BinaryXmlSerializer.serializeUserState(state: AccessState, userId: Int) {
-        serializePermissionFlags(state.userStates[userId])
+        serializeAppIdPermissions(state.userStates[userId])
     }
 
-    private fun BinaryXmlSerializer.serializePermissionFlags(userState: UserState) {
-        tag(TAG_PERMISSIONS) {
-            userState.uidPermissionFlags.forEachIndexed { _, appId, permissionFlags ->
+    private fun BinaryXmlSerializer.serializeAppIdPermissions(userState: UserState) {
+        tag(TAG_APP_ID_PERMISSIONS) {
+            userState.appIdPermissionFlags.forEachIndexed { _, appId, permissionFlags ->
                 serializeAppId(appId, permissionFlags)
             }
         }
@@ -190,19 +190,19 @@
     ) {
         tag(TAG_APP_ID) {
             attributeInt(ATTR_ID, appId)
-            serializeAppIdPermissions(permissionFlags)
+            serializePermissionStates(permissionFlags)
         }
     }
 
-    private fun BinaryXmlSerializer.serializeAppIdPermissions(
+    private fun BinaryXmlSerializer.serializePermissionStates(
         permissionFlags: IndexedMap<String, Int>
     ) {
         permissionFlags.forEachIndexed { _, name, flags ->
-            serializeAppIdPermission(name, flags)
+            serializePermissionState(name, flags)
         }
     }
 
-    private fun BinaryXmlSerializer.serializeAppIdPermission(name: String, flags: Int) {
+    private fun BinaryXmlSerializer.serializePermissionState(name: String, flags: Int) {
         tag(TAG_PERMISSION) {
             attributeInterned(ATTR_NAME, name)
             attributeInt(ATTR_FLAGS, flags)
@@ -210,9 +210,10 @@
     }
 
     companion object {
-        private val LOG_TAG = UidPermissionPersistence::class.java.simpleName
+        private val LOG_TAG = AppIdPermissionPersistence::class.java.simpleName
 
         private const val TAG_APP_ID = "app-id"
+        private const val TAG_APP_ID_PERMISSIONS = "app-id-permissions"
         private const val TAG_PERMISSION = "permission"
         private const val TAG_PERMISSIONS = "permissions"
         private const val TAG_PERMISSION_TREES = "permission-trees"
diff --git a/services/permission/java/com/android/server/permission/access/permission/UidPermissionPolicy.kt b/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt
similarity index 97%
rename from services/permission/java/com/android/server/permission/access/permission/UidPermissionPolicy.kt
rename to services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt
index 5a7b37a..6673dc6 100644
--- a/services/permission/java/com/android/server/permission/access/permission/UidPermissionPolicy.kt
+++ b/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt
@@ -45,8 +45,10 @@
 import com.android.server.pm.pkg.AndroidPackage
 import com.android.server.pm.pkg.PackageState
 
-class UidPermissionPolicy : SchemePolicy() {
-    private val persistence = UidPermissionPersistence()
+class AppIdPermissionPolicy : SchemePolicy() {
+    private val persistence = AppIdPermissionPersistence()
+
+    private val migration = AppIdPermissionMigration()
 
     @Volatile
     private var onPermissionFlagsChangedListeners =
@@ -124,7 +126,7 @@
 
     override fun MutateStateScope.onAppIdRemoved(appId: Int) {
         newState.userStates.forEachValueIndexed { _, userState ->
-            userState.uidPermissionFlags -= appId
+            userState.appIdPermissionFlags -= appId
             userState.requestWrite()
             // Skip notifying the change listeners since the app ID no longer exists.
         }
@@ -209,16 +211,15 @@
         appId: Int,
         userId: Int
     ) {
-        resetRuntimePermissions(packageName, appId, userId)
+        resetRuntimePermissions(packageName, userId)
     }
 
-    fun MutateStateScope.resetRuntimePermissions(
-        packageName: String,
-        appId: Int,
-        userId: Int
-    ) {
-        val androidPackage = newState.systemState.packageStates[packageName]?.androidPackage
-            ?: return
+    fun MutateStateScope.resetRuntimePermissions(packageName: String, userId: Int) {
+        // It's okay to skip resetting permissions for packages that are removed,
+        // because their states will be trimmed in onPackageRemoved()/onAppIdRemoved()
+        val packageState = newState.systemState.packageStates[packageName] ?: return
+        val androidPackage = packageState.androidPackage ?: return
+        val appId = packageState.appId
         androidPackage.requestedPermissions.forEachIndexed { _, permissionName ->
             val permission = newState.systemState.permissions[permissionName]
                 ?: return@forEachIndexed
@@ -446,7 +447,7 @@
                     return@forEachIndexed
                 }
             } else {
-                if (oldPermission != null) {
+                if (oldPermission != null && oldPermission.isReconciled) {
                     val isPermissionGroupChanged = newPermissionInfo.isRuntime &&
                         newPermissionInfo.group != null &&
                         newPermissionInfo.group != oldPermission.groupName
@@ -595,7 +596,7 @@
             requestedPermissions += it.androidPackage!!.requestedPermissions
         }
         newState.userStates.forEachIndexed { _, userId, userState ->
-            userState.uidPermissionFlags[appId]?.forEachReversedIndexed { _, permissionName, _ ->
+            userState.appIdPermissionFlags[appId]?.forEachReversedIndexed { _, permissionName, _ ->
                 if (permissionName !in requestedPermissions) {
                     setPermissionFlags(appId, userId, permissionName, 0)
                 }
@@ -607,7 +608,7 @@
         // If the app is updated, and has scoped storage permissions, then it is possible that the
         // app updated in an attempt to get unscoped storage. If so, revoke all storage permissions.
         newState.userStates.forEachIndexed { _, userId, userState ->
-            userState.uidPermissionFlags[appId]?.forEachReversedIndexed {
+            userState.appIdPermissionFlags[appId]?.forEachReversedIndexed {
                 _, permissionName, oldFlags ->
                 if (permissionName !in STORAGE_AND_MEDIA_PERMISSIONS || oldFlags == 0) {
                     return@forEachReversedIndexed
@@ -628,6 +629,8 @@
                     !oldIsRequestLegacyExternalStorage && newIsRequestLegacyExternalStorage
                 if ((isNewlyRequestingLegacyExternalStorage || isTargetSdkVersionDowngraded) &&
                     oldFlags.hasBits(PermissionFlags.RUNTIME_GRANTED)) {
+                    Log.v(LOG_TAG, "Revoking storage permission: $permissionName for appId: " +
+                            " $appId and user: $userId")
                     val newFlags = oldFlags andInv (
                         PermissionFlags.RUNTIME_GRANTED or USER_SETTABLE_MASK
                     )
@@ -1313,7 +1316,7 @@
     }
 
     fun GetStateScope.getUidPermissionFlags(appId: Int, userId: Int): IndexedMap<String, Int>? =
-        state.userStates[userId]?.uidPermissionFlags?.get(appId)
+        state.userStates[userId]?.appIdPermissionFlags?.get(appId)
 
     fun GetStateScope.getPermissionFlags(
         appId: Int,
@@ -1333,7 +1336,7 @@
         userId: Int,
         permissionName: String
     ): Int =
-        state.userStates[userId]?.uidPermissionFlags?.get(appId).getWithDefault(permissionName, 0)
+        state.userStates[userId]?.appIdPermissionFlags?.get(appId).getWithDefault(permissionName, 0)
 
     fun MutateStateScope.setPermissionFlags(
         appId: Int,
@@ -1351,8 +1354,8 @@
         flagValues: Int
     ): Boolean {
         val userState = newState.userStates[userId]
-        val uidPermissionFlags = userState.uidPermissionFlags
-        var permissionFlags = uidPermissionFlags[appId]
+        val appIdPermissionFlags = userState.appIdPermissionFlags
+        var permissionFlags = appIdPermissionFlags[appId]
         val oldFlags = permissionFlags.getWithDefault(permissionName, 0)
         val newFlags = (oldFlags andInv flagMask) or (flagValues and flagMask)
         if (oldFlags == newFlags) {
@@ -1360,11 +1363,11 @@
         }
         if (permissionFlags == null) {
             permissionFlags = IndexedMap()
-            uidPermissionFlags[appId] = permissionFlags
+            appIdPermissionFlags[appId] = permissionFlags
         }
         permissionFlags.putWithDefault(permissionName, newFlags, 0)
         if (permissionFlags.isEmpty()) {
-            uidPermissionFlags -= appId
+            appIdPermissionFlags -= appId
         }
         userState.requestWrite()
         onPermissionFlagsChangedListeners.forEachIndexed { _, it ->
@@ -1385,8 +1388,16 @@
         }
     }
 
+    override fun migrateSystemState(state: AccessState) {
+        migration.migrateSystemState(state)
+    }
+
+    override fun migrateUserState(state: AccessState, userId: Int) {
+        migration.migrateUserState(state, userId)
+    }
+
     companion object {
-        private val LOG_TAG = UidPermissionPolicy::class.java.simpleName
+        private val LOG_TAG = AppIdPermissionPolicy::class.java.simpleName
 
         private const val PLATFORM_PACKAGE_NAME = "android"
 
diff --git a/services/permission/java/com/android/server/permission/access/permission/PermissionFlags.kt b/services/permission/java/com/android/server/permission/access/permission/PermissionFlags.kt
index 48658ff..4b20472 100644
--- a/services/permission/java/com/android/server/permission/access/permission/PermissionFlags.kt
+++ b/services/permission/java/com/android/server/permission/access/permission/PermissionFlags.kt
@@ -22,6 +22,7 @@
 import android.os.Build
 import android.permission.PermissionManager
 import com.android.server.permission.access.util.andInv
+import com.android.server.permission.access.util.flagsToString
 import com.android.server.permission.access.util.hasAnyBit
 import com.android.server.permission.access.util.hasBits
 
@@ -137,7 +138,7 @@
      * For example, this flag may be set in
      * [com.android.server.pm.permission.DefaultPermissionGrantPolicy].
      *
-     * @see PackageManager.FLAG_PERMISSION_SYSTEM_FIXED
+     * @see PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT
      */
     const val PREGRANT = 1 shl 9
 
@@ -477,4 +478,38 @@
         }
         return flags
     }
+
+    fun flagToString(flag: Int): String =
+        when (flag) {
+            INSTALL_GRANTED -> "INSTALL_GRANTED"
+            INSTALL_REVOKED -> "INSTALL_REVOKED"
+            PROTECTION_GRANTED -> "PROTECTION_GRANTED"
+            ROLE -> "ROLE"
+            RUNTIME_GRANTED -> "RUNTIME_GRANTED"
+            USER_SET -> "USER_SET"
+            USER_FIXED -> "USER_FIXED"
+            POLICY_FIXED -> "POLICY_FIXED"
+            SYSTEM_FIXED -> "SYSTEM_FIXED"
+            PREGRANT -> "PREGRANT"
+            LEGACY_GRANTED -> "LEGACY_GRANTED"
+            IMPLICIT_GRANTED -> "IMPLICIT_GRANTED"
+            IMPLICIT -> "IMPLICIT"
+            USER_SENSITIVE_WHEN_GRANTED -> "USER_SENSITIVE_WHEN_GRANTED"
+            USER_SENSITIVE_WHEN_REVOKED -> "USER_SENSITIVE_WHEN_REVOKED"
+            INSTALLER_EXEMPT -> "INSTALLER_EXEMPT"
+            SYSTEM_EXEMPT -> "SYSTEM_EXEMPT"
+            UPGRADE_EXEMPT -> "UPGRADE_EXEMPT"
+            RESTRICTION_REVOKED -> "RESTRICTION_REVOKED"
+            SOFT_RESTRICTED -> "SOFT_RESTRICTED"
+            APP_OP_REVOKED -> "APP_OP_REVOKED"
+            ONE_TIME -> "ONE_TIME"
+            HIBERNATION -> "HIBERNATION"
+            USER_SELECTED -> "USER_SELECTED"
+            else -> "0x${flag.toUInt().toString(16).uppercase()}"
+        }
+
+    fun toString(flags: Int): String = flags.flagsToString { flagToString(it) }
+
+    fun apiFlagsToString(apiFlags: Int): String =
+        apiFlags.flagsToString { PackageManager.permissionFlagToString(it) }
 }
diff --git a/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt b/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt
index de7dc3b..9b69362 100644
--- a/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt
+++ b/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt
@@ -65,7 +65,7 @@
 import com.android.server.permission.access.MutateStateScope
 import com.android.server.permission.access.PermissionUri
 import com.android.server.permission.access.UidUri
-import com.android.server.permission.access.appop.UidAppOpPolicy
+import com.android.server.permission.access.appop.AppIdAppOpPolicy
 import com.android.server.permission.access.collection.* // ktlint-disable no-wildcard-imports
 import com.android.server.permission.access.util.andInv
 import com.android.server.permission.access.util.hasAnyBit
@@ -101,7 +101,7 @@
     private val service: AccessCheckingService
 ) : PermissionManagerServiceInterface {
     private val policy =
-        service.getSchemePolicy(UidUri.SCHEME, PermissionUri.SCHEME) as UidPermissionPolicy
+        service.getSchemePolicy(UidUri.SCHEME, PermissionUri.SCHEME) as AppIdPermissionPolicy
 
     private val context = service.context
     private lateinit var metricsLogger: MetricsLogger
@@ -930,7 +930,8 @@
         permissionName: String,
         isGranted: Boolean
     ) {
-        val appOpPolicy = service.getSchemePolicy(UidUri.SCHEME, AppOpUri.SCHEME) as UidAppOpPolicy
+        val appOpPolicy = service.getSchemePolicy(UidUri.SCHEME, AppOpUri.SCHEME) as
+            AppIdAppOpPolicy
         val appOpName = AppOpsManager.permissionToOp(permissionName)
         val mode = if (isGranted) AppOpsManager.MODE_ALLOWED else AppOpsManager.MODE_ERRORED
         with(appOpPolicy) { setAppOpMode(packageState.appId, userId, appOpName, mode) }
@@ -1600,11 +1601,23 @@
     }
 
     override fun resetRuntimePermissions(androidPackage: AndroidPackage, userId: Int) {
-        // TODO("Not yet implemented")
+        service.mutateState {
+            with(policy) {
+                resetRuntimePermissions(androidPackage.packageName, userId)
+            }
+        }
     }
 
     override fun resetRuntimePermissionsForUser(userId: Int) {
-        // TODO("Not yet implemented")
+        packageManagerLocal.withUnfilteredSnapshot().use { snapshot ->
+            service.mutateState {
+                snapshot.packageStates.forEach { (_, packageState) ->
+                    with(policy) {
+                        resetRuntimePermissions(packageState.packageName, userId)
+                    }
+                }
+            }
+        }
     }
 
     override fun addOnPermissionsChangeListener(listener: IOnPermissionsChangeListener) {
@@ -2090,7 +2103,7 @@
      * Callback invoked when interesting actions have been taken on a permission.
      */
     private inner class OnPermissionFlagsChangedListener :
-        UidPermissionPolicy.OnPermissionFlagsChangedListener() {
+        AppIdPermissionPolicy.OnPermissionFlagsChangedListener() {
         private var isPermissionFlagsChanged = false
 
         private val runtimePermissionChangedUids = IntSet()
diff --git a/services/permission/java/com/android/server/permission/access/util/IntExtensions.kt b/services/permission/java/com/android/server/permission/access/util/IntExtensions.kt
index e71d7a1..bc3328c 100644
--- a/services/permission/java/com/android/server/permission/access/util/IntExtensions.kt
+++ b/services/permission/java/com/android/server/permission/access/util/IntExtensions.kt
@@ -21,3 +21,19 @@
 fun Int.hasBits(bits: Int): Boolean = this and bits == bits
 
 infix fun Int.andInv(other: Int): Int = this and other.inv()
+
+inline fun Int.flagsToString(flagToString: (Int) -> String): String {
+    var flags = this
+    return buildString {
+        append("[")
+        while (flags != 0) {
+            val flag = 1 shl flags.countTrailingZeroBits()
+            flags = flags andInv flag
+            append(flagToString(flag))
+            if (flags != 0) {
+                append('|')
+            }
+        }
+        append("]")
+    }
+}
diff --git a/services/tests/PackageManagerServiceTests/server/Android.bp b/services/tests/PackageManagerServiceTests/server/Android.bp
index e711cab..c76af47 100644
--- a/services/tests/PackageManagerServiceTests/server/Android.bp
+++ b/services/tests/PackageManagerServiceTests/server/Android.bp
@@ -43,7 +43,6 @@
         "ShortcutManagerTestUtils",
         "truth-prebuilt",
         "testables",
-        "ub-uiautomator",
         "platformprotosnano",
         "framework-protos",
         "hamcrest-library",
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/AppsFilterImplTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/AppsFilterImplTest.java
index 7909ba4..d5cd6ef9 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/AppsFilterImplTest.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/AppsFilterImplTest.java
@@ -224,7 +224,6 @@
 
         MockitoAnnotations.initMocks(this);
         when(mSnapshot.getPackageStates()).thenAnswer(x -> mExisting);
-        when(mSnapshot.getAllSharedUsers()).thenReturn(mSharedUserSettings);
         when(mSnapshot.getUserInfos()).thenReturn(USER_INFO_LIST);
         when(mSnapshot.getSharedUser(anyInt())).thenAnswer(invocation -> {
             final int sharedUserAppId = invocation.getArgument(0);
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/CachedAppOptimizerTest.java b/services/tests/mockingservicestests/src/com/android/server/am/CachedAppOptimizerTest.java
index ec9e5b5..1fbb8dd 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/CachedAppOptimizerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/CachedAppOptimizerTest.java
@@ -19,7 +19,6 @@
 import static android.app.ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
 
 import static com.android.server.am.ActivityManagerService.Injector;
-import static com.android.server.am.CachedAppOptimizer.compactActionIntToAction;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -155,12 +154,6 @@
         synchronized (mCachedAppOptimizerUnderTest.mPhenotypeFlagLock) {
             assertThat(mCachedAppOptimizerUnderTest.useCompaction()).isEqualTo(
                     CachedAppOptimizer.DEFAULT_USE_COMPACTION);
-            assertThat(mCachedAppOptimizerUnderTest.mCompactActionSome)
-                    .isEqualTo(
-                            compactActionIntToAction(CachedAppOptimizer.DEFAULT_COMPACT_ACTION_1));
-            assertThat(mCachedAppOptimizerUnderTest.mCompactActionFull)
-                    .isEqualTo(
-                            compactActionIntToAction(CachedAppOptimizer.DEFAULT_COMPACT_ACTION_2));
             assertThat(mCachedAppOptimizerUnderTest.mCompactThrottleSomeSome).isEqualTo(
                     CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_1);
             assertThat(mCachedAppOptimizerUnderTest.mCompactThrottleSomeFull).isEqualTo(
@@ -210,12 +203,6 @@
         DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
                 CachedAppOptimizer.KEY_USE_COMPACTION, "true", false);
         DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
-                CachedAppOptimizer.KEY_COMPACT_ACTION_1,
-                Integer.toString((CachedAppOptimizer.DEFAULT_COMPACT_ACTION_1 + 1 % 4) + 1), false);
-        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
-                CachedAppOptimizer.KEY_COMPACT_ACTION_2,
-                Integer.toString((CachedAppOptimizer.DEFAULT_COMPACT_ACTION_2 + 1 % 4) + 1), false);
-        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
                 CachedAppOptimizer.KEY_COMPACT_THROTTLE_1,
                 Long.toString(CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_1 + 1), false);
         DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
@@ -266,12 +253,6 @@
         assertThat(mCachedAppOptimizerUnderTest.useCompaction()).isTrue();
         assertThat(mCachedAppOptimizerUnderTest.mCachedAppOptimizerThread.isAlive()).isTrue();
 
-        assertThat(mCachedAppOptimizerUnderTest.mCompactActionSome)
-                .isEqualTo(compactActionIntToAction(
-                        (CachedAppOptimizer.DEFAULT_COMPACT_ACTION_1 + 1 % 4) + 1));
-        assertThat(mCachedAppOptimizerUnderTest.mCompactActionFull)
-                .isEqualTo(compactActionIntToAction(
-                        (CachedAppOptimizer.DEFAULT_COMPACT_ACTION_2 + 1 % 4) + 1));
         assertThat(mCachedAppOptimizerUnderTest.mCompactThrottleSomeSome).isEqualTo(
                 CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_1 + 1);
         assertThat(mCachedAppOptimizerUnderTest.mCompactThrottleSomeFull).isEqualTo(
@@ -404,72 +385,6 @@
     }
 
     @Test
-    public void compactAction_listensToDeviceConfigChanges() throws InterruptedException {
-        mCachedAppOptimizerUnderTest.init();
-
-        // When we override new values for the compaction action with reasonable values...
-
-        // There are four possible values for compactAction[Some|Full].
-        for (int i = 1; i < 5; i++) {
-            mCountDown = new CountDownLatch(2);
-            int expectedSome = (CachedAppOptimizer.DEFAULT_COMPACT_ACTION_1 + i) % 4 + 1;
-            DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
-                    CachedAppOptimizer.KEY_COMPACT_ACTION_1, Integer.toString(expectedSome), false);
-            int expectedFull = (CachedAppOptimizer.DEFAULT_COMPACT_ACTION_2 + i) % 4 + 1;
-            DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
-                    CachedAppOptimizer.KEY_COMPACT_ACTION_2, Integer.toString(expectedFull), false);
-            assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue();
-
-            // Then the updates are reflected in the flags.
-            synchronized (mCachedAppOptimizerUnderTest.mPhenotypeFlagLock) {
-                assertThat(mCachedAppOptimizerUnderTest.mCompactActionSome)
-                        .isEqualTo(compactActionIntToAction(expectedSome));
-                assertThat(mCachedAppOptimizerUnderTest.mCompactActionFull)
-                        .isEqualTo(compactActionIntToAction(expectedFull));
-            }
-        }
-    }
-
-    @Test
-    public void compactAction_listensToDeviceConfigChangesBadValues() throws InterruptedException {
-        mCachedAppOptimizerUnderTest.init();
-
-        // When we override new values for the compaction action with bad values ...
-        mCountDown = new CountDownLatch(2);
-        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
-                CachedAppOptimizer.KEY_COMPACT_ACTION_1, "foo", false);
-        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
-                CachedAppOptimizer.KEY_COMPACT_ACTION_2, "foo", false);
-        assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue();
-
-        synchronized (mCachedAppOptimizerUnderTest.mPhenotypeFlagLock) {
-            // Then the default values are reflected in the flag
-            assertThat(mCachedAppOptimizerUnderTest.mCompactActionSome)
-                    .isEqualTo(
-                            compactActionIntToAction(CachedAppOptimizer.DEFAULT_COMPACT_ACTION_1));
-            assertThat(mCachedAppOptimizerUnderTest.mCompactActionFull)
-                    .isEqualTo(
-                            compactActionIntToAction(CachedAppOptimizer.DEFAULT_COMPACT_ACTION_2));
-        }
-
-        mCountDown = new CountDownLatch(2);
-        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
-                CachedAppOptimizer.KEY_COMPACT_ACTION_1, "", false);
-        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
-                CachedAppOptimizer.KEY_COMPACT_ACTION_2, "", false);
-        assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue();
-
-        synchronized (mCachedAppOptimizerUnderTest.mPhenotypeFlagLock) {
-            assertThat(mCachedAppOptimizerUnderTest.mCompactActionSome)
-                    .isEqualTo(
-                            compactActionIntToAction(CachedAppOptimizer.DEFAULT_COMPACT_ACTION_1));
-            assertThat(mCachedAppOptimizerUnderTest.mCompactActionFull)
-                    .isEqualTo(
-                            compactActionIntToAction(CachedAppOptimizer.DEFAULT_COMPACT_ACTION_2));
-        }
-    }
-
-    @Test
     public void compactThrottle_listensToDeviceConfigChanges() throws InterruptedException {
         mCachedAppOptimizerUnderTest.init();
 
@@ -1108,14 +1023,17 @@
 
         mCachedAppOptimizerUnderTest.mLastCompactionStats.clear();
 
-        // We force a some compaction
-        mCachedAppOptimizerUnderTest.compactApp(processRecord,
-                CachedAppOptimizer.CompactProfile.SOME, CachedAppOptimizer.CompactSource.APP, true);
-        waitForHandler();
-        // then process is compacted.
-        CachedAppOptimizer.CompactProfile executedCompactProfile =
-                processRecord.mOptRecord.getLastCompactProfile();
-        assertThat(executedCompactProfile).isEqualTo(CachedAppOptimizer.CompactProfile.SOME);
+        if (CachedAppOptimizer.ENABLE_FILE_COMPACT) {
+            // We force a some compaction
+            mCachedAppOptimizerUnderTest.compactApp(processRecord,
+                    CachedAppOptimizer.CompactProfile.SOME, CachedAppOptimizer.CompactSource.APP,
+                    true);
+            waitForHandler();
+            // then process is compacted.
+            CachedAppOptimizer.CompactProfile executedCompactProfile =
+                    processRecord.mOptRecord.getLastCompactProfile();
+            assertThat(executedCompactProfile).isEqualTo(CachedAppOptimizer.CompactProfile.SOME);
+        }
     }
 
     private void setFlag(String key, String value, boolean defaultValue) throws Exception {
@@ -1192,7 +1110,7 @@
         }
 
         @Override
-        public void performCompaction(CachedAppOptimizer.CompactAction action, int pid)
+        public void performCompaction(CachedAppOptimizer.CompactProfile profile, int pid)
                 throws IOException {
             mRss = mRssAfterCompaction;
         }
diff --git a/services/tests/mockingservicestests/src/com/android/server/cpu/CpuInfoReaderTest.java b/services/tests/mockingservicestests/src/com/android/server/cpu/CpuInfoReaderTest.java
index b214787..04f6f8b 100644
--- a/services/tests/mockingservicestests/src/com/android/server/cpu/CpuInfoReaderTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/cpu/CpuInfoReaderTest.java
@@ -92,6 +92,7 @@
         expectedCpuInfos.append(0, new CpuInfoReader.CpuInfo(/* cpuCore= */ 0,
                 FLAG_CPUSET_CATEGORY_TOP_APP, /* isOnline= */ true, /* curCpuFreqKHz= */ 1_230_000,
                 /* maxCpuFreqKHz= */ 2_500_000, /* avgTimeInStateCpuFreqKHz= */ 488_095,
+                /* normalizedAvailableCpuFreqKHz= */ 2_402_267,
                 new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 32_249_610,
                         /* niceTimeMillis= */ 7_950_930, /* systemTimeMillis= */ 52_227_050,
                         /* idleTimeMillis= */ 409_036_950, /* iowaitTimeMillis= */ 1_322_810,
@@ -101,6 +102,7 @@
         expectedCpuInfos.append(1, new CpuInfoReader.CpuInfo(/* cpuCore= */ 1,
                 FLAG_CPUSET_CATEGORY_TOP_APP, /* isOnline= */ true, /* curCpuFreqKHz= */ 1_450_000,
                 /* maxCpuFreqKHz= */ 2_800_000, /* avgTimeInStateCpuFreqKHz= */ 502_380,
+                /* normalizedAvailableCpuFreqKHz= */ 2_693_525,
                 new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 28_949_280,
                         /* niceTimeMillis= */ 7_799_450, /* systemTimeMillis= */ 54_004_020,
                         /* idleTimeMillis= */ 402_707_120, /* iowaitTimeMillis= */ 1_186_960,
@@ -111,6 +113,7 @@
                 FLAG_CPUSET_CATEGORY_TOP_APP | FLAG_CPUSET_CATEGORY_BACKGROUND,
                 /* isOnline= */ true, /* curCpuFreqKHz= */ 1_000_000,
                 /* maxCpuFreqKHz= */ 2_000_000, /* avgTimeInStateCpuFreqKHz= */ 464_285,
+                /* normalizedAvailableCpuFreqKHz= */ 1_901_608,
                 new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 28_959_280,
                         /* niceTimeMillis= */ 7_789_450, /* systemTimeMillis= */ 54_014_020,
                         /* idleTimeMillis= */ 402_717_120, /* iowaitTimeMillis= */ 1_166_960,
@@ -121,6 +124,7 @@
                 FLAG_CPUSET_CATEGORY_TOP_APP | FLAG_CPUSET_CATEGORY_BACKGROUND,
                 /* isOnline= */ true, /* curCpuFreqKHz= */ 1_000_000,
                 /* maxCpuFreqKHz= */ 2_000_000, /* avgTimeInStateCpuFreqKHz= */ 464_285,
+                /* normalizedAvailableCpuFreqKHz= */ 1_907_125,
                 new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 32_349_610,
                         /* niceTimeMillis= */ 7_850_930, /* systemTimeMillis= */ 52_127_050,
                         /* idleTimeMillis= */ 409_136_950, /* iowaitTimeMillis= */ 1_332_810,
@@ -139,6 +143,7 @@
         expectedCpuInfos.append(0, new CpuInfoReader.CpuInfo(/* cpuCore= */ 0,
                 FLAG_CPUSET_CATEGORY_TOP_APP, /* isOnline= */ true, /* curCpuFreqKHz= */ 1_000_000,
                 /* maxCpuFreqKHz= */ 2_500_000, /* avgTimeInStateCpuFreqKHz= */ 419_354,
+                /* normalizedAvailableCpuFreqKHz= */ 2_425_919,
                 new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 10_000_000,
                         /* niceTimeMillis= */ 1_000_000, /* systemTimeMillis= */ 10_000_000,
                         /* idleTimeMillis= */ 110_000_000, /* iowaitTimeMillis= */ 1_100_000,
@@ -148,6 +153,7 @@
         expectedCpuInfos.append(1, new CpuInfoReader.CpuInfo(/* cpuCore= */ 1,
                 FLAG_CPUSET_CATEGORY_TOP_APP, /* isOnline= */ true, /* curCpuFreqKHz= */ 2_800_000,
                 /* maxCpuFreqKHz= */ 2_800_000, /* avgTimeInStateCpuFreqKHz= */ 429_032,
+                /* normalizedAvailableCpuFreqKHz= */ 2_403_009,
                 new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 900_000,
                         /* niceTimeMillis= */ 1_000_000, /* systemTimeMillis= */ 10_000_000,
                         /* idleTimeMillis= */ 1_000_000, /* iowaitTimeMillis= */ 90_000,
@@ -158,6 +164,7 @@
                 FLAG_CPUSET_CATEGORY_TOP_APP | FLAG_CPUSET_CATEGORY_BACKGROUND,
                 /* isOnline= */ true, /* curCpuFreqKHz= */ 2_000_000,
                 /* maxCpuFreqKHz= */ 2_000_000, /* avgTimeInStateCpuFreqKHz= */ 403_225,
+                /* normalizedAvailableCpuFreqKHz= */ 1_688_209,
                 new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 10_000_000,
                         /* niceTimeMillis= */ 2_000_000, /* systemTimeMillis= */ 0,
                         /* idleTimeMillis= */ 10_000_000, /* iowaitTimeMillis= */ 1_000_000,
@@ -168,6 +175,7 @@
                 FLAG_CPUSET_CATEGORY_TOP_APP | FLAG_CPUSET_CATEGORY_BACKGROUND,
                 /* isOnline= */ false, /* curCpuFreqKHz= */ MISSING_FREQUENCY,
                 /* maxCpuFreqKHz= */ 2_000_000, /* avgTimeInStateCpuFreqKHz= */ MISSING_FREQUENCY,
+                /* normalizedAvailableCpuFreqKHz= */ MISSING_FREQUENCY,
                 new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 2_000_000,
                         /* niceTimeMillis= */ 1_000_000, /* systemTimeMillis= */ 1_000_000,
                         /* idleTimeMillis= */ 100_000, /* iowaitTimeMillis= */ 100_000,
@@ -189,6 +197,7 @@
         expectedCpuInfos.append(0, new CpuInfoReader.CpuInfo(/* cpuCore= */ 0,
                 FLAG_CPUSET_CATEGORY_TOP_APP, /* isOnline= */ true, /* curCpuFreqKHz= */ 1_230_000,
                 /* maxCpuFreqKHz= */ 2_500_000, /* avgTimeInStateCpuFreqKHz= */ MISSING_FREQUENCY,
+                /* normalizedAvailableCpuFreqKHz= */ 2_253_713,
                 new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 32_249_610,
                         /* niceTimeMillis= */ 7_950_930, /* systemTimeMillis= */ 52_227_050,
                         /* idleTimeMillis= */ 409_036_950, /* iowaitTimeMillis= */ 1_322_810,
@@ -198,6 +207,7 @@
         expectedCpuInfos.append(1, new CpuInfoReader.CpuInfo(/* cpuCore= */ 1,
                 FLAG_CPUSET_CATEGORY_TOP_APP, /* isOnline= */ true, /* curCpuFreqKHz= */ 1_450_000,
                 /* maxCpuFreqKHz= */ 2_800_000, /* avgTimeInStateCpuFreqKHz= */ MISSING_FREQUENCY,
+                /* normalizedAvailableCpuFreqKHz= */ 2_492_687,
                 new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 28_949_280,
                         /* niceTimeMillis= */ 7_799_450, /* systemTimeMillis= */ 54_004_020,
                         /* idleTimeMillis= */ 402_707_120, /* iowaitTimeMillis= */ 1_186_960,
@@ -208,6 +218,7 @@
                 FLAG_CPUSET_CATEGORY_TOP_APP | FLAG_CPUSET_CATEGORY_BACKGROUND,
                 /* isOnline= */ true, /* curCpuFreqKHz= */ 1_000_000,
                 /* maxCpuFreqKHz= */ 2_000_000, /* avgTimeInStateCpuFreqKHz= */ MISSING_FREQUENCY,
+                /* normalizedAvailableCpuFreqKHz= */ 1_788_079,
                 new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 28_959_280,
                         /* niceTimeMillis= */ 7_789_450, /* systemTimeMillis= */ 54_014_020,
                         /* idleTimeMillis= */ 402_717_120, /* iowaitTimeMillis= */ 1_166_960,
@@ -218,6 +229,7 @@
                 FLAG_CPUSET_CATEGORY_TOP_APP | FLAG_CPUSET_CATEGORY_BACKGROUND,
                 /* isOnline= */ true, /* curCpuFreqKHz= */ 1_000_000,
                 /* maxCpuFreqKHz= */ 2_000_000, /* avgTimeInStateCpuFreqKHz= */ MISSING_FREQUENCY,
+                /* normalizedAvailableCpuFreqKHz= */ 1_799_962,
                 new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 32_349_610,
                         /* niceTimeMillis= */ 7_850_930, /* systemTimeMillis= */ 52_127_050,
                         /* idleTimeMillis= */ 409_136_950, /* iowaitTimeMillis= */ 1_332_810,
@@ -237,6 +249,7 @@
         expectedCpuInfos.append(0, new CpuInfoReader.CpuInfo(/* cpuCore= */ 0,
                 FLAG_CPUSET_CATEGORY_TOP_APP, /* isOnline= */ true, /* curCpuFreqKHz= */ 1_000_000,
                 /* maxCpuFreqKHz= */ 2_500_000, /* avgTimeInStateCpuFreqKHz= */ MISSING_FREQUENCY,
+                /* normalizedAvailableCpuFreqKHz= */ 2323347,
                 new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 10_000_000,
                         /* niceTimeMillis= */ 1_000_000, /* systemTimeMillis= */ 10_000_000,
                         /* idleTimeMillis= */ 110_000_000, /* iowaitTimeMillis= */ 1_100_000,
@@ -246,6 +259,7 @@
         expectedCpuInfos.append(1, new CpuInfoReader.CpuInfo(/* cpuCore= */ 1,
                 FLAG_CPUSET_CATEGORY_TOP_APP, /* isOnline= */ true, /* curCpuFreqKHz= */ 2_800_000,
                 /* maxCpuFreqKHz= */ 2_800_000, /* avgTimeInStateCpuFreqKHz= */ MISSING_FREQUENCY,
+                /* normalizedAvailableCpuFreqKHz= */ 209111,
                 new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 900_000,
                         /* niceTimeMillis= */ 1_000_000, /* systemTimeMillis= */ 10_000_000,
                         /* idleTimeMillis= */ 1_000_000, /* iowaitTimeMillis= */ 90_000,
@@ -256,6 +270,7 @@
                 FLAG_CPUSET_CATEGORY_TOP_APP | FLAG_CPUSET_CATEGORY_BACKGROUND,
                 /* isOnline= */ true, /* curCpuFreqKHz= */ 2_000_000,
                 /* maxCpuFreqKHz= */ 2_000_000, /* avgTimeInStateCpuFreqKHz= */ MISSING_FREQUENCY,
+                /* normalizedAvailableCpuFreqKHz= */ 453514,
                 new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 10_000_000,
                         /* niceTimeMillis= */ 2_000_000, /* systemTimeMillis= */ 0,
                         /* idleTimeMillis= */ 10_000_000, /* iowaitTimeMillis= */ 1_000_000,
@@ -266,6 +281,7 @@
                 FLAG_CPUSET_CATEGORY_TOP_APP | FLAG_CPUSET_CATEGORY_BACKGROUND,
                 /* isOnline= */ true, /* curCpuFreqKHz= */ 2_000_000,
                 /* maxCpuFreqKHz= */ 2_000_000, /* avgTimeInStateCpuFreqKHz= */ MISSING_FREQUENCY,
+                /* normalizedAvailableCpuFreqKHz= */ 37728,
                 new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 2_000_000,
                         /* niceTimeMillis= */ 1_000_000, /* systemTimeMillis= */ 1_000_000,
                         /* idleTimeMillis= */ 100_000, /* iowaitTimeMillis= */ 100_000,
@@ -323,38 +339,8 @@
 
         SparseArray<CpuInfoReader.CpuInfo> actualCpuInfos = cpuInfoReader.readCpuInfos();
         SparseArray<CpuInfoReader.CpuInfo> expectedCpuInfos = new SparseArray<>();
-        expectedCpuInfos.append(1, new CpuInfoReader.CpuInfo(/* cpuCore= */ 1,
-                FLAG_CPUSET_CATEGORY_TOP_APP, /* isOnline= */ true, /* curCpuFreqKHz= */ 3_000_000,
-                /* maxCpuFreqKHz= */ 1_000_000, /* avgTimeInStateCpuFreqKHz= */ MISSING_FREQUENCY,
-                new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 28_949_280,
-                        /* niceTimeMillis= */ 7_799_450, /* systemTimeMillis= */ 54_004_020,
-                        /* idleTimeMillis= */ 402_707_120, /* iowaitTimeMillis= */ 1_186_960,
-                        /* irqTimeMillis= */ 14_786_940, /* softirqTimeMillis= */ 1_498_130,
-                        /* stealTimeMillis= */ 78_780, /* guestTimeMillis= */ 0,
-                        /* guestNiceTimeMillis= */ 0)));
-        expectedCpuInfos.append(2, new CpuInfoReader.CpuInfo(/* cpuCore= */ 2,
-                FLAG_CPUSET_CATEGORY_TOP_APP | FLAG_CPUSET_CATEGORY_BACKGROUND,
-                /* isOnline= */ true, /* curCpuFreqKHz= */ 9, /* maxCpuFreqKHz= */ 2,
-                /* avgTimeInStateCpuFreqKHz= */ MISSING_FREQUENCY,
-                new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 28_959_280,
-                        /* niceTimeMillis= */ 7_789_450, /* systemTimeMillis= */ 54_014_020,
-                        /* idleTimeMillis= */ 402_717_120, /* iowaitTimeMillis= */ 1_166_960,
-                        /* irqTimeMillis= */ 14_796_940, /* softirqTimeMillis= */ 1_478_130,
-                        /* stealTimeMillis= */ 88_780, /* guestTimeMillis= */ 0,
-                        /* guestNiceTimeMillis= */ 0)));
-        expectedCpuInfos.append(3, new CpuInfoReader.CpuInfo(/* cpuCore= */ 3,
-                FLAG_CPUSET_CATEGORY_TOP_APP | FLAG_CPUSET_CATEGORY_BACKGROUND,
-                /* isOnline= */ true, /* curCpuFreqKHz= */ 9, /* maxCpuFreqKHz= */ 2,
-                /* avgTimeInStateCpuFreqKHz= */ MISSING_FREQUENCY,
-                new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 32_349_610,
-                        /* niceTimeMillis= */ 7_850_930, /* systemTimeMillis= */ 52_127_050,
-                        /* idleTimeMillis= */ 409_136_950, /* iowaitTimeMillis= */ 1_332_810,
-                        /* irqTimeMillis= */ 8_136_740, /* softirqTimeMillis= */ 438_970,
-                        /* stealTimeMillis= */ 71_950, /* guestTimeMillis= */ 0,
-                        /* guestNiceTimeMillis= */ 0)));
 
-        compareCpuInfos("CPU infos with corrupted CPU frequency", expectedCpuInfos,
-                actualCpuInfos);
+        compareCpuInfos("CPU infos with corrupted CPU frequency", expectedCpuInfos, actualCpuInfos);
     }
 
     @Test
@@ -368,6 +354,7 @@
         expectedCpuInfos.append(0, new CpuInfoReader.CpuInfo(/* cpuCore= */ 0,
                 FLAG_CPUSET_CATEGORY_TOP_APP, /* isOnline= */ true, /* curCpuFreqKHz= */ 1_230_000,
                 /* maxCpuFreqKHz= */ 2_500_000, /* avgTimeInStateCpuFreqKHz= */ 488_095,
+                /* normalizedAvailableCpuFreqKHz= */ 2_402_267,
                 new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 32_249_610,
                         /* niceTimeMillis= */ 7_950_930, /* systemTimeMillis= */ 52_227_050,
                         /* idleTimeMillis= */ 409_036_950, /* iowaitTimeMillis= */ 1_322_810,
@@ -377,6 +364,7 @@
         expectedCpuInfos.append(1, new CpuInfoReader.CpuInfo(/* cpuCore= */ 1,
                 FLAG_CPUSET_CATEGORY_TOP_APP, /* isOnline= */ true, /* curCpuFreqKHz= */ 1_450_000,
                 /* maxCpuFreqKHz= */ 2_800_000, /* avgTimeInStateCpuFreqKHz= */ 502_380,
+                /* normalizedAvailableCpuFreqKHz= */ 2_693_525,
                 new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 28_949_280,
                         /* niceTimeMillis= */ 7_799_450, /* systemTimeMillis= */ 54_004_020,
                         /* idleTimeMillis= */ 402_707_120, /* iowaitTimeMillis= */ 1_186_960,
@@ -393,7 +381,7 @@
         assertWithMessage("Make empty dir %s", emptyDir).that(emptyDir.mkdir()).isTrue();
         CpuInfoReader cpuInfoReader = new CpuInfoReader(emptyDir, getCacheFile(
                 VALID_CPUFREQ_WITH_TIME_IN_STATE_DIR),
-                getCacheFile(VALID_PROC_STAT));
+                getCacheFile(VALID_PROC_STAT), /* minReadIntervalMillis= */0);
 
         assertWithMessage("Init CPU reader info").that(cpuInfoReader.init()).isFalse();
 
@@ -406,7 +394,7 @@
         File emptyDir = getCacheFile(EMPTY_DIR);
         assertWithMessage("Make empty dir %s", emptyDir).that(emptyDir.mkdir()).isTrue();
         CpuInfoReader cpuInfoReader = new CpuInfoReader(getCacheFile(VALID_CPUSET_DIR), emptyDir,
-                getCacheFile(VALID_PROC_STAT));
+                getCacheFile(VALID_PROC_STAT), /* minReadIntervalMillis= */0);
 
         assertWithMessage("Init CPU reader info").that(cpuInfoReader.init()).isFalse();
 
@@ -420,12 +408,32 @@
         assertWithMessage("Create empty file %s", emptyFile).that(emptyFile.createNewFile())
                 .isTrue();
         CpuInfoReader cpuInfoReader = new CpuInfoReader(getCacheFile(VALID_CPUSET_DIR),
-                getCacheFile(VALID_CPUFREQ_WITH_TIME_IN_STATE_DIR), getCacheFile(EMPTY_FILE));
+                getCacheFile(VALID_CPUFREQ_WITH_TIME_IN_STATE_DIR), getCacheFile(EMPTY_FILE),
+                /* minReadIntervalMillis= */0);
 
         assertWithMessage("Cpu infos with empty proc stat").that(cpuInfoReader.readCpuInfos())
                 .isNull();
     }
 
+    @Test
+    public void testReadingTooFrequentlyReturnsLastReadCpuInfos() throws Exception {
+        CpuInfoReader cpuInfoReader = new CpuInfoReader(getCacheFile(VALID_CPUSET_DIR),
+                getCacheFile(VALID_CPUFREQ_WITH_TIME_IN_STATE_DIR), getCacheFile(VALID_PROC_STAT),
+                /* minReadIntervalMillis= */ 60_000);
+        assertWithMessage("Initialize CPU info reader").that(cpuInfoReader.init()).isTrue();
+
+        SparseArray<CpuInfoReader.CpuInfo> firstCpuInfos = cpuInfoReader.readCpuInfos();
+        assertWithMessage("CPU infos first snapshot").that(firstCpuInfos).isNotNull();
+        assertWithMessage("CPU infos first snapshot size").that(firstCpuInfos.size())
+                .isGreaterThan(0);
+
+        SparseArray<CpuInfoReader.CpuInfo> secondCpuInfos = cpuInfoReader.readCpuInfos();
+        compareCpuInfos("CPU infos second snapshot", firstCpuInfos, secondCpuInfos);
+
+        SparseArray<CpuInfoReader.CpuInfo> thirdCpuInfos = cpuInfoReader.readCpuInfos();
+        compareCpuInfos("CPU infos third snapshot", firstCpuInfos, thirdCpuInfos);
+    }
+
     private void compareCpuInfos(String message,
             SparseArray<CpuInfoReader.CpuInfo> expected,
             SparseArray<CpuInfoReader.CpuInfo> actual) {
@@ -462,7 +470,8 @@
 
     private static CpuInfoReader newCpuInfoReader(File cpusetDir, File cpuFreqDir,
             File procStatFile) {
-        CpuInfoReader cpuInfoReader = new CpuInfoReader(cpusetDir, cpuFreqDir, procStatFile);
+        CpuInfoReader cpuInfoReader = new CpuInfoReader(cpusetDir, cpuFreqDir, procStatFile,
+                /* minReadIntervalMillis= */ 0);
         assertWithMessage("Initialize CPU info reader").that(cpuInfoReader.init()).isTrue();
         return cpuInfoReader;
     }
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/gnss/GnssMeasurementsProviderTest.java b/services/tests/mockingservicestests/src/com/android/server/location/gnss/GnssMeasurementsProviderTest.java
new file mode 100644
index 0000000..fd9dfe8
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/location/gnss/GnssMeasurementsProviderTest.java
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.location.gnss;
+
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.content.Context;
+import android.location.GnssMeasurementRequest;
+import android.location.IGnssMeasurementsListener;
+import android.location.LocationManager;
+import android.location.LocationManagerInternal;
+import android.location.util.identity.CallerIdentity;
+import android.os.IBinder;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.server.LocalServices;
+import com.android.server.location.gnss.hal.FakeGnssHal;
+import com.android.server.location.gnss.hal.GnssNative;
+import com.android.server.location.injector.FakeUserInfoHelper;
+import com.android.server.location.injector.Injector;
+import com.android.server.location.injector.TestInjector;
+
+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;
+
+import java.util.Objects;
+
+@Presubmit
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class GnssMeasurementsProviderTest {
+    private static final int CURRENT_USER = FakeUserInfoHelper.DEFAULT_USERID;
+    private static final CallerIdentity IDENTITY = CallerIdentity.forTest(CURRENT_USER, 1000,
+            "mypackage", "attribution", "listener");
+    private static final GnssConfiguration.HalInterfaceVersion HIDL_V2_1 =
+            new GnssConfiguration.HalInterfaceVersion(
+                    2, 1);
+    private static final GnssConfiguration.HalInterfaceVersion AIDL_V3 =
+            new GnssConfiguration.HalInterfaceVersion(
+                    GnssConfiguration.HalInterfaceVersion.AIDL_INTERFACE, 3);
+    private static final GnssMeasurementRequest ACTIVE_REQUEST =
+            new GnssMeasurementRequest.Builder().build();
+    private static final GnssMeasurementRequest PASSIVE_REQUEST =
+            new GnssMeasurementRequest.Builder().setIntervalMillis(
+                    GnssMeasurementRequest.PASSIVE_INTERVAL).build();
+    private @Mock Context mContext;
+    private @Mock LocationManagerInternal mInternal;
+    private @Mock GnssConfiguration mMockConfiguration;
+    private @Mock GnssNative.GeofenceCallbacks mGeofenceCallbacks;
+    private @Mock IGnssMeasurementsListener mListener1;
+    private @Mock IGnssMeasurementsListener mListener2;
+    private @Mock IBinder mBinder1;
+    private @Mock IBinder mBinder2;
+
+    private GnssNative mGnssNative;
+
+    private GnssMeasurementsProvider mTestProvider;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+
+        doReturn(mBinder1).when(mListener1).asBinder();
+        doReturn(mBinder2).when(mListener2).asBinder();
+        doReturn(true).when(mInternal).isProviderEnabledForUser(eq(LocationManager.GPS_PROVIDER),
+                anyInt());
+        LocalServices.addService(LocationManagerInternal.class, mInternal);
+        FakeGnssHal fakeGnssHal = new FakeGnssHal();
+        GnssNative.setGnssHalForTest(fakeGnssHal);
+        Injector injector = new TestInjector(mContext);
+        mGnssNative = spy(Objects.requireNonNull(
+                GnssNative.create(injector, mMockConfiguration)));
+        mGnssNative.setGeofenceCallbacks(mGeofenceCallbacks);
+        mTestProvider = new GnssMeasurementsProvider(injector, mGnssNative);
+        mGnssNative.register();
+    }
+
+    @After
+    public void tearDown() {
+        LocalServices.removeServiceForTest(LocationManagerInternal.class);
+    }
+
+    @Test
+    public void testAddListener_active() {
+        // add the active request
+        mTestProvider.addListener(ACTIVE_REQUEST, IDENTITY, mListener1);
+        verify(mGnssNative, times(1)).startMeasurementCollection(
+                eq(ACTIVE_REQUEST.isFullTracking()),
+                eq(ACTIVE_REQUEST.isCorrelationVectorOutputsEnabled()),
+                eq(ACTIVE_REQUEST.getIntervalMillis()));
+
+        // remove the active request
+        mTestProvider.removeListener(mListener1);
+        verify(mGnssNative, times(1)).stopMeasurementCollection();
+    }
+
+    @Test
+    public void testAddListener_passive() {
+        // add the passive request
+        mTestProvider.addListener(PASSIVE_REQUEST, IDENTITY, mListener1);
+        verify(mGnssNative, never()).startMeasurementCollection(anyBoolean(), anyBoolean(),
+                anyInt());
+
+        // remove the passive request
+        mTestProvider.removeListener(mListener1);
+        verify(mGnssNative, times(1)).stopMeasurementCollection();
+    }
+
+    @Test
+    public void testReregister_aidlV3Plus() {
+        doReturn(AIDL_V3).when(mMockConfiguration).getHalInterfaceVersion();
+
+        // add the passive request
+        mTestProvider.addListener(PASSIVE_REQUEST, IDENTITY, mListener1);
+        verify(mGnssNative, never()).startMeasurementCollection(anyBoolean(), anyBoolean(),
+                anyInt());
+
+        // add the active request, reregister with the active request
+        mTestProvider.addListener(ACTIVE_REQUEST, IDENTITY, mListener2);
+        verify(mGnssNative, never()).stopMeasurementCollection();
+        verify(mGnssNative, times(1)).startMeasurementCollection(
+                eq(ACTIVE_REQUEST.isFullTracking()),
+                eq(ACTIVE_REQUEST.isCorrelationVectorOutputsEnabled()),
+                eq(ACTIVE_REQUEST.getIntervalMillis()));
+
+        // remove the active request, reregister with the passive request
+        mTestProvider.removeListener(mListener2);
+        verify(mGnssNative, times(1)).stopMeasurementCollection();
+
+        // remove the passive request
+        mTestProvider.removeListener(mListener1);
+        verify(mGnssNative, times(2)).stopMeasurementCollection();
+    }
+
+    @Test
+    public void testReregister_preAidlV3() {
+        doReturn(HIDL_V2_1).when(mMockConfiguration).getHalInterfaceVersion();
+
+        // add the passive request
+        mTestProvider.addListener(PASSIVE_REQUEST, IDENTITY, mListener1);
+        verify(mGnssNative, never()).startMeasurementCollection(anyBoolean(), anyBoolean(),
+                anyInt());
+
+        // add the active request, reregister with the active request
+        mTestProvider.addListener(ACTIVE_REQUEST, IDENTITY, mListener2);
+        verify(mGnssNative, times(1)).stopMeasurementCollection();
+        verify(mGnssNative, times(1)).startMeasurementCollection(
+                eq(ACTIVE_REQUEST.isFullTracking()),
+                eq(ACTIVE_REQUEST.isCorrelationVectorOutputsEnabled()),
+                eq(ACTIVE_REQUEST.getIntervalMillis()));
+
+        // remove the active request, reregister with the passive request
+        mTestProvider.removeListener(mListener2);
+        verify(mGnssNative, times(2)).stopMeasurementCollection();
+
+        // remove the passive request
+        mTestProvider.removeListener(mListener1);
+        verify(mGnssNative, times(3)).stopMeasurementCollection();
+    }
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/injector/FakeEmergencyHelper.java b/services/tests/mockingservicestests/src/com/android/server/location/injector/FakeEmergencyHelper.java
index 2cf57da..7ee411b 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/injector/FakeEmergencyHelper.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/injector/FakeEmergencyHelper.java
@@ -27,6 +27,7 @@
 
     public void setInEmergency(boolean inEmergency) {
         mInEmergency = inEmergency;
+        dispatchEmergencyStateChanged();
     }
 
     @Override
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java
index 7dc1935..293003d 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java
@@ -80,8 +80,12 @@
 import android.os.RemoteException;
 import android.os.WorkSource;
 import android.platform.test.annotations.Presubmit;
+import android.provider.DeviceConfig;
+import android.provider.Settings;
 import android.util.Log;
 
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.filters.MediumTest;
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
@@ -174,6 +178,8 @@
         doReturn(mResources).when(mContext).getResources();
         doReturn(mPackageManager).when(mContext).getPackageManager();
         doReturn(mPowerManager).when(mContext).getSystemService(PowerManager.class);
+        doReturn(ApplicationProvider.getApplicationContext()).when(
+                mContext).getApplicationContext();
         doReturn(mWakeLock).when(mPowerManager).newWakeLock(anyInt(), anyString());
         doReturn(PackageManager.PERMISSION_DENIED)
                 .when(mContext)
@@ -210,6 +216,8 @@
 
     @After
     public void tearDown() throws Exception {
+        DeviceConfig.resetToDefaults(Settings.RESET_MODE_PACKAGE_DEFAULTS,
+                DeviceConfig.NAMESPACE_LOCATION);
         LocalServices.removeServiceForTest(LocationManagerInternal.class);
 
         // some test failures may leave the fg thread stuck, interrupt until we get out of it
@@ -1339,6 +1347,144 @@
         assertThat(mManager.isVisibleToCaller()).isFalse();
     }
 
+    @MediumTest
+    @Test
+    public void testEnableMsl_expectedBehavior() throws Exception {
+        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_LOCATION,
+                "enable_location_provider_manager_msl", Boolean.toString(true), false);
+
+        // Create a random location and set provider location to cache necessary MSL assets.
+        Location loc = createLocation(NAME, mRandom);
+        loc.setAltitude(mRandom.nextDouble());
+        loc.setVerticalAccuracyMeters(mRandom.nextFloat());
+        mProvider.setProviderLocation(LocationResult.wrap(loc));
+        Thread.sleep(1000);
+
+        // Register listener and reset provider location to capture.
+        ILocationListener listener = createMockLocationListener();
+        LocationRequest request = new LocationRequest.Builder(0).setWorkSource(WORK_SOURCE).build();
+        mPassive.registerLocationRequest(request, IDENTITY, PERMISSION_FINE, listener);
+        mProvider.setProviderLocation(LocationResult.wrap(loc));
+        ArgumentCaptor<List<Location>> captor = ArgumentCaptor.forClass(List.class);
+        verify(listener).onLocationChanged(captor.capture(), nullable(IRemoteCallback.class));
+
+        // Assert that MSL fields are populated.
+        Location actual = captor.getValue().get(0);
+        assertThat(actual.hasMslAltitude()).isTrue();
+        assertThat(actual.hasMslAltitudeAccuracy()).isTrue();
+    }
+
+    @MediumTest
+    @Test
+    public void testEnableMsl_noVerticalAccuracy() throws Exception {
+        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_LOCATION,
+                "enable_location_provider_manager_msl", Boolean.toString(true), false);
+
+        // Create a random location and set provider location to cache necessary MSL assets.
+        Location loc = createLocation(NAME, mRandom);
+        loc.setAltitude(mRandom.nextDouble());
+        loc.setVerticalAccuracyMeters(mRandom.nextFloat());
+        mProvider.setProviderLocation(LocationResult.wrap(loc));
+        Thread.sleep(1000);
+
+        // Register listener and reset provider location with no vertical accuracy to capture.
+        ILocationListener listener = createMockLocationListener();
+        LocationRequest request = new LocationRequest.Builder(0).setWorkSource(WORK_SOURCE).build();
+        mPassive.registerLocationRequest(request, IDENTITY, PERMISSION_FINE, listener);
+        loc.removeVerticalAccuracy();
+        mProvider.setProviderLocation(LocationResult.wrap(loc));
+        ArgumentCaptor<List<Location>> captor = ArgumentCaptor.forClass(List.class);
+        verify(listener).onLocationChanged(captor.capture(), nullable(IRemoteCallback.class));
+
+        // Assert that only the MSL accuracy field is populated.
+        Location actual = captor.getValue().get(0);
+        assertThat(actual.hasMslAltitude()).isTrue();
+        assertThat(actual.hasMslAltitudeAccuracy()).isFalse();
+    }
+
+    @MediumTest
+    @Test
+    public void testEnableMsl_noAltitude() throws Exception {
+        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_LOCATION,
+                "enable_location_provider_manager_msl", Boolean.toString(true), false);
+
+        // Create a random location and set provider location to cache necessary MSL assets.
+        Location loc = createLocation(NAME, mRandom);
+        loc.setAltitude(mRandom.nextDouble());
+        loc.setVerticalAccuracyMeters(mRandom.nextFloat());
+        mProvider.setProviderLocation(LocationResult.wrap(loc));
+        Thread.sleep(1000);
+
+        // Register listener and reset provider location with no altitude to capture.
+        ILocationListener listener = createMockLocationListener();
+        LocationRequest request = new LocationRequest.Builder(0).setWorkSource(WORK_SOURCE).build();
+        mPassive.registerLocationRequest(request, IDENTITY, PERMISSION_FINE, listener);
+        loc.removeAltitude();
+        mProvider.setProviderLocation(LocationResult.wrap(loc));
+        ArgumentCaptor<List<Location>> captor = ArgumentCaptor.forClass(List.class);
+        verify(listener).onLocationChanged(captor.capture(), nullable(IRemoteCallback.class));
+
+        // Assert that no MSL fields are populated.
+        Location actual = captor.getValue().get(0);
+        assertThat(actual.hasMslAltitude()).isFalse();
+        assertThat(actual.hasMslAltitudeAccuracy()).isFalse();
+    }
+
+    @MediumTest
+    @Test
+    public void testEnableMsl_invalidAltitude() throws Exception {
+        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_LOCATION,
+                "enable_location_provider_manager_msl", Boolean.toString(true), false);
+
+        // Create a random location and set provider location to cache necessary MSL assets.
+        Location loc = createLocation(NAME, mRandom);
+        loc.setAltitude(mRandom.nextDouble());
+        loc.setVerticalAccuracyMeters(mRandom.nextFloat());
+        mProvider.setProviderLocation(LocationResult.wrap(loc));
+        Thread.sleep(1000);
+
+        // Register listener and reset provider location with invalid altitude to capture.
+        ILocationListener listener = createMockLocationListener();
+        LocationRequest request = new LocationRequest.Builder(0).setWorkSource(WORK_SOURCE).build();
+        mPassive.registerLocationRequest(request, IDENTITY, PERMISSION_FINE, listener);
+        loc.setAltitude(Double.POSITIVE_INFINITY);
+        mProvider.setProviderLocation(LocationResult.wrap(loc));
+        ArgumentCaptor<List<Location>> captor = ArgumentCaptor.forClass(List.class);
+        verify(listener).onLocationChanged(captor.capture(), nullable(IRemoteCallback.class));
+
+        // Assert that no MSL fields are populated.
+        Location actual = captor.getValue().get(0);
+        assertThat(actual.hasMslAltitude()).isFalse();
+        assertThat(actual.hasMslAltitudeAccuracy()).isFalse();
+    }
+
+    @MediumTest
+    @Test
+    public void testDisableMsl_expectedBehavior() throws Exception {
+        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_LOCATION,
+                "enable_location_provider_manager_msl", Boolean.toString(false), false);
+
+        // Create a random location and set provider location to cache necessary MSL assets.
+        Location loc = createLocation(NAME, mRandom);
+        loc.setAltitude(mRandom.nextDouble());
+        loc.setVerticalAccuracyMeters(mRandom.nextFloat());
+        mProvider.setProviderLocation(LocationResult.wrap(loc));
+        Thread.sleep(1000);
+
+        // Register listener and reset provider location to capture.
+        ILocationListener listener = createMockLocationListener();
+        LocationRequest request = new LocationRequest.Builder(0).setWorkSource(WORK_SOURCE).build();
+        mPassive.registerLocationRequest(request, IDENTITY, PERMISSION_FINE, listener);
+        mProvider.setProviderLocation(LocationResult.wrap(loc));
+        ArgumentCaptor<List<Location>> captor = ArgumentCaptor.forClass(List.class);
+        verify(listener).onLocationChanged(captor.capture(), nullable(IRemoteCallback.class));
+
+        // Assert that no MSL fields are populated.
+        Location actual = captor.getValue().get(0);
+        assertThat(actual.hasMslAltitude()).isFalse();
+        assertThat(actual.hasMslAltitudeAccuracy()).isFalse();
+    }
+
     private ILocationListener createMockLocationListener() {
         return spy(new ILocationListener.Stub() {
             @Override
diff --git a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
index 24b003c..caa2e36 100644
--- a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
@@ -18,6 +18,7 @@
 
 import static android.database.sqlite.SQLiteDatabase.deleteDatabase;
 
+import static org.mockito.ArgumentMatchers.contains;
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyBoolean;
 import static org.mockito.Matchers.anyInt;
@@ -719,6 +720,41 @@
     }
 
     @SmallTest
+    public void testStartAddAccountSessionWhereAuthenticatorReturnsIntentWithProhibitedFlags()
+            throws Exception {
+        unlockSystemUser();
+        ResolveInfo resolveInfo = new ResolveInfo();
+        resolveInfo.activityInfo = new ActivityInfo();
+        resolveInfo.activityInfo.applicationInfo = new ApplicationInfo();
+        when(mMockPackageManager.resolveActivityAsUser(
+                any(Intent.class), anyInt(), anyInt())).thenReturn(resolveInfo);
+        when(mMockPackageManager.checkSignatures(
+                anyInt(), anyInt())).thenReturn(PackageManager.SIGNATURE_MATCH);
+
+        final CountDownLatch latch = new CountDownLatch(1);
+        Response response = new Response(latch, mMockAccountManagerResponse);
+        Bundle options = createOptionsWithAccountName(
+                AccountManagerServiceTestFixtures.ACCOUNT_NAME_INTERVENE);
+        int prohibitedFlags = Intent.FLAG_GRANT_READ_URI_PERMISSION
+                | Intent.FLAG_GRANT_WRITE_URI_PERMISSION
+                | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION
+                | Intent.FLAG_GRANT_PREFIX_URI_PERMISSION;
+        options.putInt(AccountManagerServiceTestFixtures.KEY_INTENT_FLAGS, prohibitedFlags);
+
+        mAms.startAddAccountSession(
+                response, // response
+                AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1, // accountType
+                "authTokenType",
+                null, // requiredFeatures
+                true, // expectActivityLaunch
+                options); // optionsIn
+        waitForLatch(latch);
+
+        verify(mMockAccountManagerResponse).onError(
+                eq(AccountManager.ERROR_CODE_INVALID_RESPONSE), contains("invalid intent"));
+    }
+
+    @SmallTest
     public void testStartAddAccountSessionError() throws Exception {
         unlockSystemUser();
         Bundle options = createOptionsWithAccountName(
diff --git a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTestFixtures.java b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTestFixtures.java
index 73f30d9..b98a6a8 100644
--- a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTestFixtures.java
+++ b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTestFixtures.java
@@ -17,9 +17,6 @@
 
 import android.accounts.Account;
 
-import java.util.ArrayList;
-import java.util.List;
-
 /**
  * Constants shared between test AccountAuthenticators and AccountManagerServiceTest.
  */
@@ -31,6 +28,8 @@
             "account_manager_service_test:account_status_token_key";
     public static final String KEY_ACCOUNT_PASSWORD =
             "account_manager_service_test:account_password_key";
+    public static final String KEY_INTENT_FLAGS =
+            "account_manager_service_test:intent_flags_key";
     public static final String KEY_OPTIONS_BUNDLE =
             "account_manager_service_test:option_bundle_key";
     public static final String ACCOUNT_NAME_SUCCESS = "success_on_return@fixture.com";
diff --git a/services/tests/servicestests/src/com/android/server/accounts/TestAccountType1Authenticator.java b/services/tests/servicestests/src/com/android/server/accounts/TestAccountType1Authenticator.java
index 8106364..924443e 100644
--- a/services/tests/servicestests/src/com/android/server/accounts/TestAccountType1Authenticator.java
+++ b/services/tests/servicestests/src/com/android/server/accounts/TestAccountType1Authenticator.java
@@ -24,8 +24,6 @@
 import android.content.Intent;
 import android.os.Bundle;
 
-import com.android.frameworks.servicestests.R;
-
 import java.util.concurrent.atomic.AtomicInteger;
 
 /**
@@ -270,11 +268,13 @@
         String accountName = null;
         Bundle sessionBundle = null;
         String password = null;
+        int intentFlags = 0;
         if (options != null) {
             accountName = options.getString(AccountManagerServiceTestFixtures.KEY_ACCOUNT_NAME);
             sessionBundle = options.getBundle(
                     AccountManagerServiceTestFixtures.KEY_ACCOUNT_SESSION_BUNDLE);
             password = options.getString(AccountManagerServiceTestFixtures.KEY_ACCOUNT_PASSWORD);
+            intentFlags = options.getInt(AccountManagerServiceTestFixtures.KEY_INTENT_FLAGS, 0);
         }
 
         Bundle result = new Bundle();
@@ -302,6 +302,7 @@
             intent.putExtra(AccountManagerServiceTestFixtures.KEY_RESULT,
                     eventualActivityResultData);
             intent.putExtra(AccountManagerServiceTestFixtures.KEY_CALLBACK, response);
+            intent.setFlags(intentFlags);
 
             result.putParcelable(AccountManager.KEY_INTENT, intent);
         } else {
diff --git a/services/tests/servicestests/src/com/android/server/am/DropboxRateLimiterTest.java b/services/tests/servicestests/src/com/android/server/am/DropboxRateLimiterTest.java
index e68a8a0..01563e2 100644
--- a/services/tests/servicestests/src/com/android/server/am/DropboxRateLimiterTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/DropboxRateLimiterTest.java
@@ -106,6 +106,64 @@
                 mRateLimiter.shouldRateLimit("tag", "p").droppedCountSinceRateLimitActivated());
     }
 
+    @Test
+    public void testStrictRepeatedLimiting() throws Exception {
+        // The first 6 entries should not be rate limited.
+        assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
+        assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
+        assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
+        assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
+        assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
+        assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
+        // The 7th entry of the same process should be rate limited.
+        assertTrue(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
+
+        // After 11 minutes there should be nothing left in the buffer and the same type of entry
+        // should not get rate limited anymore.
+        mClock.setOffsetMillis(11 * 60 * 1000);
+        assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
+        // The first 6 entries should not be rate limited again.
+        assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
+        assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
+        assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
+        assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
+        assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
+
+        // The 7th entry of the same process should be rate limited.
+        assertTrue(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
+
+        // After 11 more minutes there should be nothing left in the buffer and the same type of
+        // entry should not get rate limited anymore.
+        mClock.setOffsetMillis(22 * 60 * 1000);
+        assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
+
+        // Repeated crashes after the last reset being rate limited should be restricted faster.
+        assertTrue(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
+
+        // We now need to wait 61 minutes for the buffer should be empty again.
+        mClock.setOffsetMillis(83 * 60 * 1000);
+        assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
+
+        // After yet another 61 minutes, this time without triggering rate limiting, the strict
+        // limiting should be turnd off.
+        mClock.setOffsetMillis(144 * 60 * 1000);
+        assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
+        assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
+
+        // As rate limiting was not triggered in the last reset, after another 11 minutes the
+        // buffer should still act as normal.
+        mClock.setOffsetMillis(155 * 60 * 1000);
+        // The first 6 entries should not be rate limited.
+        assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
+        assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
+        assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
+        assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
+        assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
+        assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
+        // The 7th entry of the same process should be rate limited.
+        assertTrue(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
+    }
+
     private static class TestClock implements DropboxRateLimiter.Clock {
         long mOffsetMillis = 0L;
 
diff --git a/services/tests/servicestests/src/com/android/server/appop/AppOpsNotedWatcherTest.java b/services/tests/servicestests/src/com/android/server/appop/AppOpsNotedWatcherTest.java
index 47fdcb6..b5229d8 100644
--- a/services/tests/servicestests/src/com/android/server/appop/AppOpsNotedWatcherTest.java
+++ b/services/tests/servicestests/src/com/android/server/appop/AppOpsNotedWatcherTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.appops;
+package com.android.server.appop;
 
 import static org.mockito.Mockito.eq;
 import static org.mockito.Mockito.inOrder;
diff --git a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
index a0fb3de..f368a66 100644
--- a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
@@ -78,6 +78,7 @@
 import android.service.dreams.DreamManagerInternal;
 import android.sysprop.PowerProperties;
 import android.test.mock.MockContentResolver;
+import android.util.IntArray;
 import android.view.Display;
 import android.view.DisplayInfo;
 
@@ -2322,6 +2323,31 @@
         verify(mLowPowerStandbyControllerMock).setActiveDuringMaintenance(false);
     }
 
+    @Test
+    public void testPowerGroupInitialization_multipleDisplayGroups() {
+        IntArray displayGroupIds = IntArray.wrap(new int[]{1, 2, 3});
+        when(mDisplayManagerInternalMock.getDisplayGroupIds()).thenReturn(displayGroupIds);
+
+        createService();
+        startSystem();
+
+        // Power group for DEFAULT_DISPLAY_GROUP is added by default.
+        assertThat(mService.getPowerGroupSize()).isEqualTo(4);
+    }
+
+    @Test
+    public void testPowerGroupInitialization_multipleDisplayGroupsWithDefaultGroup() {
+        IntArray displayGroupIds = IntArray.wrap(new int[]{Display.DEFAULT_DISPLAY_GROUP, 1, 2, 3});
+        when(mDisplayManagerInternalMock.getDisplayGroupIds()).thenReturn(displayGroupIds);
+
+        createService();
+        startSystem();
+
+        // Power group for DEFAULT_DISPLAY_GROUP is added once even if getDisplayGroupIds() return
+        // an array including DEFAULT_DESIPLAY_GROUP.
+        assertThat(mService.getPowerGroupSize()).isEqualTo(4);
+    }
+
     private WakeLock acquireWakeLock(String tag, int flags) {
         IBinder token = new Binder();
         String packageName = "pkg.name";
diff --git a/services/tests/servicestests/src/com/android/server/vibrator/VibrationSettingsTest.java b/services/tests/servicestests/src/com/android/server/vibrator/VibrationSettingsTest.java
index d50aca9..843e2b4 100644
--- a/services/tests/servicestests/src/com/android/server/vibrator/VibrationSettingsTest.java
+++ b/services/tests/servicestests/src/com/android/server/vibrator/VibrationSettingsTest.java
@@ -49,6 +49,7 @@
 import android.app.ActivityManager;
 import android.content.ComponentName;
 import android.content.ContentResolver;
+import android.content.Context;
 import android.content.ContextWrapper;
 import android.content.Intent;
 import android.content.pm.PackageManagerInternal;
@@ -121,18 +122,14 @@
     @Rule public FakeSettingsProviderRule mSettingsProviderRule = FakeSettingsProvider.rule();
 
     @Mock private VibrationSettings.OnVibratorSettingsChanged mListenerMock;
-    @Mock
-    private PowerManagerInternal mPowerManagerInternalMock;
-    @Mock
-    private VirtualDeviceManagerInternal mVirtualDeviceManagerInternalMock;
-    @Mock
-    private PackageManagerInternal mPackageManagerInternalMock;
-    @Mock
-    private VibrationConfig mVibrationConfigMock;
+    @Mock private PowerManagerInternal mPowerManagerInternalMock;
+    @Mock private VirtualDeviceManagerInternal mVirtualDeviceManagerInternalMock;
+    @Mock private PackageManagerInternal mPackageManagerInternalMock;
+    @Mock private AudioManager mAudioManagerMock;
+    @Mock private VibrationConfig mVibrationConfigMock;
 
     private TestLooper mTestLooper;
     private ContextWrapper mContextSpy;
-    private AudioManager mAudioManager;
     private VibrationSettings mVibrationSettings;
     private PowerManagerInternal.LowPowerModeListener mRegisteredPowerModeListener;
     private VirtualDeviceManagerInternal.VirtualDisplayListener mRegisteredVirtualDisplayListener;
@@ -146,6 +143,7 @@
 
         ContentResolver contentResolver = mSettingsProviderRule.mockContentResolver(mContextSpy);
         when(mContextSpy.getContentResolver()).thenReturn(contentResolver);
+        when(mContextSpy.getSystemService(eq(Context.AUDIO_SERVICE))).thenReturn(mAudioManagerMock);
         doAnswer(invocation -> {
             mRegisteredPowerModeListener = invocation.getArgument(0);
             return null;
@@ -165,7 +163,6 @@
         addServicesForTest();
 
         setDefaultIntensity(VIBRATION_INTENSITY_MEDIUM);
-        mAudioManager = mContextSpy.getSystemService(AudioManager.class);
         mVibrationSettings = new VibrationSettings(mContextSpy,
                 new Handler(mTestLooper.getLooper()), mVibrationConfigMock);
 
@@ -211,9 +208,34 @@
     }
 
     @Test
+    public void addListener_switchUserTriggerListener() {
+        mVibrationSettings.addListener(mListenerMock);
+
+        // Testing the broadcast flow manually.
+        mVibrationSettings.mSettingChangeReceiver.onReceive(mContextSpy,
+                new Intent(Intent.ACTION_USER_SWITCHED));
+
+        verify(mListenerMock).onChange();
+    }
+
+    @Test
+    public void addListener_ringerModeChangeTriggerListener() {
+        mVibrationSettings.addListener(mListenerMock);
+
+        // Testing the broadcast flow manually.
+        mVibrationSettings.mSettingChangeReceiver.onReceive(mContextSpy,
+                new Intent(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION));
+        mVibrationSettings.mSettingChangeReceiver.onReceive(mContextSpy,
+                new Intent(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION));
+
+        verify(mListenerMock, times(2)).onChange();
+    }
+
+    @Test
     public void addListener_settingsChangeTriggerListener() {
         mVibrationSettings.addListener(mListenerMock);
 
+        // Testing the broadcast flow manually.
         mVibrationSettings.mSettingObserver.onChange(false);
         mVibrationSettings.mSettingObserver.onChange(false);
 
@@ -224,6 +246,7 @@
     public void addListener_lowPowerModeChangeTriggerListener() {
         mVibrationSettings.addListener(mListenerMock);
 
+        // Testing the broadcast flow manually.
         mRegisteredPowerModeListener.onLowPowerModeChanged(LOW_POWER_STATE);
         mRegisteredPowerModeListener.onLowPowerModeChanged(NORMAL_POWER_STATE);
         mRegisteredPowerModeListener.onLowPowerModeChanged(NORMAL_POWER_STATE); // No change.
@@ -235,13 +258,20 @@
     public void removeListener_noMoreCallbacksToListener() {
         mVibrationSettings.addListener(mListenerMock);
 
-        setUserSetting(Settings.System.RING_VIBRATION_INTENSITY, 0);
+        mVibrationSettings.mSettingObserver.onChange(false);
         verify(mListenerMock).onChange();
 
         mVibrationSettings.removeListener(mListenerMock);
 
+        // Trigger multiple observers manually.
+        mVibrationSettings.mSettingObserver.onChange(false);
+        mRegisteredPowerModeListener.onLowPowerModeChanged(LOW_POWER_STATE);
+        mVibrationSettings.mSettingChangeReceiver.onReceive(mContextSpy,
+                new Intent(Intent.ACTION_USER_SWITCHED));
+        mVibrationSettings.mSettingChangeReceiver.onReceive(mContextSpy,
+                new Intent(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION));
+
         verifyNoMoreInteractions(mListenerMock);
-        setUserSetting(Settings.System.VIBRATE_INPUT_DEVICES, 1);
     }
 
     @Test
@@ -482,7 +512,7 @@
         assertVibrationNotIgnoredForUsage(USAGE_RINGTONE);
 
         // Testing the broadcast flow manually.
-        mAudioManager.setRingerModeInternal(AudioManager.RINGER_MODE_SILENT);
+        when(mAudioManagerMock.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_SILENT);
         mVibrationSettings.mSettingChangeReceiver.onReceive(mContextSpy,
                 new Intent(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION));
 
@@ -785,7 +815,6 @@
                 mVibrationSettings.shouldIgnoreVibration(callerInfo));
     }
 
-
     private String errorMessageForUsage(int usage) {
         return "Error for usage " + VibrationAttributes.usageToString(usage);
     }
@@ -814,8 +843,8 @@
     }
 
     private void setRingerMode(int ringerMode) {
-        mAudioManager.setRingerModeInternal(ringerMode);
-        assertEquals(ringerMode, mAudioManager.getRingerModeInternal());
+        when(mAudioManagerMock.getRingerModeInternal()).thenReturn(ringerMode);
+        // Mock AudioManager broadcast of internal ringer mode change.
         mVibrationSettings.mSettingChangeReceiver.onReceive(mContextSpy,
                 new Intent(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION));
     }
diff --git a/services/texttospeech/java/com/android/server/texttospeech/TextToSpeechManagerService.java b/services/texttospeech/java/com/android/server/texttospeech/TextToSpeechManagerService.java
index 9015563..2411498 100644
--- a/services/texttospeech/java/com/android/server/texttospeech/TextToSpeechManagerService.java
+++ b/services/texttospeech/java/com/android/server/texttospeech/TextToSpeechManagerService.java
@@ -63,6 +63,12 @@
         public void createSession(String engine,
                 ITextToSpeechSessionCallback sessionCallback) {
             synchronized (mLock) {
+                if (engine == null) {
+                    runSessionCallbackMethod(
+                            () -> sessionCallback.onError("Engine cannot be null"));
+                    return;
+                }
+
                 TextToSpeechManagerPerUserService perUserService = getServiceForUserLocked(
                         UserHandle.getCallingUserId());
                 if (perUserService != null) {
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 66711df..3f5c76d 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -10642,12 +10642,20 @@
      * no reason to power it off. When any of the voters want to power it off, it will be turned
      * off. In case of emergency, the radio will be turned on even if there are some reasons for
      * powering it off, and these radio off votes will be cleared.
-     * Multiple apps can vote for the same reason and the last vote will take effect. Each app is
-     * responsible for its vote. A powering-off vote of a reason will be maintained until it is
-     * cleared by calling {@link clearRadioPowerOffForReason} for that reason, or an emergency call
-     * is made, or the device is rebooted. When an app comes backup from a crash, it needs to make
-     * sure if its vote is as expected. An app can use the API {@link getRadioPowerOffReasons} to
-     * check its vote.
+     * <p>
+     * Each API call is for one reason. However, an app can call the API multiple times for multiple
+     * reasons. Multiple apps can vote for the same reason but the vote of one app does not affect
+     * the vote of another app.
+     * <p>
+     * Each app is responsible for its vote. A powering-off vote for a reason of an app will be
+     * maintained until it is cleared by calling {@link #clearRadioPowerOffForReason(int)} for that
+     * reason by the app, or an emergency call is made, or the device is rebooted. When an app
+     * comes backup from a crash, it needs to make sure if its vote is as expected. An app can use
+     * the API {@link #getRadioPowerOffReasons()} to check its votes. Votes won't be removed when
+     * an app crashes.
+     * <p>
+     * User setting for power state is persistent across device reboots. This applies to all users,
+     * callers must be careful to update the off reasons when the current user changes.
      *
      * @param reason The reason for powering off radio.
      * @throws SecurityException if the caller does not have MODIFY_PHONE_STATE permission.
@@ -10704,10 +10712,10 @@
     }
 
     /**
-     * Get reasons for powering off radio, as requested by {@link requestRadioPowerOffForReason}.
-     * If the reason set is empty, the radio is on in all cases.
+     * Get reasons for powering off radio of the calling app, as requested by
+     * {@link #requestRadioPowerOffForReason(int)}.
      *
-     * @return Set of reasons for powering off radio.
+     * @return Set of reasons for powering off radio of the calling app.
      * @throws SecurityException if the caller does not have READ_PRIVILEGED_PHONE_STATE permission.
      * @throws IllegalStateException if the Telephony service is not currently available.
      *
diff --git a/tests/EnforcePermission/Android.bp b/tests/EnforcePermission/Android.bp
new file mode 100644
index 0000000..719a898
--- /dev/null
+++ b/tests/EnforcePermission/Android.bp
@@ -0,0 +1,22 @@
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
+filegroup {
+    name: "frameworks-enforce-permission-test-aidl",
+    srcs: ["aidl/**/*.aidl"],
+}
diff --git a/tests/EnforcePermission/aidl/android/tests/enforcepermission/INested.aidl b/tests/EnforcePermission/aidl/android/tests/enforcepermission/INested.aidl
new file mode 100644
index 0000000..1eb773d
--- /dev/null
+++ b/tests/EnforcePermission/aidl/android/tests/enforcepermission/INested.aidl
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.tests.enforcepermission;
+
+interface INested {
+    @EnforcePermission("ACCESS_NETWORK_STATE")
+    void ProtectedByAccessNetworkState();
+
+    @EnforcePermission("READ_SYNC_SETTINGS")
+    void ProtectedByReadSyncSettings();
+}
diff --git a/tests/EnforcePermission/aidl/android/tests/enforcepermission/IProtected.aidl b/tests/EnforcePermission/aidl/android/tests/enforcepermission/IProtected.aidl
new file mode 100644
index 0000000..18e3aec
--- /dev/null
+++ b/tests/EnforcePermission/aidl/android/tests/enforcepermission/IProtected.aidl
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.tests.enforcepermission;
+
+interface IProtected {
+    @EnforcePermission("INTERNET")
+    void ProtectedByInternet();
+
+    @EnforcePermission("VIBRATE")
+    void ProtectedByVibrate();
+
+    @EnforcePermission("INTERNET")
+    void ProtectedByInternetAndVibrateImplicitly();
+
+    @EnforcePermission("INTERNET")
+    void ProtectedByInternetAndAccessNetworkStateImplicitly();
+
+    @EnforcePermission("INTERNET")
+    void ProtectedByInternetAndReadSyncSettingsImplicitly();
+}
diff --git a/tests/EnforcePermission/service-app/Android.bp b/tests/EnforcePermission/service-app/Android.bp
new file mode 100644
index 0000000..a4ac1d7
--- /dev/null
+++ b/tests/EnforcePermission/service-app/Android.bp
@@ -0,0 +1,32 @@
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_test_helper_app {
+    name: "EnforcePermissionTestHelper",
+    srcs: [
+        "src/**/*.java",
+        ":frameworks-enforce-permission-test-aidl",
+    ],
+    platform_apis: true,
+    certificate: "platform",
+}
diff --git a/tests/EnforcePermission/service-app/AndroidManifest.xml b/tests/EnforcePermission/service-app/AndroidManifest.xml
new file mode 100644
index 0000000..ddafe15
--- /dev/null
+++ b/tests/EnforcePermission/service-app/AndroidManifest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2023 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+  package="android.tests.enforcepermission.service">
+    <application>
+        <service
+          android:name=".TestService"
+          android:exported="true" />
+
+        <service
+          android:name=".NestedTestService"
+          android:exported="true" />
+    </application>
+</manifest>
diff --git a/tests/EnforcePermission/service-app/src/android/tests/enforcepermission/service/NestedTestService.java b/tests/EnforcePermission/service-app/src/android/tests/enforcepermission/service/NestedTestService.java
new file mode 100644
index 0000000..7879a12
--- /dev/null
+++ b/tests/EnforcePermission/service-app/src/android/tests/enforcepermission/service/NestedTestService.java
@@ -0,0 +1,48 @@
+/**
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.tests.enforcepermission.service;
+
+import android.annotation.EnforcePermission;
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+import android.tests.enforcepermission.INested;
+import android.util.Log;
+
+public class NestedTestService extends Service {
+    private static final String TAG = "EnforcePermission.NestedTestService";
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        Log.i(TAG, "onBind");
+        return mBinder;
+    }
+
+    private final INested.Stub mBinder = new INested.Stub() {
+        @Override
+        @EnforcePermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
+        public void ProtectedByAccessNetworkState() {
+            ProtectedByAccessNetworkState_enforcePermission();
+        }
+
+        @Override
+        @EnforcePermission(android.Manifest.permission.READ_SYNC_SETTINGS)
+        public void ProtectedByReadSyncSettings() {
+            ProtectedByReadSyncSettings_enforcePermission();
+        }
+    };
+}
diff --git a/tests/EnforcePermission/service-app/src/android/tests/enforcepermission/service/TestService.java b/tests/EnforcePermission/service-app/src/android/tests/enforcepermission/service/TestService.java
new file mode 100644
index 0000000..e9b897d
--- /dev/null
+++ b/tests/EnforcePermission/service-app/src/android/tests/enforcepermission/service/TestService.java
@@ -0,0 +1,119 @@
+/**
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.tests.enforcepermission.service;
+
+import android.annotation.EnforcePermission;
+import android.app.Service;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.tests.enforcepermission.INested;
+import android.tests.enforcepermission.IProtected;
+import android.util.Log;
+
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+public class TestService extends Service {
+
+    private static final String TAG = "EnforcePermission.TestService";
+    private volatile ServiceConnection mNestedServiceConnection;
+
+    @Override
+    public void onCreate() {
+        mNestedServiceConnection = new ServiceConnection();
+        Intent intent = new Intent(this, NestedTestService.class);
+        boolean bound = bindService(intent, mNestedServiceConnection, Context.BIND_AUTO_CREATE);
+        if (!bound) {
+            Log.wtf(TAG, "bindService() on NestedTestService failed");
+        }
+    }
+
+    @Override
+    public void onDestroy() {
+        unbindService(mNestedServiceConnection);
+    }
+
+    private static final class ServiceConnection implements android.content.ServiceConnection {
+        private volatile CompletableFuture<INested> mFuture = new CompletableFuture<>();
+
+        public INested get() {
+            try {
+                return mFuture.get(1, TimeUnit.SECONDS);
+            } catch (ExecutionException | InterruptedException | TimeoutException e) {
+                throw new RuntimeException("Unable to reach NestedTestService: " + e.getMessage());
+            }
+        }
+
+        public void onServiceConnected(ComponentName className, IBinder service) {
+            mFuture.complete(INested.Stub.asInterface(service));
+        }
+
+        public void onServiceDisconnected(ComponentName className) {
+            mFuture = new CompletableFuture<>();
+        }
+    };
+
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return mBinder;
+    }
+
+    private final IProtected.Stub mBinder = new IProtected.Stub() {
+        @Override
+        @EnforcePermission(android.Manifest.permission.INTERNET)
+        public void ProtectedByInternet() {
+            ProtectedByInternet_enforcePermission();
+        }
+
+        @Override
+        @EnforcePermission(android.Manifest.permission.VIBRATE)
+        public void ProtectedByVibrate() {
+            ProtectedByVibrate_enforcePermission();
+        }
+
+        @Override
+        @EnforcePermission(android.Manifest.permission.INTERNET)
+        public void ProtectedByInternetAndVibrateImplicitly() {
+            ProtectedByInternetAndVibrateImplicitly_enforcePermission();
+
+            ProtectedByVibrate();
+        }
+
+        @Override
+        @EnforcePermission(android.Manifest.permission.INTERNET)
+        public void ProtectedByInternetAndAccessNetworkStateImplicitly() throws RemoteException {
+            ProtectedByInternetAndAccessNetworkStateImplicitly_enforcePermission();
+
+            mNestedServiceConnection.get().ProtectedByAccessNetworkState();
+
+        }
+
+        @Override
+        @EnforcePermission(android.Manifest.permission.INTERNET)
+        public void ProtectedByInternetAndReadSyncSettingsImplicitly() throws RemoteException {
+            ProtectedByInternetAndReadSyncSettingsImplicitly_enforcePermission();
+
+            mNestedServiceConnection.get().ProtectedByReadSyncSettings();
+        }
+    };
+}
diff --git a/tests/EnforcePermission/test-app/Android.bp b/tests/EnforcePermission/test-app/Android.bp
new file mode 100644
index 0000000..305ed8f
--- /dev/null
+++ b/tests/EnforcePermission/test-app/Android.bp
@@ -0,0 +1,38 @@
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_test {
+    name: "EnforcePermissionTests",
+    srcs: [
+        "src/**/*.java",
+        ":frameworks-enforce-permission-test-aidl",
+    ],
+    static_libs: [
+        "androidx.test.rules",
+    ],
+    libs: [
+        "android.test.base",
+        "android.test.runner",
+    ],
+    data: [
+        ":EnforcePermissionTestHelper",
+    ],
+    platform_apis: true,
+    certificate: "platform",
+    test_suites: ["general-tests"],
+}
diff --git a/tests/EnforcePermission/test-app/AndroidManifest.xml b/tests/EnforcePermission/test-app/AndroidManifest.xml
new file mode 100644
index 0000000..4a0c6a8
--- /dev/null
+++ b/tests/EnforcePermission/test-app/AndroidManifest.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2023 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+  package="android.tests.enforcepermission.tests">
+
+    <!-- Expected for the tests (not actually used) -->
+    <uses-permission android:name="android.permission.INTERNET" />
+    <uses-permission android:name="android.permission.READ_SYNC_SETTINGS" />
+
+    <queries>
+        <package android:name="android.tests.enforcepermission.service" />
+    </queries>
+
+    <application>
+        <uses-library android:name="android.test.runner" />
+    </application>
+    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+                     android:targetPackage="android.tests.enforcepermission.tests"/>
+</manifest>
diff --git a/tests/EnforcePermission/test-app/AndroidTest.xml b/tests/EnforcePermission/test-app/AndroidTest.xml
new file mode 100644
index 0000000..120381a
--- /dev/null
+++ b/tests/EnforcePermission/test-app/AndroidTest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2023 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Runs EnforcePermission End-to-End Tests">
+    <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
+      <option name="test-file-name" value="EnforcePermissionTestHelper.apk"/>
+      <option name="test-file-name" value="EnforcePermissionTests.apk"/>
+      <option name="cleanup-apks" value="true" />
+    </target_preparer>
+
+    <option name="test-tag" value="EnforcePermissionTests"/>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest">
+        <option name="package" value="android.tests.enforcepermission.tests"/>
+        <option name="runner" value="androidx.test.runner.AndroidJUnitRunner"/>
+    </test>
+</configuration>
diff --git a/tests/EnforcePermission/test-app/src/android/tests/enforcepermission/tests/ServiceTest.java b/tests/EnforcePermission/test-app/src/android/tests/enforcepermission/tests/ServiceTest.java
new file mode 100644
index 0000000..d2a4a03
--- /dev/null
+++ b/tests/EnforcePermission/test-app/src/android/tests/enforcepermission/tests/ServiceTest.java
@@ -0,0 +1,129 @@
+/**
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.tests.enforcepermission.tests;
+
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertTrue;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.tests.enforcepermission.IProtected;
+import android.util.Log;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+@RunWith(AndroidJUnit4.class)
+public class ServiceTest {
+
+    private static final String TAG = "EnforcePermission.Tests";
+    private static final String SERVICE_NAME = "android.tests.enforcepermission.service";
+    private static final int SERVICE_TIMEOUT_SEC = 5;
+
+    private Context mContext;
+    private volatile ServiceConnection mServiceConnection;
+
+    @Before
+    public void bindTestService() throws Exception {
+        Log.d(TAG, "bindTestService");
+        mContext = InstrumentationRegistry.getTargetContext();
+        mServiceConnection = new ServiceConnection();
+        Intent intent = new Intent();
+        intent.setClassName(SERVICE_NAME, SERVICE_NAME + ".TestService");
+        assertTrue(mContext.bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE));
+    }
+
+    @After
+    public void unbindTestService() throws Exception {
+        mContext.unbindService(mServiceConnection);
+    }
+
+    private static final class ServiceConnection implements android.content.ServiceConnection {
+        private volatile CompletableFuture<IProtected> mFuture = new CompletableFuture<>();
+
+        @Override
+        public void onServiceConnected(ComponentName className, IBinder service) {
+            mFuture.complete(IProtected.Stub.asInterface(service));
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName className) {
+            mFuture = new CompletableFuture<>();
+        }
+
+        public IProtected get() {
+            try {
+                return mFuture.get(SERVICE_TIMEOUT_SEC, TimeUnit.SECONDS);
+            } catch (ExecutionException | InterruptedException | TimeoutException e) {
+                throw new RuntimeException("Unable to reach TestService: " + e.toString());
+            }
+        }
+    }
+
+    @Test
+    public void testImmediatePermissionGranted_succeeds()
+            throws RemoteException {
+        mServiceConnection.get().ProtectedByInternet();
+    }
+
+    @Test
+    public void testImmediatePermissionNotGranted_fails()
+            throws RemoteException {
+        final Exception ex = assertThrows(SecurityException.class,
+                () -> mServiceConnection.get().ProtectedByVibrate());
+        assertThat(ex.getMessage(), containsString("VIBRATE"));
+    }
+
+    @Test
+    public void testImmediatePermissionGrantedButImplicitLocalNotGranted_fails()
+            throws RemoteException {
+        final Exception ex = assertThrows(SecurityException.class,
+                () -> mServiceConnection.get().ProtectedByInternetAndVibrateImplicitly());
+        assertThat(ex.getMessage(), containsString("VIBRATE"));
+    }
+
+    @Test
+    public void testImmediatePermissionGrantedButImplicitNestedNotGranted_fails()
+            throws RemoteException {
+        final Exception ex = assertThrows(SecurityException.class,
+                () -> mServiceConnection.get()
+                      .ProtectedByInternetAndAccessNetworkStateImplicitly());
+        assertThat(ex.getMessage(), containsString("ACCESS_NETWORK_STATE"));
+    }
+
+    @Test
+    public void testImmediatePermissionGrantedAndImplicitNestedGranted_succeeds()
+            throws RemoteException {
+        mServiceConnection.get().ProtectedByInternetAndReadSyncSettingsImplicitly();
+    }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/GestureHelper.java b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/GestureHelper.java
index 858cd76..70dcc12 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/GestureHelper.java
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/GestureHelper.java
@@ -20,6 +20,7 @@
 import android.app.Instrumentation;
 import android.app.UiAutomation;
 import android.os.SystemClock;
+import android.util.Log;
 import android.view.InputDevice;
 import android.view.InputEvent;
 import android.view.MotionEvent;
@@ -30,6 +31,7 @@
  * Injects gestures given an {@link Instrumentation} object.
  */
 public class GestureHelper {
+    private static final String TAG = GestureHelper.class.getSimpleName();
     // Inserted after each motion event injection.
     private static final int MOTION_EVENT_INJECTION_DELAY_MILLIS = 5;
 
@@ -153,6 +155,9 @@
             for (int j = 0; j < coords.length; j++) {
                 coords[j].x += (endPoints[j].x - startPoints[j].x) / steps;
                 coords[j].y += (endPoints[j].y - startPoints[j].y) / steps;
+
+                // TODO: remove logging once b/269505548 is resolved
+                Log.d(TAG, "(" + coords[j].x + ", " + coords[j].y + ")");
             }
 
             eventTime = SystemClock.uptimeMillis();
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/LetterboxAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/LetterboxAppHelper.kt
new file mode 100644
index 0000000..1ccac13
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/LetterboxAppHelper.kt
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.helpers
+
+import android.app.Instrumentation
+import androidx.test.uiautomator.By
+import androidx.test.uiautomator.Until
+import com.android.server.wm.flicker.testapp.ActivityOptions
+import android.tools.common.datatypes.component.ComponentNameMatcher
+import android.tools.device.traces.parsers.toFlickerComponent
+import android.tools.device.traces.parsers.WindowManagerStateHelper
+import android.tools.device.apphelpers.StandardAppHelper
+import android.tools.device.helpers.FIND_TIMEOUT
+import android.tools.device.helpers.SYSTEMUI_PACKAGE
+
+class LetterboxAppHelper
+@JvmOverloads
+constructor(
+    instr: Instrumentation,
+    launcherName: String = ActivityOptions.NonResizeablePortraitActivity.LABEL,
+    component: ComponentNameMatcher =
+        ActivityOptions.NonResizeablePortraitActivity.COMPONENT.toFlickerComponent()
+) : StandardAppHelper(instr, launcherName, component) {
+
+    fun clickRestart(wmHelper: WindowManagerStateHelper) {
+        val restartButton = uiDevice.wait(Until.findObject(By.res(
+            SYSTEMUI_PACKAGE, "size_compat_restart_button")), FIND_TIMEOUT)
+        restartButton?.run { restartButton.click() } ?: error("Restart button not found")
+
+        // size compat mode restart confirmation dialog button
+        val restartDialogButton = uiDevice.wait(Until.findObject(By.res(
+            SYSTEMUI_PACKAGE, "letterbox_restart_dialog_restart_button")), FIND_TIMEOUT)
+        restartDialogButton?.run { restartDialogButton.click() }
+            ?: error("Restart dialog button not found")
+        wmHelper.StateSyncBuilder().withAppTransitionIdle().waitForAndVerify()
+    }
+}
diff --git a/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml b/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
index 5361d73f..1ec9ec9 100644
--- a/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
+++ b/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
@@ -88,6 +88,18 @@
                 <category android:name="android.intent.category.LAUNCHER"/>
             </intent-filter>
         </activity>
+        <activity android:name=".NonResizeablePortraitActivity"
+                  android:theme="@style/CutoutNever"
+                  android:resizeableActivity="false"
+                  android:screenOrientation="portrait"
+                  android:taskAffinity="com.android.server.wm.flicker.testapp.NonResizeablePortraitActivity"
+                  android:label="NonResizeablePortraitActivity"
+                  android:exported="true">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.LAUNCHER"/>
+            </intent-filter>
+        </activity>
         <activity android:name=".LaunchNewActivity"
                   android:taskAffinity="com.android.server.wm.flicker.testapp.LaunchNewActivity"
                   android:theme="@style/CutoutShortEdges"
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java
index b61bc0c..9c3226b 100644
--- a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java
@@ -67,6 +67,12 @@
                 FLICKER_APP_PACKAGE + ".NonResizeableActivity");
     }
 
+    public static class NonResizeablePortraitActivity {
+        public static final String LABEL = "NonResizeablePortraitActivity";
+        public static final ComponentName COMPONENT = new ComponentName(FLICKER_APP_PACKAGE,
+                FLICKER_APP_PACKAGE + ".NonResizeablePortraitActivity");
+    }
+
     public static class DialogThemedActivity {
         public static final String LABEL = "DialogThemedActivity";
         public static final ComponentName COMPONENT = new ComponentName(FLICKER_APP_PACKAGE,
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/NonResizeablePortraitActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/NonResizeablePortraitActivity.java
new file mode 100644
index 0000000..4b420dc
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/NonResizeablePortraitActivity.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2021 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.wm.flicker.testapp;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+public class NonResizeablePortraitActivity extends Activity {
+
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        setContentView(R.layout.activity_non_resizeable);
+    }
+}
diff --git a/tests/SoundTriggerTests/src/android/hardware/soundtrigger/SoundTriggerTest.java b/tests/SoundTriggerTests/src/android/hardware/soundtrigger/SoundTriggerTest.java
index e36f398..f49d9c9 100644
--- a/tests/SoundTriggerTests/src/android/hardware/soundtrigger/SoundTriggerTest.java
+++ b/tests/SoundTriggerTests/src/android/hardware/soundtrigger/SoundTriggerTest.java
@@ -219,10 +219,18 @@
 
     @SmallTest
     public void testRecognitionEventParcelUnparcel_noData() throws Exception {
-        RecognitionEvent re = new RecognitionEvent(SoundTrigger.RECOGNITION_STATUS_SUCCESS, 1,
-                true, 2, 3, 4, false, null, null);
+        RecognitionEvent re = new RecognitionEvent(SoundTrigger.RECOGNITION_STATUS_SUCCESS,
+                1 /* soundModelHandle */,
+                true /* captureAvailable */,
+                2 /* captureSession */,
+                3 /* captureDelayMs */,
+                4 /* capturePreambleMs */,
+                false /* triggerInData */,
+                null /* captureFormat */,
+                null /* data */,
+                12345678 /* halEventReceivedMillis */);
 
-        // Write to a parcel
+                // Write to a parcel
         Parcel parcel = Parcel.obtain();
         re.writeToParcel(parcel, 0);
 
@@ -236,10 +244,18 @@
 
     @SmallTest
     public void testRecognitionEventParcelUnparcel_zeroData() throws Exception {
-        RecognitionEvent re = new RecognitionEvent(SoundTrigger.RECOGNITION_STATUS_FAILURE, 1,
-                true, 2, 3, 4, false, null, new byte[1]);
+        RecognitionEvent re = new RecognitionEvent(SoundTrigger.RECOGNITION_STATUS_FAILURE,
+                1 /* soundModelHandle */,
+                true /* captureAvailable */,
+                2 /* captureSession */,
+                3 /* captureDelayMs */,
+                4 /* capturePreambleMs */,
+                false /* triggerInData */,
+                null /* captureFormat */,
+                new byte[1] /* data */,
+                12345678 /* halEventReceivedMillis */);
 
-        // Write to a parcel
+                // Write to a parcel
         Parcel parcel = Parcel.obtain();
         re.writeToParcel(parcel, 0);
 
@@ -255,10 +271,18 @@
     public void testRecognitionEventParcelUnparcel_largeData() throws Exception {
         byte[] data = new byte[200 * 1024];
         mRandom.nextBytes(data);
-        RecognitionEvent re = new RecognitionEvent(SoundTrigger.RECOGNITION_STATUS_ABORT, 1,
-                false, 2, 3, 4, false, null, data);
+        RecognitionEvent re = new RecognitionEvent(SoundTrigger.RECOGNITION_STATUS_ABORT,
+                1 /* soundModelHandle */,
+                false /* captureAvailable */,
+                2 /* captureSession */,
+                3 /* captureDelayMs */,
+                4 /* capturePreambleMs */,
+                false /* triggerInData */,
+                null /* captureFormat */,
+                data,
+                12345678 /* halEventReceivedMillis */);
 
-        // Write to a parcel
+                // Write to a parcel
         Parcel parcel = Parcel.obtain();
         re.writeToParcel(parcel, 0);
 
@@ -274,14 +298,20 @@
     public void testRecognitionEventParcelUnparcel_largeAudioData() throws Exception {
         byte[] data = new byte[200 * 1024];
         mRandom.nextBytes(data);
-        RecognitionEvent re = new RecognitionEvent(SoundTrigger.RECOGNITION_STATUS_ABORT, 1,
-                false, 2, 3, 4, true,
-                (new AudioFormat.Builder())
-                .setChannelMask(AudioFormat.CHANNEL_IN_MONO)
-                .setEncoding(AudioFormat.ENCODING_PCM_16BIT)
-                .setSampleRate(16000)
-                .build(),
-                data);
+        RecognitionEvent re = new RecognitionEvent(SoundTrigger.RECOGNITION_STATUS_ABORT,
+                1 /* soundModelHandle */,
+                false /* captureAvailable */,
+                2 /* captureSession */,
+                3 /* captureDelayMs */,
+                4 /* capturePreambleMs */,
+                true /* triggerInData */,
+                new AudioFormat.Builder()
+                        .setChannelMask(AudioFormat.CHANNEL_IN_MONO)
+                        .setEncoding(AudioFormat.ENCODING_PCM_16BIT)
+                        .setSampleRate(16000)
+                        .build(),
+                data,
+                12345678 /* halEventReceivedMillis */);
 
         // Write to a parcel
         Parcel parcel = Parcel.obtain();
@@ -298,7 +328,17 @@
     @SmallTest
     public void testKeyphraseRecognitionEventParcelUnparcel_noKeyphrases() throws Exception {
         KeyphraseRecognitionEvent re = new KeyphraseRecognitionEvent(
-                SoundTrigger.RECOGNITION_STATUS_SUCCESS, 1, true, 2, 3, 4, false, null, null, null);
+                SoundTrigger.RECOGNITION_STATUS_SUCCESS,
+                1 /* soundModelHandle */,
+                true /* captureAvailable */,
+                2 /* captureSession */,
+                3 /* captureDelayMs */,
+                4 /* capturePreambleMs */,
+                false /* triggerInData */,
+                null /* captureFormat */,
+                null /* data */,
+                null /* keyphraseExtras */,
+                12345678 /* halEventReceivedMillis */);
 
         // Write to a parcel
         Parcel parcel = Parcel.obtain();
@@ -317,8 +357,17 @@
     public void testKeyphraseRecognitionEventParcelUnparcel_zeroData() throws Exception {
         KeyphraseRecognitionExtra[] kpExtra = new KeyphraseRecognitionExtra[0];
         KeyphraseRecognitionEvent re = new KeyphraseRecognitionEvent(
-                SoundTrigger.RECOGNITION_STATUS_FAILURE, 2, true, 2, 3, 4, false, null, new byte[1],
-                kpExtra);
+                SoundTrigger.RECOGNITION_STATUS_FAILURE,
+                2 /* soundModelHandle */,
+                true /* captureAvailable */,
+                2 /* captureSession */,
+                3 /* captureDelayMs */,
+                4 /* capturePreambleMs */,
+                false /* triggerInData */,
+                null /* captureFormat */,
+                new byte[1] /* data */,
+                kpExtra,
+                12345678 /* halEventReceivedMillis */);
 
         // Write to a parcel
         Parcel parcel = Parcel.obtain();
@@ -353,8 +402,17 @@
                 new ConfidenceLevel[0]);
 
         KeyphraseRecognitionEvent re = new KeyphraseRecognitionEvent(
-                SoundTrigger.RECOGNITION_STATUS_FAILURE, 1, true, 2, 3, 4, false, null, data,
-                kpExtra);
+                SoundTrigger.RECOGNITION_STATUS_FAILURE,
+                1 /* soundModelHandle */,
+                true /* captureAvailable */,
+                2 /* captureSession */,
+                3 /* captureDelayMs */,
+                4 /* capturePreambleMs */,
+                false /* triggerInData */,
+                null /* captureFormat */,
+                data,
+                kpExtra,
+                12345678 /* halEventReceivedMillis */);
 
         // Write to a parcel
         Parcel parcel = Parcel.obtain();
diff --git a/tests/SurfaceViewBufferTests/src/com/android/test/InverseDisplayTransformTests.kt b/tests/SurfaceViewBufferTests/src/com/android/test/InverseDisplayTransformTests.kt
index e722ba5..1de965e 100644
--- a/tests/SurfaceViewBufferTests/src/com/android/test/InverseDisplayTransformTests.kt
+++ b/tests/SurfaceViewBufferTests/src/com/android/test/InverseDisplayTransformTests.kt
@@ -76,4 +76,4 @@
         }
         LayersTraceSubject(trace).layer("SurfaceView", 3).hasBufferSize(rotatedBufferSize)
     }
-}
+}
\ No newline at end of file
diff --git a/tests/SurfaceViewBufferTests/src/com/android/test/SharedBufferModeTests.kt b/tests/SurfaceViewBufferTests/src/com/android/test/SharedBufferModeTests.kt
index be3ed71..4c5224a 100644
--- a/tests/SurfaceViewBufferTests/src/com/android/test/SharedBufferModeTests.kt
+++ b/tests/SurfaceViewBufferTests/src/com/android/test/SharedBufferModeTests.kt
@@ -87,4 +87,4 @@
             checkPixels(svBounds, Color.BLUE)
         }
     }
-}
+}
\ No newline at end of file
diff --git a/tests/SurfaceViewBufferTests/src/com/android/test/SurfaceTracingTestBase.kt b/tests/SurfaceViewBufferTests/src/com/android/test/SurfaceTracingTestBase.kt
index cf4cb8c..a38019d 100644
--- a/tests/SurfaceViewBufferTests/src/com/android/test/SurfaceTracingTestBase.kt
+++ b/tests/SurfaceViewBufferTests/src/com/android/test/SurfaceTracingTestBase.kt
@@ -116,4 +116,4 @@
         private const val TRACE_FLAGS =
                 (1 shl 0) or (1 shl 5) or (1 shl 6) // TRACE_CRITICAL | TRACE_BUFFERS | TRACE_SYNC
     }
-}
+}
\ No newline at end of file
diff --git a/tests/SurfaceViewBufferTests/src/com/android/test/SurfaceViewBufferTestBase.kt b/tests/SurfaceViewBufferTests/src/com/android/test/SurfaceViewBufferTestBase.kt
index bba9678..1770e32 100644
--- a/tests/SurfaceViewBufferTests/src/com/android/test/SurfaceViewBufferTestBase.kt
+++ b/tests/SurfaceViewBufferTests/src/com/android/test/SurfaceViewBufferTestBase.kt
@@ -100,4 +100,4 @@
             INVERSE_DISPLAY(0x08)
         }
     }
-}
+}
\ No newline at end of file
diff --git a/tools/aapt2/SdkConstants.cpp b/tools/aapt2/SdkConstants.cpp
index a7c5479..a766bd4 100644
--- a/tools/aapt2/SdkConstants.cpp
+++ b/tools/aapt2/SdkConstants.cpp
@@ -26,8 +26,8 @@
 namespace aapt {
 
 static ApiVersion sDevelopmentSdkLevel = 10000;
-static const auto sDevelopmentSdkCodeNames =
-    std::unordered_set<StringPiece>({"Q", "R", "S", "Sv2", "Tiramisu", "UpsideDownCake"});
+static const auto sDevelopmentSdkCodeNames = std::unordered_set<StringPiece>(
+    {"Q", "R", "S", "Sv2", "Tiramisu", "UpsideDownCake", "VanillaIceCream"});
 
 static const std::vector<std::pair<uint16_t, ApiVersion>> sAttrIdMap = {
     {0x021c, 1},
diff --git a/tools/aapt2/cmd/Link_test.cpp b/tools/aapt2/cmd/Link_test.cpp
index 28fcc1a..e629baf 100644
--- a/tools/aapt2/cmd/Link_test.cpp
+++ b/tools/aapt2/cmd/Link_test.cpp
@@ -441,8 +441,8 @@
       R"(<resources>
           <public type="attr" name="finalized_res" id="0x01010001"/>
 
-          <!-- S staged attributes (support staged resources in the same type id) -->
-          <staging-public-group type="attr" first-id="0x01010050">
+          <!-- S staged attributes (Not support staged resources in the same type id) -->
+          <staging-public-group type="attr" first-id="0x01fc0050">
             <public name="staged_s_res" />
           </staging-public-group>
 
@@ -480,8 +480,8 @@
           <public type="attr" name="staged_s2_res" id="0x01010003"/>
           <public type="string" name="staged_s_string" id="0x01020000"/>
 
-          <!-- S staged attributes (support staged resources in the same type id) -->
-          <staging-public-group-final type="attr" first-id="0x01010050">
+          <!-- S staged attributes (Not support staged resources in the same type id) -->
+          <staging-public-group-final type="attr" first-id="0x01fc0050">
             <public name="staged_s_res" />
           </staging-public-group-final>
 
@@ -551,7 +551,7 @@
   EXPECT_THAT(android_r_contents, HasSubstr("public static final int finalized_res=0x01010001;"));
   EXPECT_THAT(
       android_r_contents,
-      HasSubstr("public static final int staged_s_res; static { staged_s_res=0x01010050; }"));
+      HasSubstr("public static final int staged_s_res; static { staged_s_res=0x01fc0050; }"));
   EXPECT_THAT(
       android_r_contents,
       HasSubstr("public static final int staged_s_string; static { staged_s_string=0x01fd0080; }"));
@@ -583,7 +583,7 @@
 
   result = am.GetResourceId("android:attr/staged_s_res");
   ASSERT_TRUE(result.has_value());
-  EXPECT_THAT(*result, Eq(0x01010050));
+  EXPECT_THAT(*result, Eq(0x01fc0050));
 
   result = am.GetResourceId("android:string/staged_s_string");
   ASSERT_TRUE(result.has_value());
diff --git a/tools/aapt2/compile/IdAssigner.cpp b/tools/aapt2/compile/IdAssigner.cpp
index b3f98a9..5421abd 100644
--- a/tools/aapt2/compile/IdAssigner.cpp
+++ b/tools/aapt2/compile/IdAssigner.cpp
@@ -37,6 +37,7 @@
 
 template <typename Id, typename Key>
 struct NextIdFinder {
+  std::map<Id, Key> pre_assigned_ids_;
   explicit NextIdFinder(Id start_id = 0u) : next_id_(start_id){};
 
   // Attempts to reserve an identifier for the specified key.
@@ -55,7 +56,6 @@
   Id next_id_;
   bool next_id_called_ = false;
   bool exhausted_ = false;
-  std::map<Id, Key> pre_assigned_ids_;
   typename std::map<Id, Key>::iterator next_preassigned_id_;
 };
 
@@ -158,7 +158,7 @@
   }
 
   if (assigned_id_map_) {
-    // Reserve all the IDs mentioned in the stable ID map. That way we won't assig IDs that were
+    // Reserve all the IDs mentioned in the stable ID map. That way we won't assign IDs that were
     // listed in the map if they don't exist in the table.
     for (const auto& stable_id_entry : *assigned_id_map_) {
       const ResourceName& pre_assigned_name = stable_id_entry.first;
@@ -191,6 +191,11 @@
 }
 
 namespace {
+static const std::string_view staged_type_overlap_error =
+    "Staged public resource type IDs have conflict with non staged public resources type "
+    "IDs, please restart staged resource type ID assignment at 0xff in public-staging.xml "
+    "and also delete all the overlapping groups in public-final.xml";
+
 template <typename Id, typename Key>
 Result<Id> NextIdFinder<Id, Key>::ReserveId(Key key, Id id) {
   CHECK(!next_id_called_) << "ReserveId cannot be called after NextId";
@@ -282,8 +287,20 @@
     // another type.
     auto assign_result = type_id_finder_.ReserveId(key, id.type_id());
     if (!assign_result.has_value()) {
-      diag->Error(android::DiagMessage() << "can't assign ID " << id << " to resource " << name
-                                         << " because type " << assign_result.error());
+      auto pre_assigned_type = type_id_finder_.pre_assigned_ids_[id.type_id()].type;
+      bool pre_assigned_type_staged =
+          non_staged_type_ids_.find(pre_assigned_type) == non_staged_type_ids_.end();
+      auto hex_type_id = fmt::format("{:#04x}", (int)id.type_id());
+      bool current_type_staged = visibility.staged_api;
+      diag->Error(android::DiagMessage()
+                  << "can't assign type ID " << hex_type_id << " to "
+                  << (current_type_staged ? "staged type " : "non staged type ") << name.type.type
+                  << " because this type ID have been assigned to "
+                  << (pre_assigned_type_staged ? "staged type " : "non staged type ")
+                  << pre_assigned_type);
+      if (pre_assigned_type_staged || current_type_staged) {
+        diag->Error(android::DiagMessage() << staged_type_overlap_error);
+      }
       return false;
     }
     type = types_.emplace(key, TypeGroup(package_id_, id.type_id())).first;
@@ -298,6 +315,20 @@
                   << " because type already has ID " << std::hex << (int)id.type_id());
       return false;
     }
+  } else {
+    // Ensure that staged public resources cannot have the same type name and type id with
+    // non staged public resources.
+    auto non_staged_type = non_staged_type_ids_.find(name.type.type);
+    if (non_staged_type != non_staged_type_ids_.end() && non_staged_type->second == id.type_id()) {
+      diag->Error(
+          android::DiagMessage()
+          << "can`t assign type ID " << fmt::format("{:#04x}", (int)id.type_id())
+          << " to staged type " << name.type.type << " because type ID "
+          << fmt::format("{:#04x}", (int)id.type_id())
+          << " already has been assigned to a non staged resource type with the same type name");
+      diag->Error(android::DiagMessage() << staged_type_overlap_error);
+      return false;
+    }
   }
 
   auto assign_result = type->second.ReserveId(name, id);
diff --git a/tools/aapt2/compile/IdAssigner_test.cpp b/tools/aapt2/compile/IdAssigner_test.cpp
index 8911dad..ce45b7c 100644
--- a/tools/aapt2/compile/IdAssigner_test.cpp
+++ b/tools/aapt2/compile/IdAssigner_test.cpp
@@ -117,14 +117,28 @@
 }
 
 TEST_F(IdAssignerTests, FailWhenTypeHasTwoNonStagedIdsRegardlessOfStagedId) {
-  auto table = test::ResourceTableBuilder()
-                   .AddSimple("android:attr/foo", ResourceId(0x01050000))
-                   .AddSimple("android:attr/bar", ResourceId(0x01ff0006))
-                   .Add(NewResourceBuilder("android:attr/staged_baz")
-                            .SetId(0x01ff0000)
-                            .SetVisibility({.staged_api = true})
-                            .Build())
-                   .Build();
+  auto table =
+      test::ResourceTableBuilder()
+          .AddSimple("android:attr/foo", ResourceId(0x01050000))
+          .AddSimple("android:attr/bar", ResourceId(0x01ff0006))
+          .Add(NewResourceBuilder("android:attr/staged_baz")
+                   .SetId(0x01ff0000)
+                   .SetVisibility({.staged_api = true, .level = Visibility::Level::kPublic})
+                   .Build())
+          .Build();
+  IdAssigner assigner;
+  ASSERT_FALSE(assigner.Consume(context.get(), table.get()));
+}
+
+TEST_F(IdAssignerTests, FailWhenTypeHaveBothStagedAndNonStagedIds) {
+  auto table =
+      test::ResourceTableBuilder()
+          .AddSimple("android:attr/foo", ResourceId(0x01010000))
+          .Add(NewResourceBuilder("android:bool/staged_baz")
+                   .SetId(0x01010001)
+                   .SetVisibility({.staged_api = true, .level = Visibility::Level::kPublic})
+                   .Build())
+          .Build();
   IdAssigner assigner;
   ASSERT_FALSE(assigner.Consume(context.get(), table.get()));
 }
diff --git a/tools/lint/framework/checks/src/main/java/com/google/android/lint/RegisterReceiverFlagDetector.kt b/tools/lint/framework/checks/src/main/java/com/google/android/lint/RegisterReceiverFlagDetector.kt
index c3e0428..28027a7 100644
--- a/tools/lint/framework/checks/src/main/java/com/google/android/lint/RegisterReceiverFlagDetector.kt
+++ b/tools/lint/framework/checks/src/main/java/com/google/android/lint/RegisterReceiverFlagDetector.kt
@@ -111,7 +111,7 @@
 
         if (!isProtected) {
             val actionsList = unprotectedActionsList.joinToString(", ", "", "", -1, "")
-            val message = "$receiverArg is missing 'RECEIVED_EXPORTED` or 'RECEIVE_NOT_EXPORTED' " +
+            val message = "$receiverArg is missing 'RECEIVER_EXPORTED` or 'RECEIVER_NOT_EXPORTED' " +
                             "flag for unprotected broadcast(s) registered for $actionsList."
             if (flagsArg == null) {
                 context.report(
diff --git a/tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/EnforcePermissionDetectorTest.kt b/tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/EnforcePermissionDetectorTest.kt
index f7560a7..75b0073 100644
--- a/tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/EnforcePermissionDetectorTest.kt
+++ b/tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/EnforcePermissionDetectorTest.kt
@@ -321,6 +321,34 @@
             )
     }
 
+    fun testDoesDetectIssuesShortStringsNotAllowed() {
+        lint().files(java(
+            """
+            package test.pkg;
+            import android.annotation.EnforcePermission;
+            public class TestClass121 extends IFooMethod.Stub {
+                @Override
+                @EnforcePermission(anyOf={"INTERNET", "READ_PHONE_STATE"})
+                public void testMethodAnyLiteral() {}
+            }
+            """).indented(),
+            *stubs
+        )
+            .run()
+            .expect(
+                """
+                src/test/pkg/TestClass121.java:6: Error: The method \
+                TestClass121.testMethodAnyLiteral is annotated with @EnforcePermission(anyOf={"INTERNET", "READ_PHONE_STATE"}) \
+                which differs from the overridden method Stub.testMethodAnyLiteral: \
+                @android.annotation.EnforcePermission(anyOf={android.Manifest.permission.INTERNET, "android.permission.READ_PHONE_STATE"}). \
+                The same annotation must be used for both methods. [MismatchingEnforcePermissionAnnotation]
+                    public void testMethodAnyLiteral() {}
+                                ~~~~~~~~~~~~~~~~~~~~
+                1 errors, 0 warnings
+                """.addLineContinuation()
+            )
+    }
+
     /* Stubs */
 
     // A service with permission annotation on the method.