Merge "replace the hardcode for min/max sample rate with audio.h in jni" into main
diff --git a/api/coverage/tools/ExtractFlaggedApis.kt b/api/coverage/tools/ExtractFlaggedApis.kt
index 5efda98..bf67187 100644
--- a/api/coverage/tools/ExtractFlaggedApis.kt
+++ b/api/coverage/tools/ExtractFlaggedApis.kt
@@ -75,10 +75,10 @@
 fun getClassFlag(classItem: ClassItem): String? {
     var classFlag = getFlagAnnotation(classItem)
     var cur = classItem
-    // If a class is not an inner class, use its @FlaggedApi annotation value.
+    // If a class is not a nested class, use its @FlaggedApi annotation value.
     // Otherwise, use the flag value of the closest outer class that is annotated by @FlaggedApi.
-    while (cur.isInnerClass() && classFlag == null) {
-        cur = cur.parent() as ClassItem
+    while (classFlag == null) {
+        cur = cur.containingClass() ?: break
         classFlag = getFlagAnnotation(cur)
     }
     return classFlag
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 5aa89b9..805cfb7 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -3738,6 +3738,7 @@
     method @Nullable @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public android.content.Intent registerReceiverForAllUsers(@Nullable android.content.BroadcastReceiver, @NonNull android.content.IntentFilter, @Nullable String, @Nullable android.os.Handler, int);
     method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public abstract void sendBroadcastAsUser(@RequiresPermission android.content.Intent, android.os.UserHandle, @Nullable String, @Nullable android.os.Bundle);
     method public void sendBroadcastMultiplePermissions(@NonNull android.content.Intent, @NonNull String[], @Nullable android.app.BroadcastOptions);
+    method @FlaggedApi("android.os.ordered_broadcast_multiple_permissions") public void sendOrderedBroadcastMultiplePermissions(@NonNull android.content.Intent, @NonNull String[], @Nullable String, @Nullable android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle, @Nullable android.os.Bundle);
     method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public void startActivityAsUser(@NonNull @RequiresPermission android.content.Intent, @NonNull android.os.UserHandle);
     method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public void startActivityAsUser(@NonNull @RequiresPermission android.content.Intent, @Nullable android.os.Bundle, @NonNull android.os.UserHandle);
     field public static final String AMBIENT_CONTEXT_SERVICE = "ambient_context";
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index af56cb4..d1bd88c 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -1524,6 +1524,17 @@
     public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
             String receiverPermission, int appOp, Bundle options, BroadcastReceiver resultReceiver,
             Handler scheduler, int initialCode, String initialData, Bundle initialExtras) {
+        String[] receiverPermissions = receiverPermission == null ? null
+                : new String[] {receiverPermission};
+        sendOrderedBroadcastAsUserMultiplePermissions(intent, user, receiverPermissions, appOp,
+                options, resultReceiver, scheduler, initialCode, initialData, initialExtras);
+    }
+
+    @Override
+    public void sendOrderedBroadcastAsUserMultiplePermissions(Intent intent, UserHandle user,
+            String[] receiverPermissions, int appOp, Bundle options,
+            BroadcastReceiver resultReceiver, Handler scheduler, int initialCode,
+            String initialData, Bundle initialExtras) {
         IIntentReceiver rd = null;
         if (resultReceiver != null) {
             if (mPackageInfo != null) {
@@ -1543,8 +1554,6 @@
             }
         }
         String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
-        String[] receiverPermissions = receiverPermission == null ? null
-                : new String[] {receiverPermission};
         try {
             intent.prepareToLeaveProcess(this);
             ActivityManager.getService().broadcastIntentWithFeature(
@@ -1571,6 +1580,20 @@
     }
 
     @Override
+    public void sendOrderedBroadcastMultiplePermissions(Intent intent, String[] receiverPermissions,
+            String receiverAppOp, BroadcastReceiver resultReceiver, Handler scheduler,
+            int initialCode, String initialData, @Nullable Bundle initialExtras,
+            @Nullable Bundle options) {
+        int intAppOp = AppOpsManager.OP_NONE;
+        if (!TextUtils.isEmpty(receiverAppOp)) {
+            intAppOp = AppOpsManager.strOpToOp(receiverAppOp);
+        }
+        sendOrderedBroadcastAsUserMultiplePermissions(intent, getUser(), receiverPermissions,
+                intAppOp, options, resultReceiver, scheduler, initialCode, initialData,
+                initialExtras);
+    }
+
+    @Override
     public void sendOrderedBroadcast(Intent intent, int initialCode, String receiverPermission,
             String receiverAppOp, BroadcastReceiver resultReceiver, Handler scheduler,
             String initialData, @Nullable Bundle initialExtras, Bundle options) {
diff --git a/core/java/android/app/admin/OWNERS b/core/java/android/app/admin/OWNERS
index 308f1d6..4f3f5d9 100644
--- a/core/java/android/app/admin/OWNERS
+++ b/core/java/android/app/admin/OWNERS
@@ -1,7 +1,6 @@
 # Bug component: 142675
 # Assign bugs to device-policy-manager-triage@google.com
 
-file:WorkDeviceExperience_OWNERS
 file:EnterprisePlatformSecurity_OWNERS
 
 yamasani@google.com #{LAST_RESORT_SUGGESTION}
\ No newline at end of file
diff --git a/core/java/android/app/assist/OWNERS b/core/java/android/app/assist/OWNERS
index e4ffd7f..b53bdc2 100644
--- a/core/java/android/app/assist/OWNERS
+++ b/core/java/android/app/assist/OWNERS
@@ -1,2 +1 @@
-hackz@google.com
-volnov@google.com
\ No newline at end of file
+srazdan@google.com
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index a6eed50..b121da3 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -2916,6 +2916,23 @@
             @Nullable String initialData, @Nullable  Bundle initialExtras);
 
     /**
+     * Similar to above but takes array of names of permissions that a receiver must hold in order
+     * to receive your broadcast. If empty, no permissions are required.
+     *
+     * @see #sendOrderedBroadcastAsUser(Intent, UserHandle, String,
+     *       BroadcastReceiver, Handler, int, String, Bundle)
+     * @hide
+     */
+    @SuppressWarnings("HiddenAbstractMethod")
+    @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS)
+    public void sendOrderedBroadcastAsUserMultiplePermissions(Intent intent,
+            UserHandle user, String[] receiverPermissions, int appOp, Bundle options,
+            BroadcastReceiver resultReceiver, Handler scheduler, int initialCode,
+            String initialData, Bundle initialExtras) {
+        throw new RuntimeException("Not implemented. Must override in a subclass.");
+    }
+
+    /**
      * Version of
      * {@link #sendOrderedBroadcast(Intent, String, BroadcastReceiver, Handler, int, String,
      * Bundle)} that allows you to specify the App Op to enforce restrictions on which receivers
@@ -2997,6 +3014,21 @@
     }
 
     /**
+     * Like {@link #sendOrderedBroadcast(Intent, String, String, BroadcastReceiver, Handler, int,
+     * String, Bundle)}, but also allows specification of a list of multiple permissions.
+     * @hide
+     */
+    @FlaggedApi(Flags.FLAG_ORDERED_BROADCAST_MULTIPLE_PERMISSIONS)
+    @SystemApi
+    public void sendOrderedBroadcastMultiplePermissions(
+            @NonNull Intent intent, @NonNull String[] receiverPermissions,
+            @Nullable String receiverAppOp, @Nullable BroadcastReceiver resultReceiver,
+            @Nullable Handler scheduler, int initialCode, @Nullable String initialData,
+            @Nullable Bundle initialExtras, @Nullable Bundle options) {
+        throw new RuntimeException("Not implemented. Must override in a subclass.");
+    }
+
+    /**
      * <p>Perform a {@link #sendBroadcast(Intent)} that is "sticky," meaning the
      * Intent you are sending stays around after the broadcast is complete,
      * so that others can quickly retrieve that data through the return
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index a475c29..79fa6ea 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -652,6 +652,16 @@
                 resultReceiver, scheduler, initialCode, initialData, initialExtras);
     }
 
+    /** @hide */
+    @Override
+    public void sendOrderedBroadcastAsUserMultiplePermissions(Intent intent, UserHandle user,
+            @Nullable String[] receiverPermission, int appOp, @Nullable Bundle options,
+            @Nullable BroadcastReceiver resultReceiver, @Nullable Handler scheduler,
+            int initialCode, @Nullable String initialData, @Nullable Bundle initialExtras) {
+        mBase.sendOrderedBroadcastAsUserMultiplePermissions(intent, user, receiverPermission, appOp,
+                options, resultReceiver, scheduler, initialCode, initialData, initialExtras);
+    }
+
     @Override
     public void sendOrderedBroadcast(@RequiresPermission @NonNull Intent intent,
             @Nullable String receiverPermission, @Nullable String receiverAppOp,
@@ -661,6 +671,17 @@
                 scheduler, initialCode, initialData, initialExtras);
     }
 
+    /** @hide */
+    @Override
+    public void sendOrderedBroadcastMultiplePermissions(
+            @NonNull Intent intent, @NonNull String[] receiverPermissions,
+            @Nullable String receiverAppOp, @Nullable BroadcastReceiver resultReceiver,
+            @Nullable Handler scheduler, int initialCode, @Nullable String initialData,
+            @Nullable Bundle initialExtras, @Nullable Bundle options) {
+        mBase.sendOrderedBroadcastMultiplePermissions(intent, receiverPermissions, receiverAppOp,
+                resultReceiver, scheduler, initialCode, initialData, initialExtras, options);
+    }
+
     @Override
     public void sendOrderedBroadcast(@RequiresPermission @NonNull Intent intent, int initialCode,
             @Nullable String receiverPermission, @Nullable String receiverAppOp,
diff --git a/core/java/android/hardware/OWNERS b/core/java/android/hardware/OWNERS
index 51ad151..43d3f54 100644
--- a/core/java/android/hardware/OWNERS
+++ b/core/java/android/hardware/OWNERS
@@ -5,7 +5,7 @@
 sumir@google.com
 
 # Camera
-per-file *Camera*=cychen@google.com,epeev@google.com,etalvala@google.com,shuzhenwang@google.com,zhijunhe@google.com,jchowdhary@google.com
+per-file *Camera*=file:platform/frameworks/av:/camera/OWNERS
 
 # Sensor Privacy
 per-file *SensorPrivacy* = file:platform/frameworks/native:/libs/sensorprivacy/OWNERS
diff --git a/core/java/android/os/flags.aconfig b/core/java/android/os/flags.aconfig
index ca69457..200c1d8 100644
--- a/core/java/android/os/flags.aconfig
+++ b/core/java/android/os/flags.aconfig
@@ -68,6 +68,14 @@
 }
 
 flag {
+    name: "ordered_broadcast_multiple_permissions"
+    is_exported: true
+    namespace: "bluetooth"
+    description: "Guards the Context.sendOrderedBroadcastMultiplePermissions API"
+    bug: "345802719"
+}
+
+flag {
     name: "battery_saver_supported_check_api"
     namespace: "backstage_power"
     description: "Guards a new API in PowerManager to check if battery saver is supported or not."
diff --git a/core/java/android/view/autofill/OWNERS b/core/java/android/view/autofill/OWNERS
index 898947a..7f3b4e5 100644
--- a/core/java/android/view/autofill/OWNERS
+++ b/core/java/android/view/autofill/OWNERS
@@ -1,10 +1,11 @@
 # Bug component: 351486
 
-simranjit@google.com
 haoranzhang@google.com
+jiewenlei@google.com
+simranjit@google.com
 skxu@google.com
+shuc@google.com
 yunicorn@google.com
-reemabajwa@google.com
 
 # Bug component: 543785 = per-file *Augmented*
 per-file *Augmented* = wangqi@google.com
diff --git a/core/java/com/android/internal/widget/ILockSettings.aidl b/core/java/com/android/internal/widget/ILockSettings.aidl
index 8236783..511c680 100644
--- a/core/java/com/android/internal/widget/ILockSettings.aidl
+++ b/core/java/com/android/internal/widget/ILockSettings.aidl
@@ -109,4 +109,5 @@
     boolean isWeakEscrowTokenActive(long handle, int userId);
     boolean isWeakEscrowTokenValid(long handle, in byte[] token, int userId);
     void unlockUserKeyIfUnsecured(int userId);
+    boolean writeRepairModeCredential(int userId);
 }
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index e46b8d7..f4ad487 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -449,6 +449,21 @@
     }
 
     /**
+     * Save the current password data to the repair mode file.
+     *
+     * @return true if success or false otherwise.
+     */
+    public boolean writeRepairModeCredential(int userId) {
+        throwIfCalledOnMainThread();
+        try {
+            return getLockSettings().writeRepairModeCredential(userId);
+        } catch (RemoteException re) {
+            Log.e(TAG, "Failed to write repair mode credential", re);
+            return false;
+        }
+    }
+
+    /**
      * Check to see if a credential matches the saved one.
      * If credential matches, return an opaque attestation that the challenge was verified.
      *
diff --git a/core/java/com/android/internal/widget/LockPatternView.java b/core/java/com/android/internal/widget/LockPatternView.java
index 0734e68..11c220b 100644
--- a/core/java/com/android/internal/widget/LockPatternView.java
+++ b/core/java/com/android/internal/widget/LockPatternView.java
@@ -261,6 +261,8 @@
         public float lineEndY = Float.MIN_VALUE;
         @Nullable
         Animator activationAnimator;
+        @Nullable
+        Animator deactivationAnimator;
      }
 
     /**
@@ -667,7 +669,7 @@
      */
     private void resetPattern() {
         if (mKeepDotActivated && !mPattern.isEmpty()) {
-            resetLastActivatedCellProgress();
+            resetPatternCellSize();
         }
         mPattern.clear();
         mPatternPath.reset();
@@ -676,14 +678,20 @@
         invalidate();
     }
 
-    private void resetLastActivatedCellProgress() {
-        final ArrayList<Cell> pattern = mPattern;
-        final Cell lastCell = pattern.get(pattern.size() - 1);
-        final CellState cellState = mCellStates[lastCell.row][lastCell.column];
-        if (cellState.activationAnimator != null) {
-            cellState.activationAnimator.cancel();
+    private void resetPatternCellSize() {
+        for (int i = 0; i < mCellStates.length; i++) {
+            for (int j = 0; j < mCellStates[i].length; j++) {
+                CellState cellState = mCellStates[i][j];
+                if (cellState.activationAnimator != null) {
+                    cellState.activationAnimator.cancel();
+                }
+                if (cellState.deactivationAnimator != null) {
+                    cellState.deactivationAnimator.cancel();
+                }
+                cellState.activationAnimationProgress = 0f;
+                cellState.radius = mDotSize / 2f;
+            }
         }
-        cellState.activationAnimationProgress = 0f;
     }
 
     /**
@@ -819,12 +827,16 @@
                     !mPatternDrawLookup[fillInGapCell.row][fillInGapCell.column]) {
                 addCellToPattern(fillInGapCell);
                 if (mKeepDotActivated) {
-                    startCellDeactivatedAnimation(fillInGapCell);
+                    if (mFadePattern) {
+                        startCellDeactivatedAnimation(fillInGapCell, /* fillInGap= */ true);
+                    } else {
+                        startCellActivatedAnimation(fillInGapCell);
+                    }
                 }
             }
 
             if (mKeepDotActivated && lastCell != null) {
-                startCellDeactivatedAnimation(lastCell);
+                startCellDeactivatedAnimation(lastCell, /* fillInGap= */ false);
             }
 
             addCellToPattern(cell);
@@ -872,17 +884,25 @@
     }
 
     private void startCellActivatedAnimation(Cell cell) {
-        startCellActivationAnimation(cell, CELL_ACTIVATE);
+        startCellActivationAnimation(cell, CELL_ACTIVATE, /* fillInGap= */ false);
     }
 
-    private void startCellDeactivatedAnimation(Cell cell) {
-        startCellActivationAnimation(cell, CELL_DEACTIVATE);
+    private void startCellDeactivatedAnimation(Cell cell, boolean fillInGap) {
+        startCellActivationAnimation(cell, CELL_DEACTIVATE, /* fillInGap= */ fillInGap);
     }
 
-    private void startCellActivationAnimation(Cell cell, int activate) {
+    /**
+     * Start cell animation.
+     * @param cell The cell to be animated.
+     * @param activate Whether the cell is being activated or deactivated.
+     * @param fillInGap Whether the cell is a gap cell, i.e. filled in based on current pattern.
+     */
+    private void startCellActivationAnimation(Cell cell, int activate, boolean fillInGap) {
         final CellState cellState = mCellStates[cell.row][cell.column];
 
-        if (cellState.activationAnimator != null) {
+        // When mKeepDotActivated is true, don't cancel the previous animator since it would leave
+        // a dot in an in-between size if the next dot is reached before the animation is finished.
+        if (cellState.activationAnimator != null && !mKeepDotActivated) {
             cellState.activationAnimator.cancel();
         }
         AnimatorSet animatorSet = new AnimatorSet();
@@ -898,24 +918,37 @@
                 .with(createLineEndAnimation(cellState, startX, startY,
                         getCenterXForColumn(cell.column), getCenterYForRow(cell.row)));
         if (mDotSize != mDotSizeActivated) {
-            animatorSetBuilder.with(createDotRadiusAnimation(cellState));
+            animatorSetBuilder.with(createDotRadiusAnimation(cellState, activate, fillInGap));
         }
         if (mDotColor != mDotActivatedColor) {
-            animatorSetBuilder.with(createDotActivationColorAnimation(cellState, activate));
+            animatorSetBuilder.with(
+                    createDotActivationColorAnimation(cellState, activate, fillInGap));
         }
 
-        animatorSet.addListener(new AnimatorListenerAdapter() {
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                cellState.activationAnimator = null;
-                invalidate();
-            }
-        });
-        cellState.activationAnimator = animatorSet;
+        if (activate == CELL_ACTIVATE) {
+            animatorSet.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    cellState.activationAnimator = null;
+                    invalidate();
+                }
+            });
+            cellState.activationAnimator = animatorSet;
+        } else {
+            animatorSet.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    cellState.deactivationAnimator = null;
+                    invalidate();
+                }
+            });
+            cellState.deactivationAnimator = animatorSet;
+        }
         animatorSet.start();
     }
 
-    private Animator createDotActivationColorAnimation(CellState cellState, int activate) {
+    private Animator createDotActivationColorAnimation(
+            CellState cellState, int activate, boolean fillInGap) {
         ValueAnimator.AnimatorUpdateListener updateListener =
                 valueAnimator -> {
                     cellState.activationAnimationProgress =
@@ -934,7 +967,7 @@
         deactivateAnimator.setDuration(DOT_ACTIVATION_DURATION_MILLIS);
         AnimatorSet set = new AnimatorSet();
 
-        if (mKeepDotActivated) {
+        if (mKeepDotActivated && !fillInGap) {
             set.play(activate == CELL_ACTIVATE ? activateAnimator : deactivateAnimator);
         } else {
             // 'activate' ignored in this case, do full deactivate -> activate cycle
@@ -977,7 +1010,7 @@
         return valueAnimator;
     }
 
-    private Animator createDotRadiusAnimation(CellState state) {
+    private Animator createDotRadiusAnimation(CellState state, int activate, boolean fillInGap) {
         float defaultRadius = mDotSize / 2f;
         float activatedRadius = mDotSizeActivated / 2f;
 
@@ -998,7 +1031,19 @@
         deactivationAnimator.setDuration(DOT_RADIUS_DECREASE_DURATION_MILLIS);
 
         AnimatorSet set = new AnimatorSet();
-        set.playSequentially(activationAnimator, deactivationAnimator);
+        if (mKeepDotActivated) {
+            if (mFadePattern) {
+                if (fillInGap) {
+                    set.playSequentially(activationAnimator, deactivationAnimator);
+                } else {
+                    set.play(activate == CELL_ACTIVATE ? activationAnimator : deactivationAnimator);
+                }
+            } else if (activate == CELL_ACTIVATE) {
+                set.play(activationAnimator);
+            }
+        } else {
+            set.playSequentially(activationAnimator, deactivationAnimator);
+        }
         return set;
     }
 
@@ -1176,9 +1221,15 @@
         // report pattern detected
         if (!mPattern.isEmpty()) {
             setPatternInProgress(false);
-            cancelLineAnimations();
             if (mKeepDotActivated) {
+                // When mKeepDotActivated is true, cancelling dot animations and resetting dot radii
+                // are handled in #resetPattern(), since we want to keep the dots activated until
+                // the pattern are reset.
                 deactivateLastCell();
+            } else {
+                // When mKeepDotActivated is false, cancelling animations and resetting dot radii
+                // are handled here.
+                cancelLineAnimations();
             }
             notifyPatternDetected();
             // Also clear pattern if fading is enabled
@@ -1198,7 +1249,7 @@
 
     private void deactivateLastCell() {
         Cell lastCell = mPattern.get(mPattern.size() - 1);
-        startCellDeactivatedAnimation(lastCell);
+        startCellDeactivatedAnimation(lastCell, /* fillInGap= */ false);
     }
 
     private void cancelLineAnimations() {
diff --git a/core/java/com/android/internal/widget/OWNERS b/core/java/com/android/internal/widget/OWNERS
index e2672f5..cf2f202 100644
--- a/core/java/com/android/internal/widget/OWNERS
+++ b/core/java/com/android/internal/widget/OWNERS
@@ -9,18 +9,18 @@
 per-file *LockSettings* = file:/services/core/java/com/android/server/locksettings/OWNERS
 
 # Notification related
-per-file *Notification* = file:/services/core/java/com/android/server/notification/OWNERS
-per-file *Messaging* = file:/services/core/java/com/android/server/notification/OWNERS
-per-file *Message* = file:/services/core/java/com/android/server/notification/OWNERS
-per-file *Conversation* = file:/services/core/java/com/android/server/notification/OWNERS
-per-file *People* = file:/services/core/java/com/android/server/notification/OWNERS
-per-file *ImageResolver* = file:/services/core/java/com/android/server/notification/OWNERS
-per-file CallLayout.java = file:/services/core/java/com/android/server/notification/OWNERS
-per-file CachingIconView.java = file:/services/core/java/com/android/server/notification/OWNERS
-per-file ImageFloatingTextView.java = file:/services/core/java/com/android/server/notification/OWNERS
-per-file ObservableTextView.java = file:/services/core/java/com/android/server/notification/OWNERS
-per-file RemeasuringLinearLayout.java = file:/services/core/java/com/android/server/notification/OWNERS
-per-file ViewClippingUtil.java = file:/services/core/java/com/android/server/notification/OWNERS
+per-file *Notification* = file:/packages/SystemUI/src/com/android/systemui/statusbar/notification/OWNERS
+per-file *Messaging* = file:/packages/SystemUI/src/com/android/systemui/statusbar/notification/OWNERS
+per-file *Message* = file:/packages/SystemUI/src/com/android/systemui/statusbar/notification/OWNERS
+per-file *Conversation* = file:/packages/SystemUI/src/com/android/systemui/statusbar/notification/OWNERS
+per-file *People* = file:/packages/SystemUI/src/com/android/systemui/statusbar/notification/OWNERS
+per-file *ImageResolver* = file:/packages/SystemUI/src/com/android/systemui/statusbar/notification/OWNERS
+per-file CallLayout.java = file:/packages/SystemUI/src/com/android/systemui/statusbar/notification/OWNERS
+per-file CachingIconView.java = file:/packages/SystemUI/src/com/android/systemui/statusbar/notification/OWNERS
+per-file ImageFloatingTextView.java = file:/packages/SystemUI/src/com/android/systemui/statusbar/notification/OWNERS
+per-file ObservableTextView.java = file:/packages/SystemUI/src/com/android/systemui/statusbar/notification/OWNERS
+per-file RemeasuringLinearLayout.java = file:/packages/SystemUI/src/com/android/systemui/statusbar/notification/OWNERS
+per-file ViewClippingUtil.java = file:/packages/SystemUI/src/com/android/systemui/statusbar/notification/OWNERS
 
 # Appwidget related
 per-file *RemoteViews* = file:/services/appwidget/java/com/android/server/appwidget/OWNERS
diff --git a/core/tests/coretests/src/com/android/internal/widget/LockPatternUtilsTest.java b/core/tests/coretests/src/com/android/internal/widget/LockPatternUtilsTest.java
index b90480a..92a7d8e 100644
--- a/core/tests/coretests/src/com/android/internal/widget/LockPatternUtilsTest.java
+++ b/core/tests/coretests/src/com/android/internal/widget/LockPatternUtilsTest.java
@@ -68,6 +68,7 @@
 
 import java.nio.charset.StandardCharsets;
 import java.util.List;
+import java.util.concurrent.CompletableFuture;
 
 @RunWith(AndroidJUnit4.class)
 @SmallTest
@@ -316,6 +317,40 @@
         assertNotEquals(UserHandle.USER_CURRENT_OR_SELF, LockPatternUtils.USER_REPAIR_MODE);
     }
 
+    @Test
+    public void testWriteRepairModeCredential_mainThread() {
+        createTestLockSettings();
+        var context = InstrumentationRegistry.getTargetContext();
+
+        var future = new CompletableFuture<Exception>();
+        context.getMainThreadHandler().post(() -> {
+            try {
+                mLockPatternUtils.writeRepairModeCredential(USER_ID);
+                future.complete(null);
+            } catch (Exception e) {
+                future.complete(e);
+            }
+        });
+
+        var e = future.join();
+        assertThat(e).isNotNull();
+        assertThat(e.getMessage()).contains("should not be called from the main thread");
+    }
+
+    @Test
+    public void testWriteRepairModeCredential() throws Exception {
+        var ils = createTestLockSettings();
+
+        when(ils.writeRepairModeCredential(USER_ID)).thenReturn(false);
+        assertThat(mLockPatternUtils.writeRepairModeCredential(USER_ID)).isFalse();
+
+        when(ils.writeRepairModeCredential(USER_ID)).thenReturn(true);
+        assertThat(mLockPatternUtils.writeRepairModeCredential(USER_ID)).isTrue();
+
+        when(ils.writeRepairModeCredential(USER_ID)).thenThrow(new RemoteException());
+        assertThat(mLockPatternUtils.writeRepairModeCredential(USER_ID)).isFalse();
+    }
+
     private TestStrongAuthTracker createStrongAuthTracker() {
         final Context context = new ContextWrapper(InstrumentationRegistry.getTargetContext());
         return new TestStrongAuthTracker(context, Looper.getMainLooper());
diff --git a/data/etc/OWNERS b/data/etc/OWNERS
index 701d145..85dae63 100644
--- a/data/etc/OWNERS
+++ b/data/etc/OWNERS
@@ -1,6 +1,5 @@
 include /PACKAGE_MANAGER_OWNERS
 
-alanstokes@google.com
 cbrubaker@google.com
 hackbod@android.com
 hackbod@google.com
diff --git a/libs/WindowManager/Shell/OWNERS b/libs/WindowManager/Shell/OWNERS
index ebebd8a..cb422ea 100644
--- a/libs/WindowManager/Shell/OWNERS
+++ b/libs/WindowManager/Shell/OWNERS
@@ -1,5 +1,5 @@
 xutan@google.com
 
 # Give submodule owners in shell resource approval
-per-file res*/*/*.xml = atsjenk@google.com, hwwang@google.com, jorgegil@google.com, lbill@google.com, madym@google.com, nmusgrave@google.com, pbdr@google.com, tkachenkoi@google.com, mpodolian@google.com, liranb@google.com
+per-file res*/*/*.xml = atsjenk@google.com, hwwang@google.com, jorgegil@google.com, lbill@google.com, madym@google.com, vaniadesmonda@google.com, pbdr@google.com, tkachenkoi@google.com, mpodolian@google.com, liranb@google.com
 per-file res*/*/tv_*.xml = bronger@google.com
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/util/OWNERS b/libs/WindowManager/Shell/src/com/android/wm/shell/util/OWNERS
new file mode 100644
index 0000000..482aaab
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/util/OWNERS
@@ -0,0 +1 @@
+per-file KtProtolog.kt = file:platform/development:/tools/winscope/OWNERS
diff --git a/libs/WindowManager/Shell/tests/OWNERS b/libs/WindowManager/Shell/tests/OWNERS
index 0f24bb5..2a0a28e 100644
--- a/libs/WindowManager/Shell/tests/OWNERS
+++ b/libs/WindowManager/Shell/tests/OWNERS
@@ -9,7 +9,7 @@
 chenghsiuchang@google.com
 atsjenk@google.com
 jorgegil@google.com
-nmusgrave@google.com
+vaniadesmonda@google.com
 pbdr@google.com
 tkachenkoi@google.com
 mpodolian@google.com
diff --git a/location/Android.bp b/location/Android.bp
index 7f3442c..10ca97d 100644
--- a/location/Android.bp
+++ b/location/Android.bp
@@ -30,9 +30,6 @@
         "app-compat-annotations",
         "unsupportedappusage", // for android.compat.annotation.UnsupportedAppUsage
     ],
-    hidden_api_packages: [
-        "com.android.internal.location",
-    ],
     aidl: {
         include_dirs: [
             "frameworks/base/location/java",
diff --git a/location/java/com/android/internal/location/package-info.java b/location/java/com/android/internal/location/package-info.java
new file mode 100644
index 0000000..25573c1
--- /dev/null
+++ b/location/java/com/android/internal/location/package-info.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+
+/**
+ * Exclude from API surfaces
+ *
+ * @hide
+ */
+package com.android.internal.location;
diff --git a/nfc/Android.bp b/nfc/Android.bp
index 421f06d..2a01b3f 100644
--- a/nfc/Android.bp
+++ b/nfc/Android.bp
@@ -59,9 +59,6 @@
         "android.nfc",
         "com.android.nfc",
     ],
-    hidden_api_packages: [
-        "com.android.nfc",
-    ],
     impl_library_visibility: [
         "//frameworks/base:__subpackages__",
         "//cts/tests/tests/nfc",
diff --git a/services/core/java/com/android/server/CertBlacklister.java b/services/core/java/com/android/server/CertBlacklister.java
deleted file mode 100644
index e726c6a..0000000
--- a/services/core/java/com/android/server/CertBlacklister.java
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server;
-
-import android.content.Context;
-import android.content.ContentResolver;
-import android.database.ContentObserver;
-import android.os.Binder;
-import android.os.FileUtils;
-import android.provider.Settings;
-import android.util.Slog;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-
-import libcore.io.IoUtils;
-
-/**
- * <p>CertBlacklister provides a simple mechanism for updating the platform denylists for SSL
- * certificate public keys and serial numbers.
- */
-public class CertBlacklister extends Binder {
-
-    private static final String TAG = "CertBlacklister";
-
-    private static final String DENYLIST_ROOT = System.getenv("ANDROID_DATA") + "/misc/keychain/";
-
-    public static final String PUBKEY_PATH = DENYLIST_ROOT + "pubkey_blacklist.txt";
-    public static final String SERIAL_PATH = DENYLIST_ROOT + "serial_blacklist.txt";
-
-    public static final String PUBKEY_BLACKLIST_KEY = "pubkey_blacklist";
-    public static final String SERIAL_BLACKLIST_KEY = "serial_blacklist";
-
-    private static class BlacklistObserver extends ContentObserver {
-
-        private final String mKey;
-        private final String mName;
-        private final String mPath;
-        private final File mTmpDir;
-        private final ContentResolver mContentResolver;
-
-        public BlacklistObserver(String key, String name, String path, ContentResolver cr) {
-            super(null);
-            mKey = key;
-            mName = name;
-            mPath = path;
-            mTmpDir = new File(mPath).getParentFile();
-            mContentResolver = cr;
-        }
-
-        @Override
-        public void onChange(boolean selfChange) {
-            super.onChange(selfChange);
-            writeDenylist();
-        }
-
-        public String getValue() {
-            return Settings.Secure.getString(mContentResolver, mKey);
-        }
-
-        private void writeDenylist() {
-            new Thread("BlacklistUpdater") {
-                public void run() {
-                    synchronized(mTmpDir) {
-                        String blacklist = getValue();
-                        if (blacklist != null) {
-                            Slog.i(TAG, "Certificate blacklist changed, updating...");
-                            FileOutputStream out = null;
-                            try {
-                                // create a temporary file
-                                File tmp = File.createTempFile("journal", "", mTmpDir);
-                                // mark it -rw-r--r--
-                                tmp.setReadable(true, false);
-                                // write to it
-                                out = new FileOutputStream(tmp);
-                                out.write(blacklist.getBytes());
-                                // sync to disk
-                                FileUtils.sync(out);
-                                // atomic rename
-                                tmp.renameTo(new File(mPath));
-                                Slog.i(TAG, "Certificate blacklist updated");
-                            } catch (IOException e) {
-                                Slog.e(TAG, "Failed to write blacklist", e);
-                            } finally {
-                                IoUtils.closeQuietly(out);
-                            }
-                        }
-                    }
-                }
-            }.start();
-        }
-    }
-
-    public CertBlacklister(Context context) {
-        registerObservers(context.getContentResolver());
-    }
-
-    private BlacklistObserver buildPubkeyObserver(ContentResolver cr) {
-        return new BlacklistObserver(PUBKEY_BLACKLIST_KEY,
-                    "pubkey",
-                    PUBKEY_PATH,
-                    cr);
-    }
-
-    private BlacklistObserver buildSerialObserver(ContentResolver cr) {
-        return new BlacklistObserver(SERIAL_BLACKLIST_KEY,
-                    "serial",
-                    SERIAL_PATH,
-                    cr);
-    }
-
-    private void registerObservers(ContentResolver cr) {
-        // set up the public key denylist observer
-        cr.registerContentObserver(
-            Settings.Secure.getUriFor(PUBKEY_BLACKLIST_KEY),
-            true,
-            buildPubkeyObserver(cr)
-        );
-
-        // set up the serial number denylist observer
-        cr.registerContentObserver(
-            Settings.Secure.getUriFor(SERIAL_BLACKLIST_KEY),
-            true,
-            buildSerialObserver(cr)
-        );
-    }
-}
diff --git a/services/core/java/com/android/server/CertBlocklister.java b/services/core/java/com/android/server/CertBlocklister.java
new file mode 100644
index 0000000..9e23f88
--- /dev/null
+++ b/services/core/java/com/android/server/CertBlocklister.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.database.ContentObserver;
+import android.os.Binder;
+import android.os.FileUtils;
+import android.provider.Settings;
+import android.util.Slog;
+
+import libcore.io.IoUtils;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+/**
+ * <p>CertBlocklister provides a simple mechanism for updating the platform denylists for SSL
+ * certificate public keys and serial numbers.
+ */
+public class CertBlocklister extends Binder {
+
+    private static final String TAG = "CertBlocklister";
+
+    private static final String DENYLIST_ROOT = System.getenv("ANDROID_DATA") + "/misc/keychain/";
+
+    /* For compatibility reasons, the name of these paths cannot be changed */
+    public static final String PUBKEY_PATH = DENYLIST_ROOT + "pubkey_blacklist.txt";
+    public static final String SERIAL_PATH = DENYLIST_ROOT + "serial_blacklist.txt";
+
+    /* For compatibility reasons, the name of these keys cannot be changed */
+    public static final String PUBKEY_BLOCKLIST_KEY = "pubkey_blacklist";
+    public static final String SERIAL_BLOCKLIST_KEY = "serial_blacklist";
+
+    private static class BlocklistObserver extends ContentObserver {
+
+        private final String mKey;
+        private final String mName;
+        private final String mPath;
+        private final File mTmpDir;
+        private final ContentResolver mContentResolver;
+
+        BlocklistObserver(String key, String name, String path, ContentResolver cr) {
+            super(null);
+            mKey = key;
+            mName = name;
+            mPath = path;
+            mTmpDir = new File(mPath).getParentFile();
+            mContentResolver = cr;
+        }
+
+        @Override
+        public void onChange(boolean selfChange) {
+            super.onChange(selfChange);
+            new Thread("BlocklistUpdater") {
+                public void run() {
+                    writeDenylist();
+                }
+            }.start();
+        }
+
+        public String getValue() {
+            return Settings.Secure.getStringForUser(
+                mContentResolver, mKey, mContentResolver.getUserId());
+        }
+
+        private void writeDenylist() {
+            synchronized (mTmpDir) {
+                String blocklist = getValue();
+                if (blocklist == null) {
+                    return;
+                }
+                if (mPath.equals(SERIAL_PATH)) {
+                    Slog.w(TAG, "The certificate blocklist based on serials is deprecated. "
+                            + "Please use the pubkey blocklist instead.");
+                }
+                Slog.i(TAG, "Certificate blocklist changed, updating...");
+                FileOutputStream out = null;
+                try {
+                    // Create a temporary file and rename it atomically.
+                    File tmp = File.createTempFile("journal", "", mTmpDir);
+                    tmp.setReadable(true /* readable */, false /* ownerOnly */);
+                    out = new FileOutputStream(tmp);
+                    out.write(blocklist.getBytes());
+                    FileUtils.sync(out);
+                    tmp.renameTo(new File(mPath));
+                    Slog.i(TAG, "Certificate blocklist updated");
+                } catch (IOException e) {
+                    Slog.e(TAG, "Failed to write blocklist", e);
+                } finally {
+                    IoUtils.closeQuietly(out);
+                }
+            }
+        }
+    }
+
+    public CertBlocklister(Context context) {
+        registerObservers(context.getContentResolver());
+    }
+
+    private BlocklistObserver buildPubkeyObserver(ContentResolver cr) {
+        return new BlocklistObserver(PUBKEY_BLOCKLIST_KEY,
+                    "pubkey",
+                    PUBKEY_PATH,
+                    cr);
+    }
+
+    private BlocklistObserver buildSerialObserver(ContentResolver cr) {
+        return new BlocklistObserver(SERIAL_BLOCKLIST_KEY,
+                    "serial",
+                    SERIAL_PATH,
+                    cr);
+    }
+
+    private void registerObservers(ContentResolver cr) {
+        // set up the public key denylist observer
+        cr.registerContentObserver(
+                Settings.Secure.getUriFor(PUBKEY_BLOCKLIST_KEY),
+                true,
+                buildPubkeyObserver(cr)
+        );
+
+        // set up the serial number denylist observer
+        cr.registerContentObserver(
+                Settings.Secure.getUriFor(SERIAL_BLOCKLIST_KEY),
+                true,
+                buildSerialObserver(cr)
+        );
+    }
+}
diff --git a/services/core/java/com/android/server/OWNERS b/services/core/java/com/android/server/OWNERS
index 2545620..a627a39 100644
--- a/services/core/java/com/android/server/OWNERS
+++ b/services/core/java/com/android/server/OWNERS
@@ -48,3 +48,6 @@
 
 # SystemConfig
 per-file SystemConfig.java = file:/PACKAGE_MANAGER_OWNERS
+
+# CertBlocklister
+per-file Cert*.java = tweek@google.com, brambonne@google.com, prb@google.com, miguelaranda@google.com
diff --git a/services/core/java/com/android/server/RescueParty.java b/services/core/java/com/android/server/RescueParty.java
index dfd148d..c2cb5e9 100644
--- a/services/core/java/com/android/server/RescueParty.java
+++ b/services/core/java/com/android/server/RescueParty.java
@@ -241,12 +241,14 @@
      * opportunity to reset any settings depending on our rescue level.
      */
     public static void onSettingsProviderPublished(Context context) {
-        handleNativeRescuePartyResets();
-        ContentResolver contentResolver = context.getContentResolver();
-        DeviceConfig.setMonitorCallback(
-                contentResolver,
-                Executors.newSingleThreadExecutor(),
-                new RescuePartyMonitorCallback(context));
+        if (!Flags.deprecateFlagsAndSettingsResets()) {
+            handleNativeRescuePartyResets();
+            ContentResolver contentResolver = context.getContentResolver();
+            DeviceConfig.setMonitorCallback(
+                    contentResolver,
+                    Executors.newSingleThreadExecutor(),
+                    new RescuePartyMonitorCallback(context));
+        }
     }
 
 
@@ -256,75 +258,81 @@
      * on modules of newer versions.
      */
     public static void resetDeviceConfigForPackages(List<String> packageNames) {
-        if (packageNames == null) {
-            return;
-        }
-        Set<String> namespacesToReset = new ArraySet<String>();
-        Iterator<String> it = packageNames.iterator();
-        RescuePartyObserver rescuePartyObserver = RescuePartyObserver.getInstanceIfCreated();
-        // Get runtime package to namespace mapping if created.
-        if (rescuePartyObserver != null) {
-            while (it.hasNext()) {
-                String packageName = it.next();
-                Set<String> runtimeAffectedNamespaces =
-                        rescuePartyObserver.getAffectedNamespaceSet(packageName);
-                if (runtimeAffectedNamespaces != null) {
-                    namespacesToReset.addAll(runtimeAffectedNamespaces);
+        if (!Flags.deprecateFlagsAndSettingsResets()) {
+            if (packageNames == null) {
+                return;
+            }
+            Set<String> namespacesToReset = new ArraySet<String>();
+            Iterator<String> it = packageNames.iterator();
+            RescuePartyObserver rescuePartyObserver = RescuePartyObserver.getInstanceIfCreated();
+            // Get runtime package to namespace mapping if created.
+            if (rescuePartyObserver != null) {
+                while (it.hasNext()) {
+                    String packageName = it.next();
+                    Set<String> runtimeAffectedNamespaces =
+                            rescuePartyObserver.getAffectedNamespaceSet(packageName);
+                    if (runtimeAffectedNamespaces != null) {
+                        namespacesToReset.addAll(runtimeAffectedNamespaces);
+                    }
                 }
             }
-        }
-        // Get preset package to namespace mapping if created.
-        Set<String> presetAffectedNamespaces = getPresetNamespacesForPackages(
-                packageNames);
-        if (presetAffectedNamespaces != null) {
-            namespacesToReset.addAll(presetAffectedNamespaces);
-        }
+            // Get preset package to namespace mapping if created.
+            Set<String> presetAffectedNamespaces = getPresetNamespacesForPackages(
+                    packageNames);
+            if (presetAffectedNamespaces != null) {
+                namespacesToReset.addAll(presetAffectedNamespaces);
+            }
 
-        // Clear flags under the namespaces mapped to these packages.
-        // Using setProperties since DeviceConfig.resetToDefaults bans the current flag set.
-        Iterator<String> namespaceIt = namespacesToReset.iterator();
-        while (namespaceIt.hasNext()) {
-            String namespaceToReset = namespaceIt.next();
-            Properties properties = new Properties.Builder(namespaceToReset).build();
-            try {
-                if (!DeviceConfig.setProperties(properties)) {
-                    logCriticalInfo(Log.ERROR, "Failed to clear properties under "
+            // Clear flags under the namespaces mapped to these packages.
+            // Using setProperties since DeviceConfig.resetToDefaults bans the current flag set.
+            Iterator<String> namespaceIt = namespacesToReset.iterator();
+            while (namespaceIt.hasNext()) {
+                String namespaceToReset = namespaceIt.next();
+                Properties properties = new Properties.Builder(namespaceToReset).build();
+                try {
+                    if (!DeviceConfig.setProperties(properties)) {
+                        logCriticalInfo(Log.ERROR, "Failed to clear properties under "
                             + namespaceToReset
                             + ". Running `device_config get_sync_disabled_for_tests` will confirm"
                             + " if config-bulk-update is enabled.");
+                    }
+                } catch (DeviceConfig.BadConfigException exception) {
+                    logCriticalInfo(Log.WARN, "namespace " + namespaceToReset
+                            + " is already banned, skip reset.");
                 }
-            } catch (DeviceConfig.BadConfigException exception) {
-                logCriticalInfo(Log.WARN, "namespace " + namespaceToReset
-                        + " is already banned, skip reset.");
             }
         }
     }
 
     private static Set<String> getPresetNamespacesForPackages(List<String> packageNames) {
         Set<String> resultSet = new ArraySet<String>();
-        try {
-            String flagVal = DeviceConfig.getString(NAMESPACE_CONFIGURATION,
-                    NAMESPACE_TO_PACKAGE_MAPPING_FLAG, "");
-            String[] mappingEntries = flagVal.split(",");
-            for (int i = 0; i < mappingEntries.length; i++) {
-                if (TextUtils.isEmpty(mappingEntries[i])) {
-                    continue;
-                }
-                String[] splittedEntry = mappingEntries[i].split(":");
-                if (splittedEntry.length != 2) {
-                    throw new RuntimeException("Invalid mapping entry: " + mappingEntries[i]);
-                }
-                String namespace = splittedEntry[0];
-                String packageName = splittedEntry[1];
+        if (!Flags.deprecateFlagsAndSettingsResets()) {
+            try {
+                String flagVal = DeviceConfig.getString(NAMESPACE_CONFIGURATION,
+                        NAMESPACE_TO_PACKAGE_MAPPING_FLAG, "");
+                String[] mappingEntries = flagVal.split(",");
+                for (int i = 0; i < mappingEntries.length; i++) {
+                    if (TextUtils.isEmpty(mappingEntries[i])) {
+                        continue;
+                    }
+                    String[] splitEntry = mappingEntries[i].split(":");
+                    if (splitEntry.length != 2) {
+                        throw new RuntimeException("Invalid mapping entry: " + mappingEntries[i]);
+                    }
+                    String namespace = splitEntry[0];
+                    String packageName = splitEntry[1];
 
-                if (packageNames.contains(packageName)) {
-                    resultSet.add(namespace);
+                    if (packageNames.contains(packageName)) {
+                        resultSet.add(namespace);
+                    }
                 }
+            } catch (Exception e) {
+                resultSet.clear();
+                Slog.e(TAG, "Failed to read preset package to namespaces mapping.", e);
+            } finally {
+                return resultSet;
             }
-        } catch (Exception e) {
-            resultSet.clear();
-            Slog.e(TAG, "Failed to read preset package to namespaces mapping.", e);
-        } finally {
+        } else {
             return resultSet;
         }
     }
@@ -342,43 +350,54 @@
         }
 
         public void onNamespaceUpdate(@NonNull String updatedNamespace) {
-            startObservingPackages(mContext, updatedNamespace);
+            if (!Flags.deprecateFlagsAndSettingsResets()) {
+                startObservingPackages(mContext, updatedNamespace);
+            }
         }
 
         public void onDeviceConfigAccess(@NonNull String callingPackage,
                 @NonNull String namespace) {
-            RescuePartyObserver.getInstance(mContext).recordDeviceConfigAccess(
-                            callingPackage,
-                            namespace);
+
+            if (!Flags.deprecateFlagsAndSettingsResets()) {
+                RescuePartyObserver.getInstance(mContext).recordDeviceConfigAccess(
+                        callingPackage,
+                        namespace);
+            }
         }
     }
 
     private static void startObservingPackages(Context context, @NonNull String updatedNamespace) {
-        RescuePartyObserver rescuePartyObserver = RescuePartyObserver.getInstance(context);
-        Set<String> callingPackages = rescuePartyObserver.getCallingPackagesSet(updatedNamespace);
-        if (callingPackages == null) {
-            return;
+        if (!Flags.deprecateFlagsAndSettingsResets()) {
+            RescuePartyObserver rescuePartyObserver = RescuePartyObserver.getInstance(context);
+            Set<String> callingPackages = rescuePartyObserver.getCallingPackagesSet(
+                    updatedNamespace);
+            if (callingPackages == null) {
+                return;
+            }
+            List<String> callingPackageList = new ArrayList<>();
+            callingPackageList.addAll(callingPackages);
+            Slog.i(TAG, "Starting to observe: " + callingPackageList + ", updated namespace: "
+                    + updatedNamespace);
+            PackageWatchdog.getInstance(context).startObservingHealth(
+                    rescuePartyObserver,
+                    callingPackageList,
+                    DEFAULT_OBSERVING_DURATION_MS);
         }
-        List<String> callingPackageList = new ArrayList<>();
-        callingPackageList.addAll(callingPackages);
-        Slog.i(TAG, "Starting to observe: " + callingPackageList + ", updated namespace: "
-                + updatedNamespace);
-        PackageWatchdog.getInstance(context).startObservingHealth(
-                rescuePartyObserver,
-                callingPackageList,
-                DEFAULT_OBSERVING_DURATION_MS);
     }
 
     private static void handleNativeRescuePartyResets() {
-        if (SettingsToPropertiesMapper.isNativeFlagsResetPerformed()) {
-            String[] resetNativeCategories = SettingsToPropertiesMapper.getResetNativeCategories();
-            for (int i = 0; i < resetNativeCategories.length; i++) {
-                // Don't let RescueParty reset the namespace for RescueParty switches.
-                if (NAMESPACE_CONFIGURATION.equals(resetNativeCategories[i])) {
-                    continue;
+        if (!Flags.deprecateFlagsAndSettingsResets()) {
+            if (SettingsToPropertiesMapper.isNativeFlagsResetPerformed()) {
+                String[] resetNativeCategories =
+                        SettingsToPropertiesMapper.getResetNativeCategories();
+                for (int i = 0; i < resetNativeCategories.length; i++) {
+                    // Don't let RescueParty reset the namespace for RescueParty switches.
+                    if (NAMESPACE_CONFIGURATION.equals(resetNativeCategories[i])) {
+                        continue;
+                    }
+                    DeviceConfig.resetToDefaults(DEVICE_CONFIG_RESET_MODE,
+                            resetNativeCategories[i]);
                 }
-                DeviceConfig.resetToDefaults(DEVICE_CONFIG_RESET_MODE,
-                        resetNativeCategories[i]);
             }
         }
     }
@@ -400,6 +419,13 @@
         }
     }
 
+    private static int getMaxRescueLevel() {
+        if (!SystemProperties.getBoolean(PROP_DISABLE_FACTORY_RESET_FLAG, false)) {
+            return Level.factoryReset();
+        }
+        return Level.reboot();
+    }
+
     /**
      * Get the rescue level to perform if this is the n-th attempt at mitigating failure.
      *
@@ -409,19 +435,30 @@
      * @return the rescue level for the n-th mitigation attempt.
      */
     private static int getRescueLevel(int mitigationCount, boolean mayPerformReboot) {
-        if (mitigationCount == 1) {
-            return LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS;
-        } else if (mitigationCount == 2) {
-            return LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES;
-        } else if (mitigationCount == 3) {
-            return LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS;
-        } else if (mitigationCount == 4) {
-            return Math.min(getMaxRescueLevel(mayPerformReboot), LEVEL_WARM_REBOOT);
-        } else if (mitigationCount >= 5) {
-            return Math.min(getMaxRescueLevel(mayPerformReboot), LEVEL_FACTORY_RESET);
+        if (!Flags.deprecateFlagsAndSettingsResets()) {
+            if (mitigationCount == 1) {
+                return LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS;
+            } else if (mitigationCount == 2) {
+                return LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES;
+            } else if (mitigationCount == 3) {
+                return LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS;
+            } else if (mitigationCount == 4) {
+                return Math.min(getMaxRescueLevel(mayPerformReboot), LEVEL_WARM_REBOOT);
+            } else if (mitigationCount >= 5) {
+                return Math.min(getMaxRescueLevel(mayPerformReboot), LEVEL_FACTORY_RESET);
+            } else {
+                Slog.w(TAG, "Expected positive mitigation count, was " + mitigationCount);
+                return LEVEL_NONE;
+            }
         } else {
-            Slog.w(TAG, "Expected positive mitigation count, was " + mitigationCount);
-            return LEVEL_NONE;
+            if (mitigationCount == 1) {
+                return Level.reboot();
+            } else if (mitigationCount >= 2) {
+                return Math.min(getMaxRescueLevel(), Level.factoryReset());
+            } else {
+                Slog.w(TAG, "Expected positive mitigation count, was " + mitigationCount);
+                return LEVEL_NONE;
+            }
         }
     }
 
@@ -451,13 +488,13 @@
             return Math.min(getMaxRescueLevel(mayPerformReboot), RESCUE_LEVEL_WARM_REBOOT);
         } else if (mitigationCount == 4) {
             return Math.min(getMaxRescueLevel(mayPerformReboot),
-                                RESCUE_LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS);
+                    RESCUE_LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS);
         } else if (mitigationCount == 5) {
             return Math.min(getMaxRescueLevel(mayPerformReboot),
-                                RESCUE_LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES);
+                    RESCUE_LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES);
         } else if (mitigationCount == 6) {
             return Math.min(getMaxRescueLevel(mayPerformReboot),
-                                RESCUE_LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS);
+                    RESCUE_LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS);
         } else if (mitigationCount >= 7) {
             return Math.min(getMaxRescueLevel(mayPerformReboot), RESCUE_LEVEL_FACTORY_RESET);
         } else {
@@ -465,6 +502,22 @@
         }
     }
 
+    /**
+     * Get the rescue level to perform if this is the n-th attempt at mitigating failure.
+     *
+     * @param mitigationCount the mitigation attempt number (1 = first attempt etc.).
+     * @return the rescue level for the n-th mitigation attempt.
+     */
+    private static @RescueLevels int getRescueLevel(int mitigationCount) {
+        if (mitigationCount == 1) {
+            return Level.reboot();
+        } else if (mitigationCount >= 2) {
+            return Math.min(getMaxRescueLevel(), Level.factoryReset());
+        } else {
+            return Level.none();
+        }
+    }
+
     private static void executeRescueLevel(Context context, @Nullable String failedPackage,
             int level) {
         Slog.w(TAG, "Attempting rescue level " + levelToString(level));
@@ -537,13 +590,22 @@
                 executeWarmReboot(context, level, failedPackage);
                 break;
             case RESCUE_LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS:
-                resetAllSettingsIfNecessary(context, Settings.RESET_MODE_UNTRUSTED_DEFAULTS, level);
+                if (!Flags.deprecateFlagsAndSettingsResets()) {
+                    resetAllSettingsIfNecessary(context, Settings.RESET_MODE_UNTRUSTED_DEFAULTS,
+                            level);
+                }
                 break;
             case RESCUE_LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES:
-                resetAllSettingsIfNecessary(context, Settings.RESET_MODE_UNTRUSTED_CHANGES, level);
+                if (!Flags.deprecateFlagsAndSettingsResets()) {
+                    resetAllSettingsIfNecessary(context, Settings.RESET_MODE_UNTRUSTED_CHANGES,
+                            level);
+                }
                 break;
             case RESCUE_LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS:
-                resetAllSettingsIfNecessary(context, Settings.RESET_MODE_TRUSTED_DEFAULTS, level);
+                if (!Flags.deprecateFlagsAndSettingsResets()) {
+                    resetAllSettingsIfNecessary(context, Settings.RESET_MODE_TRUSTED_DEFAULTS,
+                            level);
+                }
                 break;
             case RESCUE_LEVEL_FACTORY_RESET:
                 // Before the completion of Reboot, if any crash happens then PackageWatchdog
@@ -560,6 +622,12 @@
 
     private static void executeWarmReboot(Context context, int level,
             @Nullable String failedPackage) {
+        if (Flags.deprecateFlagsAndSettingsResets()) {
+            if (shouldThrottleReboot()) {
+                return;
+            }
+        }
+
         // Request the reboot from a separate thread to avoid deadlock on PackageWatchdog
         // when device shutting down.
         setRebootProperty(true);
@@ -579,6 +647,11 @@
 
     private static void executeFactoryReset(Context context, int level,
             @Nullable String failedPackage) {
+        if (Flags.deprecateFlagsAndSettingsResets()) {
+            if (shouldThrottleReboot()) {
+                return;
+            }
+        }
         setFactoryResetProperty(true);
         long now = System.currentTimeMillis();
         setLastFactoryResetTimeMs(now);
@@ -655,30 +728,32 @@
 
     private static void resetAllSettingsIfNecessary(Context context, int mode,
             int level) throws Exception {
-        // No need to reset Settings again if they are already reset in the current level once.
-        if (getMaxRescueLevelAttempted() >= level) {
-            return;
-        }
-        setMaxRescueLevelAttempted(level);
-        // Try our best to reset all settings possible, and once finished
-        // rethrow any exception that we encountered
-        Exception res = null;
-        final ContentResolver resolver = context.getContentResolver();
-        try {
-            Settings.Global.resetToDefaultsAsUser(resolver, null, mode,
-                    UserHandle.SYSTEM.getIdentifier());
-        } catch (Exception e) {
-            res = new RuntimeException("Failed to reset global settings", e);
-        }
-        for (int userId : getAllUserIds()) {
-            try {
-                Settings.Secure.resetToDefaultsAsUser(resolver, null, mode, userId);
-            } catch (Exception e) {
-                res = new RuntimeException("Failed to reset secure settings for " + userId, e);
+        if (!Flags.deprecateFlagsAndSettingsResets()) {
+            // No need to reset Settings again if they are already reset in the current level once.
+            if (getMaxRescueLevelAttempted() >= level) {
+                return;
             }
-        }
-        if (res != null) {
-            throw res;
+            setMaxRescueLevelAttempted(level);
+            // Try our best to reset all settings possible, and once finished
+            // rethrow any exception that we encountered
+            Exception res = null;
+            final ContentResolver resolver = context.getContentResolver();
+            try {
+                Settings.Global.resetToDefaultsAsUser(resolver, null, mode,
+                        UserHandle.SYSTEM.getIdentifier());
+            } catch (Exception e) {
+                res = new RuntimeException("Failed to reset global settings", e);
+            }
+            for (int userId : getAllUserIds()) {
+                try {
+                    Settings.Secure.resetToDefaultsAsUser(resolver, null, mode, userId);
+                } catch (Exception e) {
+                    res = new RuntimeException("Failed to reset secure settings for " + userId, e);
+                }
+            }
+            if (res != null) {
+                throw res;
+            }
         }
     }
 
@@ -728,18 +803,28 @@
         @Override
         public int onHealthCheckFailed(@Nullable VersionedPackage failedPackage,
                 @FailureReasons int failureReason, int mitigationCount) {
+            int impact = PackageHealthObserverImpact.USER_IMPACT_LEVEL_0;
             if (!isDisabled() && (failureReason == PackageWatchdog.FAILURE_REASON_APP_CRASH
                     || failureReason == PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING)) {
                 if (Flags.recoverabilityDetection()) {
-                    return mapRescueLevelToUserImpact(getRescueLevel(mitigationCount,
-                            mayPerformReboot(failedPackage), failedPackage));
+                    if (!Flags.deprecateFlagsAndSettingsResets()) {
+                        impact =  mapRescueLevelToUserImpact(getRescueLevel(mitigationCount,
+                                mayPerformReboot(failedPackage), failedPackage));
+                    } else {
+                        impact =  mapRescueLevelToUserImpact(getRescueLevel(mitigationCount));
+                    }
                 } else {
-                    return mapRescueLevelToUserImpact(getRescueLevel(mitigationCount,
-                        mayPerformReboot(failedPackage)));
+                    impact =  mapRescueLevelToUserImpact(getRescueLevel(mitigationCount,
+                            mayPerformReboot(failedPackage)));
                 }
-            } else {
-                return PackageHealthObserverImpact.USER_IMPACT_LEVEL_0;
             }
+
+            Slog.i(TAG, "Checking available remediations for health check failure."
+                    + " failedPackage: "
+                    + (failedPackage == null ? null : failedPackage.getPackageName())
+                    + " failureReason: " + failureReason
+                    + " available impact: " + impact);
+            return impact;
         }
 
         @Override
@@ -748,12 +833,24 @@
             if (isDisabled()) {
                 return false;
             }
+            Slog.i(TAG, "Executing remediation."
+                    + " failedPackage: "
+                    + (failedPackage == null ? null : failedPackage.getPackageName())
+                    + " failureReason: " + failureReason
+                    + " mitigationCount: " + mitigationCount);
             if (failureReason == PackageWatchdog.FAILURE_REASON_APP_CRASH
                     || failureReason == PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING) {
-                final int level = Flags.recoverabilityDetection() ? getRescueLevel(mitigationCount,
-                        mayPerformReboot(failedPackage), failedPackage)
-                        : getRescueLevel(mitigationCount,
-                                mayPerformReboot(failedPackage));
+                final int level;
+                if (Flags.recoverabilityDetection()) {
+                    if (!Flags.deprecateFlagsAndSettingsResets()) {
+                        level = getRescueLevel(mitigationCount, mayPerformReboot(failedPackage),
+                                failedPackage);
+                    } else {
+                        level = getRescueLevel(mitigationCount);
+                    }
+                } else {
+                    level = getRescueLevel(mitigationCount, mayPerformReboot(failedPackage));
+                }
                 executeRescueLevel(mContext,
                         failedPackage == null ? null : failedPackage.getPackageName(), level);
                 return true;
@@ -787,8 +884,12 @@
                 return PackageHealthObserverImpact.USER_IMPACT_LEVEL_0;
             }
             if (Flags.recoverabilityDetection()) {
-                return mapRescueLevelToUserImpact(getRescueLevel(mitigationCount,
-                        true, /*failedPackage=*/ null));
+                if (!Flags.deprecateFlagsAndSettingsResets()) {
+                    return mapRescueLevelToUserImpact(getRescueLevel(mitigationCount,
+                            true, /*failedPackage=*/ null));
+                } else {
+                    return mapRescueLevelToUserImpact(getRescueLevel(mitigationCount));
+                }
             } else {
                 return mapRescueLevelToUserImpact(getRescueLevel(mitigationCount, true));
             }
@@ -800,9 +901,17 @@
                 return false;
             }
             boolean mayPerformReboot = !shouldThrottleReboot();
-            final int level = Flags.recoverabilityDetection() ? getRescueLevel(mitigationCount,
-                        mayPerformReboot, /*failedPackage=*/ null)
-                        : getRescueLevel(mitigationCount, mayPerformReboot);
+            final int level;
+            if (Flags.recoverabilityDetection()) {
+                if (!Flags.deprecateFlagsAndSettingsResets()) {
+                    level = getRescueLevel(mitigationCount, mayPerformReboot,
+                            /*failedPackage=*/ null);
+                } else {
+                    level = getRescueLevel(mitigationCount);
+                }
+            } else {
+                level = getRescueLevel(mitigationCount, mayPerformReboot);
+            }
             executeRescueLevel(mContext, /*failedPackage=*/ null, level);
             return true;
         }
@@ -828,18 +937,6 @@
             return isPersistentSystemApp(failingPackage.getPackageName());
         }
 
-        /**
-         * Returns {@code true} if Rescue Party is allowed to attempt a reboot or factory reset.
-         * Will return {@code false} if a factory reset was already offered recently.
-         */
-        private boolean shouldThrottleReboot() {
-            Long lastResetTime = getLastFactoryResetTimeMs();
-            long now = System.currentTimeMillis();
-            long throttleDurationMin = SystemProperties.getLong(PROP_THROTTLE_DURATION_MIN_FLAG,
-                    DEFAULT_FACTORY_RESET_THROTTLE_DURATION_MIN);
-            return now < lastResetTime + TimeUnit.MINUTES.toMillis(throttleDurationMin);
-        }
-
         private boolean isPersistentSystemApp(@NonNull String packageName) {
             PackageManager pm = mContext.getPackageManager();
             try {
@@ -852,20 +949,22 @@
 
         private synchronized void recordDeviceConfigAccess(@NonNull String callingPackage,
                 @NonNull String namespace) {
-            // Record it in calling packages to namespace map
-            Set<String> namespaceSet = mCallingPackageNamespaceSetMap.get(callingPackage);
-            if (namespaceSet == null) {
-                namespaceSet = new ArraySet<>();
-                mCallingPackageNamespaceSetMap.put(callingPackage, namespaceSet);
+            if (!Flags.deprecateFlagsAndSettingsResets()) {
+                // Record it in calling packages to namespace map
+                Set<String> namespaceSet = mCallingPackageNamespaceSetMap.get(callingPackage);
+                if (namespaceSet == null) {
+                    namespaceSet = new ArraySet<>();
+                    mCallingPackageNamespaceSetMap.put(callingPackage, namespaceSet);
+                }
+                namespaceSet.add(namespace);
+                // Record it in namespace to calling packages map
+                Set<String> callingPackageSet = mNamespaceCallingPackageSetMap.get(namespace);
+                if (callingPackageSet == null) {
+                    callingPackageSet = new ArraySet<>();
+                }
+                callingPackageSet.add(callingPackage);
+                mNamespaceCallingPackageSetMap.put(namespace, callingPackageSet);
             }
-            namespaceSet.add(namespace);
-            // Record it in namespace to calling packages map
-            Set<String> callingPackageSet = mNamespaceCallingPackageSetMap.get(namespace);
-            if (callingPackageSet == null) {
-                callingPackageSet = new ArraySet<>();
-            }
-            callingPackageSet.add(callingPackage);
-            mNamespaceCallingPackageSetMap.put(namespace, callingPackageSet);
         }
 
         private synchronized Set<String> getAffectedNamespaceSet(String failedPackage) {
@@ -881,6 +980,18 @@
         }
     }
 
+    /**
+     * Returns {@code true} if Rescue Party is allowed to attempt a reboot or factory reset.
+     * Will return {@code false} if a factory reset was already offered recently.
+     */
+    private static boolean shouldThrottleReboot() {
+        Long lastResetTime = getLastFactoryResetTimeMs();
+        long now = System.currentTimeMillis();
+        long throttleDurationMin = SystemProperties.getLong(PROP_THROTTLE_DURATION_MIN_FLAG,
+                DEFAULT_FACTORY_RESET_THROTTLE_DURATION_MIN);
+        return now < lastResetTime + TimeUnit.MINUTES.toMillis(throttleDurationMin);
+    }
+
     private static int[] getAllUserIds() {
         int systemUserId = UserHandle.SYSTEM.getIdentifier();
         int[] userIds = { systemUserId };
@@ -919,6 +1030,22 @@
         }
     }
 
+    private static class Level {
+        static int none() {
+            return Flags.recoverabilityDetection() ? RESCUE_LEVEL_NONE : LEVEL_NONE;
+        }
+
+        static int reboot() {
+            return Flags.recoverabilityDetection() ? RESCUE_LEVEL_WARM_REBOOT : LEVEL_WARM_REBOOT;
+        }
+
+        static int factoryReset() {
+            return Flags.recoverabilityDetection()
+                    ? RESCUE_LEVEL_FACTORY_RESET
+                    : LEVEL_FACTORY_RESET;
+        }
+    }
+
     private static String levelToString(int level) {
         if (Flags.recoverabilityDetection()) {
             switch (level) {
diff --git a/services/core/java/com/android/server/am/LmkdConnection.java b/services/core/java/com/android/server/am/LmkdConnection.java
index 598f086..4faadcb 100644
--- a/services/core/java/com/android/server/am/LmkdConnection.java
+++ b/services/core/java/com/android/server/am/LmkdConnection.java
@@ -91,10 +91,18 @@
     @GuardedBy("mLmkdSocketLock")
     private LocalSocket mLmkdSocket = null;
 
-    // socket I/O streams
-    @GuardedBy("mLmkdSocketLock")
+    // mutex to synchronize socket output stream with socket creation/destruction
+    private final Object mLmkdOutputStreamLock = new Object();
+
+    // socket output stream
+    @GuardedBy("mLmkdOutputStreamLock")
     private OutputStream mLmkdOutputStream = null;
-    @GuardedBy("mLmkdSocketLock")
+
+    // mutex to synchronize socket input stream with socket creation/destruction
+    private final Object mLmkdInputStreamLock = new Object();
+
+    // socket input stream
+    @GuardedBy("mLmkdInputStreamLock")
     private InputStream mLmkdInputStream = null;
 
     // buffer to store incoming data
@@ -148,9 +156,13 @@
                 return false;
             }
             // connection established
-            mLmkdSocket = socket;
-            mLmkdOutputStream = ostream;
-            mLmkdInputStream = istream;
+            synchronized(mLmkdOutputStreamLock) {
+                synchronized(mLmkdInputStreamLock) {
+                    mLmkdSocket = socket;
+                    mLmkdOutputStream = ostream;
+                    mLmkdInputStream = istream;
+                }
+            }
             mMsgQueue.addOnFileDescriptorEventListener(mLmkdSocket.getFileDescriptor(),
                 EVENT_INPUT | EVENT_ERROR,
                 new MessageQueue.OnFileDescriptorEventListener() {
@@ -177,7 +189,13 @@
                 mMsgQueue.removeOnFileDescriptorEventListener(
                         mLmkdSocket.getFileDescriptor());
                 IoUtils.closeQuietly(mLmkdSocket);
-                mLmkdSocket = null;
+                synchronized(mLmkdOutputStreamLock) {
+                    synchronized(mLmkdInputStreamLock) {
+                        mLmkdOutputStream = null;
+                        mLmkdInputStream = null;
+                        mLmkdSocket = null;
+                    }
+                }
             }
             // wake up reply waiters if any
             synchronized (mReplyBufLock) {
@@ -262,24 +280,33 @@
     }
 
     private boolean write(ByteBuffer buf) {
-        synchronized (mLmkdSocketLock) {
-            try {
-                mLmkdOutputStream.write(buf.array(), 0, buf.position());
-            } catch (IOException ex) {
-                return false;
+        boolean result = false;
+
+        synchronized(mLmkdOutputStreamLock) {
+            if (mLmkdOutputStream != null) {
+                try {
+                    mLmkdOutputStream.write(buf.array(), 0, buf.position());
+                    result = true;
+                } catch (IOException ex) {
+                }
             }
-            return true;
         }
+
+        return result;
     }
 
     private int read(ByteBuffer buf) {
-        synchronized (mLmkdSocketLock) {
-            try {
-                return mLmkdInputStream.read(buf.array(), 0, buf.array().length);
-            } catch (IOException ex) {
+        int result = -1;
+
+        synchronized(mLmkdInputStreamLock) {
+            if (mLmkdInputStream != null) {
+                try {
+                    result = mLmkdInputStream.read(buf.array(), 0, buf.array().length);
+                } catch (IOException ex) {
+                }
             }
-            return -1;
         }
+        return result;
     }
 
     /**
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 64e3e8e..97678aa 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -5491,8 +5491,9 @@
     void noteAppKill(final ProcessRecord app, final @Reason int reason,
             final @SubReason int subReason, final String msg) {
         if (DEBUG_PROCESSES) {
-            Slog.i(TAG, "note: " + app + " is being killed, reason: " + reason
-                    + ", sub-reason: " + subReason + ", message: " + msg);
+            Slog.i(TAG, "note: " + app + " is being killed, reason: "
+                    + ApplicationExitInfo.reasonCodeToString(reason) + ", sub-reason: "
+                    + ApplicationExitInfo.subreasonToString(subReason) + ", message: " + msg);
         }
         if (app.getPid() > 0 && !app.isolated && app.getDeathRecipient() != null) {
             // We are killing it, put it into the dying process list.
diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java
index 0f3f807..73ca6fb 100644
--- a/services/core/java/com/android/server/audio/BtHelper.java
+++ b/services/core/java/com/android/server/audio/BtHelper.java
@@ -436,8 +436,13 @@
         if (mBluetoothHeadset == null || mBluetoothHeadsetDevice == null) {
             return false;
         }
-        return mBluetoothHeadset.getAudioState(mBluetoothHeadsetDevice)
-                == BluetoothHeadset.STATE_AUDIO_CONNECTED;
+        try {
+            return mBluetoothHeadset.getAudioState(mBluetoothHeadsetDevice)
+                    == BluetoothHeadset.STATE_AUDIO_CONNECTED;
+        } catch (Exception e) {
+            Log.e(TAG, "Exception while getting audio state of " + mBluetoothHeadsetDevice, e);
+        }
+        return false;
     }
 
     // @GuardedBy("mDeviceBroker.mSetModeLock")
@@ -1051,12 +1056,16 @@
     }
 
     private void checkScoAudioState() {
-        if (mBluetoothHeadset != null
-                && mBluetoothHeadsetDevice != null
-                && mScoAudioState == SCO_STATE_INACTIVE
-                && mBluetoothHeadset.getAudioState(mBluetoothHeadsetDevice)
-                != BluetoothHeadset.STATE_AUDIO_DISCONNECTED) {
-            mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
+        try {
+            if (mBluetoothHeadset != null
+                    && mBluetoothHeadsetDevice != null
+                    && mScoAudioState == SCO_STATE_INACTIVE
+                    && mBluetoothHeadset.getAudioState(mBluetoothHeadsetDevice)
+                    != BluetoothHeadset.STATE_AUDIO_DISCONNECTED) {
+                mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
+            }
+        } catch (Exception e) {
+            Log.e(TAG, "Exception while getting audio state of " + mBluetoothHeadsetDevice, e);
         }
     }
 
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 1564b2f..0f7904e 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -2949,6 +2949,7 @@
         hideStatusBarIconLocked();
         mInFullscreenMode = false;
         mWindowManagerInternal.setDismissImeOnBackKeyPressed(false);
+        scheduleResetStylusHandwriting();
     }
 
     @BinderThread
diff --git a/services/core/java/com/android/server/location/altitude/AltitudeService.java b/services/core/java/com/android/server/location/altitude/AltitudeService.java
index 289d4a2..96540c2 100644
--- a/services/core/java/com/android/server/location/altitude/AltitudeService.java
+++ b/services/core/java/com/android/server/location/altitude/AltitudeService.java
@@ -25,6 +25,7 @@
 import android.location.Location;
 import android.location.altitude.AltitudeConverter;
 import android.os.RemoteException;
+import android.util.Log;
 
 import com.android.server.SystemService;
 
@@ -38,6 +39,8 @@
  */
 public class AltitudeService extends IAltitudeService.Stub {
 
+    private static final String TAG = "AltitudeService";
+
     private final AltitudeConverter mAltitudeConverter = new AltitudeConverter();
     private final Context mContext;
 
@@ -59,6 +62,7 @@
         try {
             mAltitudeConverter.addMslAltitudeToLocation(mContext, location);
         } catch (IOException e) {
+            Log.e(TAG, "", e);
             response.success = false;
             return response;
         }
@@ -74,6 +78,7 @@
         try {
             return mAltitudeConverter.getGeoidHeight(mContext, request);
         } catch (IOException e) {
+            Log.e(TAG, "", e);
             GetGeoidHeightResponse response = new GetGeoidHeightResponse();
             response.success = false;
             return response;
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 7157646..7aae91b 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -1773,6 +1773,20 @@
         }
     }
 
+    @Override
+    public boolean writeRepairModeCredential(int userId) {
+        checkWritePermission();
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            synchronized (mSpManager) {
+                long protectorId = getCurrentLskfBasedProtectorId(userId);
+                return mSpManager.writeRepairModeCredentialLocked(protectorId, userId);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
     /**
      * @param savedCredential if the user is a profile with
      * {@link UserManager#isCredentialSharableWithParent()} with unified challenge and
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index 89c4f0f..9199004 100644
--- a/services/core/java/com/android/server/pm/InstallPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -4550,7 +4550,7 @@
                             PackageManagerException.INTERNAL_ERROR_SYSTEM_OVERLAY_STATIC);
                 }
             } else {
-                if ((scanFlags & SCAN_AS_VENDOR) != 0) {
+                if ((scanFlags & (SCAN_AS_VENDOR | SCAN_AS_ODM)) != 0) {
                     if (pkg.getTargetSdkVersion() < ScanPackageUtils.getVendorPartitionVersion()) {
                         Slog.w(TAG, "System overlay " + pkg.getPackageName()
                                 + " targets an SDK below the required SDK level of vendor"
diff --git a/services/core/java/com/android/server/rollback/Rollback.java b/services/core/java/com/android/server/rollback/Rollback.java
index d1f91c8..c4e3fa4 100644
--- a/services/core/java/com/android/server/rollback/Rollback.java
+++ b/services/core/java/com/android/server/rollback/Rollback.java
@@ -16,6 +16,8 @@
 
 package com.android.server.rollback;
 
+import static android.crashrecovery.flags.Flags.deprecateFlagsAndSettingsResets;
+
 import static com.android.server.rollback.RollbackManagerServiceImpl.sendFailure;
 
 import android.Manifest;
@@ -622,8 +624,10 @@
                 parentSession.addChildSessionId(sessionId);
             }
 
-            // Clear flags.
-            RescueParty.resetDeviceConfigForPackages(packageNames);
+            if (!deprecateFlagsAndSettingsResets()) {
+                // Clear flags.
+                RescueParty.resetDeviceConfigForPackages(packageNames);
+            }
 
             Consumer<Intent> onResult = result -> {
                 mHandler.post(() -> {
diff --git a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
index c85ceac..4f28e02 100644
--- a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
+++ b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
@@ -154,12 +154,22 @@
             }
         }
 
+        Slog.i(TAG, "Checking available remediations for health check failure."
+                + " failedPackage: "
+                + (failedPackage == null ? null : failedPackage.getPackageName())
+                + " failureReason: " + failureReason
+                + " available impact: " + impact);
         return impact;
     }
 
     @Override
     public boolean execute(@Nullable VersionedPackage failedPackage,
             @FailureReasons int rollbackReason, int mitigationCount) {
+        Slog.i(TAG, "Executing remediation."
+                + " failedPackage: "
+                + (failedPackage == null ? null : failedPackage.getPackageName())
+                + " rollbackReason: " + rollbackReason
+                + " mitigationCount: " + mitigationCount);
         if (Flags.recoverabilityDetection()) {
             List<RollbackInfo> availableRollbacks = getAvailableRollbacks();
             if (rollbackReason == PackageWatchdog.FAILURE_REASON_NATIVE_CRASH) {
@@ -503,6 +513,10 @@
             @FailureReasons int rollbackReason) {
         assertInWorkerThread();
 
+        Slog.i(TAG, "Rolling back package. RollbackId: " + rollback.getRollbackId()
+                + " failedPackage: "
+                + (failedPackage == null ? null : failedPackage.getPackageName())
+                + " rollbackReason: " + rollbackReason);
         final RollbackManager rollbackManager = mContext.getSystemService(RollbackManager.class);
         int reasonToLog = WatchdogRollbackLogger.mapFailureReasonToMetric(rollbackReason);
         final String failedPackageToLog;
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index e19f08c..37f49e3 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -2461,11 +2461,11 @@
                 t.traceEnd();
             }
 
-            t.traceBegin("CertBlacklister");
+            t.traceBegin("CertBlocklister");
             try {
-                CertBlacklister blacklister = new CertBlacklister(context);
+                CertBlocklister blocklister = new CertBlocklister(context);
             } catch (Throwable e) {
-                reportWtf("starting CertBlacklister", e);
+                reportWtf("starting CertBlocklister", e);
             }
             t.traceEnd();
 
diff --git a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
index 977a8a0..3ed6ad7 100644
--- a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
+++ b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
@@ -287,7 +287,7 @@
         if (randomNum < traceFrequency) {
             BackgroundThread.get().getThreadHandler().post(() -> {
                 try {
-                    mIProfcollect.trace_once("applaunch");
+                    mIProfcollect.trace_system("applaunch");
                 } catch (RemoteException e) {
                     Log.e(LOG_TAG, "Failed to initiate trace: " + e.getMessage());
                 }
@@ -327,7 +327,7 @@
             // Dex2oat could take a while before it starts. Add a short delay before start tracing.
             BackgroundThread.get().getThreadHandler().postDelayed(() -> {
                 try {
-                    mIProfcollect.trace_once("dex2oat");
+                    mIProfcollect.trace_system("dex2oat");
                 } catch (RemoteException e) {
                     Log.e(LOG_TAG, "Failed to initiate trace: " + e.getMessage());
                 }
@@ -398,14 +398,17 @@
                 if (randomNum >= traceFrequency) {
                     return;
                 }
-                // Wait for 1s before starting tracing.
+                // For a small percentage a traces, we collect the initialization behavior.
+                boolean traceInitialization = ThreadLocalRandom.current().nextInt(10) < 1;
+                int traceDelay = traceInitialization ? 0 : 1000;
+                String traceTag = traceInitialization ? "camera_init" : "camera";
                 BackgroundThread.get().getThreadHandler().postDelayed(() -> {
                     try {
-                        mIProfcollect.trace_once("camera");
+                        mIProfcollect.trace_process(traceTag, "android.hardware.camera.provider");
                     } catch (RemoteException e) {
                         Log.e(LOG_TAG, "Failed to initiate trace: " + e.getMessage());
                     }
-                }, 1000);
+                }, traceDelay);
             }
         }, null);
     }
diff --git a/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java b/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java
index 3377899..f2acbc3 100644
--- a/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java
@@ -27,7 +27,6 @@
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
 import static com.android.server.RescueParty.DEFAULT_FACTORY_RESET_THROTTLE_DURATION_MIN;
 import static com.android.server.RescueParty.LEVEL_FACTORY_RESET;
-import static com.android.server.RescueParty.RESCUE_LEVEL_FACTORY_RESET;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -36,7 +35,6 @@
 import static org.mockito.ArgumentMatchers.isNull;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.times;
 
 import android.content.ContentResolver;
 import android.content.Context;
@@ -47,6 +45,9 @@
 import android.os.RecoverySystem;
 import android.os.SystemProperties;
 import android.os.UserHandle;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
+import android.platform.test.flag.junit.FlagsParameterization;
 import android.platform.test.flag.junit.SetFlagsRule;
 import android.provider.DeviceConfig;
 import android.provider.Settings;
@@ -61,6 +62,9 @@
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
 import org.mockito.Answers;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Captor;
@@ -77,10 +81,14 @@
 import java.util.concurrent.Executor;
 import java.util.concurrent.TimeUnit;
 
+
 /**
  * Test RescueParty.
  */
+@RunWith(Parameterized.class)
 public class RescuePartyTest {
+    @Rule
+    public SetFlagsRule mSetFlagsRule;
     private static final long CURRENT_NETWORK_TIME_MILLIS = 0L;
     private static final String FAKE_NATIVE_NAMESPACE1 = "native1";
     private static final String FAKE_NATIVE_NAMESPACE2 = "native2";
@@ -103,9 +111,6 @@
     private static final String PROP_DISABLE_FACTORY_RESET_FLAG =
             "persist.device_config.configuration.disable_rescue_party_factory_reset";
 
-    @Rule
-    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
-
     private MockitoSession mSession;
     private HashMap<String, String> mSystemSettingsMap;
     private HashMap<String, String> mCrashRecoveryPropertiesMap;
@@ -129,6 +134,17 @@
     @Captor
     private ArgumentCaptor<List<String>> mPackageListCaptor;
 
+    @Parameters(name = "{0}")
+    public static List<FlagsParameterization> getFlags() {
+        return FlagsParameterization.allCombinationsOf(
+                Flags.FLAG_RECOVERABILITY_DETECTION,
+                Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS);
+    }
+
+    public RescuePartyTest(FlagsParameterization flags) {
+        mSetFlagsRule = new SetFlagsRule(flags);
+    }
+
     @Before
     public void setUp() throws Exception {
         mSession =
@@ -234,10 +250,10 @@
     }
 
     @Test
-    public void testBootLoopDetectionWithExecutionForAllRescueLevels() {
+    @DisableFlags({Flags.FLAG_RECOVERABILITY_DETECTION,
+            Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS})
+    public void testBootLoop() {
         // this is old test where the flag needs to be disabled
-        mSetFlagsRule.disableFlags(Flags.FLAG_RECOVERABILITY_DETECTION);
-
         RescueParty.onSettingsProviderPublished(mMockContext);
         verify(() -> DeviceConfig.setMonitorCallback(eq(mMockContentResolver),
                 any(Executor.class),
@@ -264,10 +280,22 @@
         noteBoot(5);
         assertTrue(RescueParty.isFactoryResetPropertySet());
     }
+    @Test
+    @EnableFlags(Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS)
+    public void testBootLoopNoFlags() {
+        // this is old test where the flag needs to be disabled
+        noteBoot(1);
+        assertTrue(RescueParty.isRebootPropertySet());
+
+        setCrashRecoveryPropAttemptingReboot(false);
+        noteBoot(2);
+        assertTrue(RescueParty.isFactoryResetPropertySet());
+    }
 
     @Test
-    public void testBootLoopDetectionWithExecutionForAllRescueLevelsRecoverabilityDetection() {
-        mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION);
+    @EnableFlags(Flags.FLAG_RECOVERABILITY_DETECTION)
+    @DisableFlags(Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS)
+    public void testBootLoopRecoverability() {
         RescueParty.onSettingsProviderPublished(mMockContext);
         verify(() -> DeviceConfig.setMonitorCallback(eq(mMockContentResolver),
                 any(Executor.class),
@@ -281,12 +309,14 @@
 
         final String[] expectedAllResetNamespaces = new String[]{NAMESPACE1, NAMESPACE2};
 
+
         noteBoot(1);
 
         noteBoot(2);
         assertTrue(RescueParty.isRebootPropertySet());
 
         noteBoot(3);
+
         verifyOnlySettingsReset(Settings.RESET_MODE_UNTRUSTED_DEFAULTS);
 
         noteBoot(4);
@@ -301,10 +331,10 @@
     }
 
     @Test
-    public void testPersistentAppCrashDetectionWithExecutionForAllRescueLevels() {
+    @DisableFlags({Flags.FLAG_RECOVERABILITY_DETECTION,
+            Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS})
+    public void testPersistentAppCrash() {
         // this is old test where the flag needs to be disabled
-        mSetFlagsRule.disableFlags(Flags.FLAG_RECOVERABILITY_DETECTION);
-
         noteAppCrash(1, true);
         noteAppCrash(2, true);
         noteAppCrash(3, true);
@@ -318,8 +348,21 @@
     }
 
     @Test
-    public void testPersistentAppCrashDetectionWithExecutionForAllRescueLevelsRecoverability() {
-        mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION);
+    @EnableFlags(Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS)
+    public void testPersistentAppCrashNoFlags() {
+        // this is old test where the flag needs to be disabled
+        noteAppCrash(1, true);
+        assertTrue(RescueParty.isRebootPropertySet());
+
+        setCrashRecoveryPropAttemptingReboot(false);
+        noteAppCrash(2, true);
+        assertTrue(RescueParty.isFactoryResetPropertySet());
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_RECOVERABILITY_DETECTION)
+    @DisableFlags(Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS)
+    public void testPersistentAppCrashRecoverability() {
         RescueParty.onSettingsProviderPublished(mMockContext);
         verify(() -> DeviceConfig.setMonitorCallback(eq(mMockContentResolver),
                 any(Executor.class),
@@ -357,10 +400,10 @@
     }
 
     @Test
-    public void testNonPersistentAppDoesntDoAnything() {
+    @DisableFlags({Flags.FLAG_RECOVERABILITY_DETECTION,
+            Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS})
+    public void testNonPersistentApp() {
         // this is old test where the flag needs to be disabled
-        mSetFlagsRule.disableFlags(Flags.FLAG_RECOVERABILITY_DETECTION);
-
         noteAppCrash(1, false);
         noteAppCrash(2, false);
         noteAppCrash(3, false);
@@ -371,8 +414,9 @@
     }
 
     @Test
+    @EnableFlags(Flags.FLAG_RECOVERABILITY_DETECTION)
+    @DisableFlags(Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS)
     public void testNonPersistentAppOnlyPerformsFlagResetsRecoverabilityDetection() {
-        mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION);
         RescueParty.onSettingsProviderPublished(mMockContext);
         verify(() -> DeviceConfig.setMonitorCallback(eq(mMockContentResolver),
                 any(Executor.class),
@@ -408,60 +452,6 @@
     }
 
     @Test
-    public void testNonPersistentAppCrashDetectionWithScopedResets() {
-        // this is old test where the flag needs to be disabled
-        mSetFlagsRule.disableFlags(Flags.FLAG_RECOVERABILITY_DETECTION);
-
-        RescueParty.onSettingsProviderPublished(mMockContext);
-        verify(() -> DeviceConfig.setMonitorCallback(eq(mMockContentResolver),
-                any(Executor.class),
-                mMonitorCallbackCaptor.capture()));
-
-        // Record DeviceConfig accesses
-        RescuePartyObserver observer = RescuePartyObserver.getInstance(mMockContext);
-        DeviceConfig.MonitorCallback monitorCallback = mMonitorCallbackCaptor.getValue();
-        monitorCallback.onDeviceConfigAccess(CALLING_PACKAGE1, NAMESPACE1);
-        monitorCallback.onDeviceConfigAccess(CALLING_PACKAGE1, NAMESPACE2);
-        monitorCallback.onDeviceConfigAccess(CALLING_PACKAGE2, NAMESPACE2);
-        monitorCallback.onDeviceConfigAccess(CALLING_PACKAGE2, NAMESPACE3);
-
-        // Fake DeviceConfig value changes
-        monitorCallback.onNamespaceUpdate(NAMESPACE1);
-        verify(mMockPackageWatchdog).startObservingHealth(observer,
-                Arrays.asList(CALLING_PACKAGE1), RescueParty.DEFAULT_OBSERVING_DURATION_MS);
-        monitorCallback.onNamespaceUpdate(NAMESPACE2);
-        verify(mMockPackageWatchdog, times(2)).startObservingHealth(eq(observer),
-                mPackageListCaptor.capture(),
-                eq(RescueParty.DEFAULT_OBSERVING_DURATION_MS));
-        monitorCallback.onNamespaceUpdate(NAMESPACE3);
-        verify(mMockPackageWatchdog).startObservingHealth(observer,
-                Arrays.asList(CALLING_PACKAGE2), RescueParty.DEFAULT_OBSERVING_DURATION_MS);
-        assertTrue(mPackageListCaptor.getValue().containsAll(
-                Arrays.asList(CALLING_PACKAGE1, CALLING_PACKAGE2)));
-        // Perform and verify scoped resets
-        final String[] expectedResetNamespaces = new String[]{NAMESPACE1, NAMESPACE2};
-        final String[] expectedAllResetNamespaces =
-                new String[]{NAMESPACE1, NAMESPACE2, NAMESPACE3};
-        HashMap<String, Integer> verifiedTimesMap = new HashMap<String, Integer>();
-        observer.execute(new VersionedPackage(
-                CALLING_PACKAGE1, 1), PackageWatchdog.FAILURE_REASON_APP_CRASH, 1);
-
-        observer.execute(new VersionedPackage(
-                CALLING_PACKAGE1, 1), PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 2);
-
-        observer.execute(new VersionedPackage(
-                CALLING_PACKAGE1, 1), PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 3);
-
-        observer.execute(new VersionedPackage(
-                CALLING_PACKAGE1, 1), PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 4);
-        assertFalse(RescueParty.isRebootPropertySet());
-
-        observer.execute(new VersionedPackage(
-                CALLING_PACKAGE1, 1), PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 5);
-        assertFalse(RescueParty.isFactoryResetPropertySet());
-    }
-
-    @Test
     public void testIsRecoveryTriggeredReboot() {
         for (int i = 0; i < LEVEL_FACTORY_RESET; i++) {
             noteBoot(i + 1);
@@ -474,19 +464,6 @@
     }
 
     @Test
-    public void testIsRecoveryTriggeredRebootRecoverabilityDetection() {
-        mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION);
-        for (int i = 0; i < RESCUE_LEVEL_FACTORY_RESET; i++) {
-            noteBoot(i + 1);
-        }
-        assertFalse(RescueParty.isFactoryResetPropertySet());
-        setCrashRecoveryPropAttemptingReboot(false);
-        noteBoot(RESCUE_LEVEL_FACTORY_RESET + 1);
-        assertTrue(RescueParty.isRecoveryTriggeredReboot());
-        assertTrue(RescueParty.isFactoryResetPropertySet());
-    }
-
-    @Test
     public void testIsRecoveryTriggeredRebootOnlyAfterRebootCompleted() {
         for (int i = 0; i < LEVEL_FACTORY_RESET; i++) {
             noteBoot(i + 1);
@@ -505,25 +482,6 @@
     }
 
     @Test
-    public void testIsRecoveryTriggeredRebootOnlyAfterRebootCompletedRecoverabilityDetection() {
-        mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION);
-        for (int i = 0; i < RESCUE_LEVEL_FACTORY_RESET; i++) {
-            noteBoot(i + 1);
-        }
-        int mitigationCount = RESCUE_LEVEL_FACTORY_RESET + 1;
-        assertFalse(RescueParty.isFactoryResetPropertySet());
-        noteBoot(mitigationCount++);
-        assertFalse(RescueParty.isFactoryResetPropertySet());
-        noteBoot(mitigationCount++);
-        assertFalse(RescueParty.isFactoryResetPropertySet());
-        noteBoot(mitigationCount++);
-        setCrashRecoveryPropAttemptingReboot(false);
-        noteBoot(mitigationCount + 1);
-        assertTrue(RescueParty.isRecoveryTriggeredReboot());
-        assertTrue(RescueParty.isFactoryResetPropertySet());
-    }
-
-    @Test
     public void testThrottlingOnBootFailures() {
         setCrashRecoveryPropAttemptingReboot(false);
         long now = System.currentTimeMillis();
@@ -537,20 +495,6 @@
     }
 
     @Test
-    public void testThrottlingOnBootFailuresRecoverabilityDetection() {
-        mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION);
-        setCrashRecoveryPropAttemptingReboot(false);
-        long now = System.currentTimeMillis();
-        long beforeTimeout = now - TimeUnit.MINUTES.toMillis(
-                DEFAULT_FACTORY_RESET_THROTTLE_DURATION_MIN - 1);
-        setCrashRecoveryPropLastFactoryReset(beforeTimeout);
-        for (int i = 1; i <= RESCUE_LEVEL_FACTORY_RESET; i++) {
-            noteBoot(i);
-        }
-        assertFalse(RescueParty.isRecoveryTriggeredReboot());
-    }
-
-    @Test
     public void testThrottlingOnAppCrash() {
         setCrashRecoveryPropAttemptingReboot(false);
         long now = System.currentTimeMillis();
@@ -564,20 +508,6 @@
     }
 
     @Test
-    public void testThrottlingOnAppCrashRecoverabilityDetection() {
-        mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION);
-        setCrashRecoveryPropAttemptingReboot(false);
-        long now = System.currentTimeMillis();
-        long beforeTimeout = now - TimeUnit.MINUTES.toMillis(
-                DEFAULT_FACTORY_RESET_THROTTLE_DURATION_MIN - 1);
-        setCrashRecoveryPropLastFactoryReset(beforeTimeout);
-        for (int i = 0; i <= RESCUE_LEVEL_FACTORY_RESET; i++) {
-            noteAppCrash(i + 1, true);
-        }
-        assertFalse(RescueParty.isRecoveryTriggeredReboot());
-    }
-
-    @Test
     public void testNotThrottlingAfterTimeoutOnBootFailures() {
         setCrashRecoveryPropAttemptingReboot(false);
         long now = System.currentTimeMillis();
@@ -591,20 +521,6 @@
     }
 
     @Test
-    public void testNotThrottlingAfterTimeoutOnBootFailuresRecoverabilityDetection() {
-        mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION);
-        setCrashRecoveryPropAttemptingReboot(false);
-        long now = System.currentTimeMillis();
-        long afterTimeout = now - TimeUnit.MINUTES.toMillis(
-                DEFAULT_FACTORY_RESET_THROTTLE_DURATION_MIN + 1);
-        setCrashRecoveryPropLastFactoryReset(afterTimeout);
-        for (int i = 1; i <= RESCUE_LEVEL_FACTORY_RESET; i++) {
-            noteBoot(i);
-        }
-        assertTrue(RescueParty.isRecoveryTriggeredReboot());
-    }
-
-    @Test
     public void testNotThrottlingAfterTimeoutOnAppCrash() {
         setCrashRecoveryPropAttemptingReboot(false);
         long now = System.currentTimeMillis();
@@ -618,20 +534,7 @@
     }
 
     @Test
-    public void testNotThrottlingAfterTimeoutOnAppCrashRecoverabilityDetection() {
-        mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION);
-        setCrashRecoveryPropAttemptingReboot(false);
-        long now = System.currentTimeMillis();
-        long afterTimeout = now - TimeUnit.MINUTES.toMillis(
-                DEFAULT_FACTORY_RESET_THROTTLE_DURATION_MIN + 1);
-        setCrashRecoveryPropLastFactoryReset(afterTimeout);
-        for (int i = 0; i <= RESCUE_LEVEL_FACTORY_RESET; i++) {
-            noteAppCrash(i + 1, true);
-        }
-        assertTrue(RescueParty.isRecoveryTriggeredReboot());
-    }
-
-    @Test
+    @DisableFlags(Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS)
     public void testNativeRescuePartyResets() {
         doReturn(true).when(() -> SettingsToPropertiesMapper.isNativeFlagsResetPerformed());
         doReturn(FAKE_RESET_NATIVE_NAMESPACES).when(
@@ -647,7 +550,6 @@
 
     @Test
     public void testExplicitlyEnablingAndDisablingRescue() {
-        mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION);
         SystemProperties.set(RescueParty.PROP_ENABLE_RESCUE, Boolean.toString(false));
         SystemProperties.set(PROP_DISABLE_RESCUE, Boolean.toString(true));
         assertEquals(RescuePartyObserver.getInstance(mMockContext).execute(sFailingPackage,
@@ -660,7 +562,6 @@
 
     @Test
     public void testDisablingRescueByDeviceConfigFlag() {
-        mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION);
         SystemProperties.set(RescueParty.PROP_ENABLE_RESCUE, Boolean.toString(false));
         SystemProperties.set(PROP_DEVICE_CONFIG_DISABLE_FLAG, Boolean.toString(true));
 
@@ -686,24 +587,10 @@
     }
 
     @Test
-    public void testDisablingFactoryResetByDeviceConfigFlagRecoverabilityDetection() {
-        mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION);
-        SystemProperties.set(PROP_DISABLE_FACTORY_RESET_FLAG, Boolean.toString(true));
-
-        for (int i = 0; i < RESCUE_LEVEL_FACTORY_RESET; i++) {
-            noteBoot(i + 1);
-        }
-        assertFalse(RescueParty.isFactoryResetPropertySet());
-
-        // Restore the property value initialized in SetUp()
-        SystemProperties.set(PROP_DISABLE_FACTORY_RESET_FLAG, "");
-    }
-
-    @Test
+    @DisableFlags({Flags.FLAG_RECOVERABILITY_DETECTION,
+            Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS})
     public void testHealthCheckLevels() {
         // this is old test where the flag needs to be disabled
-        mSetFlagsRule.disableFlags(Flags.FLAG_RECOVERABILITY_DETECTION);
-
         RescuePartyObserver observer = RescuePartyObserver.getInstance(mMockContext);
 
         // Ensure that no action is taken for cases where the failure reason is unknown
@@ -729,8 +616,9 @@
     }
 
     @Test
+    @DisableFlags(Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS)
+    @EnableFlags(Flags.FLAG_RECOVERABILITY_DETECTION)
     public void testHealthCheckLevelsRecoverabilityDetection() {
-        mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION);
         RescuePartyObserver observer = RescuePartyObserver.getInstance(mMockContext);
 
         // Ensure that no action is taken for cases where the failure reason is unknown
@@ -767,11 +655,31 @@
                 PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 7),
                 PackageHealthObserverImpact.USER_IMPACT_LEVEL_40);
     }
-
     @Test
+    @EnableFlags(Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS)
+    public void testHealthCheckLevelsNoFlags() {
+        // this is old test where the flag needs to be disabled
+        RescuePartyObserver observer = RescuePartyObserver.getInstance(mMockContext);
+
+        // Ensure that no action is taken for cases where the failure reason is unknown
+        assertEquals(observer.onHealthCheckFailed(null, PackageWatchdog.FAILURE_REASON_UNKNOWN, 1),
+                PackageHealthObserverImpact.USER_IMPACT_LEVEL_0);
+
+        // Ensure the correct user impact is returned for each mitigation count.
+        assertEquals(observer.onHealthCheckFailed(null,
+                        PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 1),
+                PackageHealthObserverImpact.USER_IMPACT_LEVEL_50);
+
+        assertEquals(observer.onHealthCheckFailed(null,
+                        PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 2),
+                PackageHealthObserverImpact.USER_IMPACT_LEVEL_100);
+    }
+    @Test
+    @DisableFlags({Flags.FLAG_RECOVERABILITY_DETECTION,
+            Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS})
     public void testBootLoopLevels() {
         // this is old test where the flag needs to be disabled
-        mSetFlagsRule.disableFlags(Flags.FLAG_RECOVERABILITY_DETECTION);
+
 
         RescuePartyObserver observer = RescuePartyObserver.getInstance(mMockContext);
 
@@ -784,8 +692,9 @@
     }
 
     @Test
+    @DisableFlags(Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS)
+    @EnableFlags(Flags.FLAG_RECOVERABILITY_DETECTION)
     public void testBootLoopLevelsRecoverabilityDetection() {
-        mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION);
         RescuePartyObserver observer = RescuePartyObserver.getInstance(mMockContext);
 
         assertEquals(observer.onBootLoop(1), PackageHealthObserverImpact.USER_IMPACT_LEVEL_40);
@@ -797,6 +706,16 @@
     }
 
     @Test
+    @EnableFlags(Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS)
+    public void testBootLoopLevelsNoFlags() {
+        RescuePartyObserver observer = RescuePartyObserver.getInstance(mMockContext);
+
+        assertEquals(observer.onBootLoop(1), PackageHealthObserverImpact.USER_IMPACT_LEVEL_50);
+        assertEquals(observer.onBootLoop(2), PackageHealthObserverImpact.USER_IMPACT_LEVEL_100);
+    }
+
+    @Test
+    @DisableFlags(Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS)
     public void testResetDeviceConfigForPackagesOnlyRuntimeMap() {
         RescueParty.onSettingsProviderPublished(mMockContext);
         verify(() -> DeviceConfig.setMonitorCallback(eq(mMockContentResolver),
@@ -827,6 +746,7 @@
     }
 
     @Test
+    @DisableFlags(Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS)
     public void testResetDeviceConfigForPackagesOnlyPresetMap() {
         RescueParty.onSettingsProviderPublished(mMockContext);
         verify(() -> DeviceConfig.setMonitorCallback(eq(mMockContentResolver),
@@ -835,7 +755,7 @@
 
         String presetMapping = NAMESPACE1 + ":" + CALLING_PACKAGE1 + ","
                 + NAMESPACE2 + ":" + CALLING_PACKAGE2 + ","
-                + NAMESPACE3 +  ":" + CALLING_PACKAGE1;
+                + NAMESPACE3 + ":" + CALLING_PACKAGE1;
         doReturn(presetMapping).when(() -> DeviceConfig.getString(
                 eq(RescueParty.NAMESPACE_CONFIGURATION),
                 eq(RescueParty.NAMESPACE_TO_PACKAGE_MAPPING_FLAG),
@@ -848,6 +768,7 @@
     }
 
     @Test
+    @DisableFlags(Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS)
     public void testResetDeviceConfigForPackagesBothMaps() {
         RescueParty.onSettingsProviderPublished(mMockContext);
         verify(() -> DeviceConfig.setMonitorCallback(eq(mMockContentResolver),
@@ -884,6 +805,7 @@
     }
 
     @Test
+    @DisableFlags(Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS)
     public void testResetDeviceConfigNoExceptionWhenFlagMalformed() {
         RescueParty.onSettingsProviderPublished(mMockContext);
         verify(() -> DeviceConfig.setMonitorCallback(eq(mMockContentResolver),
diff --git a/services/tests/mockingservicestests/src/com/android/server/trust/TrustManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/trust/TrustManagerServiceTest.java
index 7aec42b..00daf41 100644
--- a/services/tests/mockingservicestests/src/com/android/server/trust/TrustManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/trust/TrustManagerServiceTest.java
@@ -43,6 +43,7 @@
 import android.Manifest;
 import android.annotation.Nullable;
 import android.app.ActivityManager;
+import android.app.ActivityManagerInternal;
 import android.app.AlarmManager;
 import android.app.IActivityManager;
 import android.app.admin.DevicePolicyManager;
@@ -142,6 +143,7 @@
     private final Map<ComponentName, ITrustAgentService.Stub> mMockTrustAgents = new HashMap<>();
 
     private @Mock ActivityManager mActivityManager;
+    private @Mock ActivityManagerInternal mActivityManagerInternal;
     private @Mock AlarmManager mAlarmManager;
     private @Mock BiometricManager mBiometricManager;
     private @Mock DevicePolicyManager mDevicePolicyManager;
@@ -158,6 +160,7 @@
     private HandlerThread mHandlerThread;
     private TrustManagerService mService;
     private ITrustManager mTrustManager;
+    private ActivityManagerInternal mPreviousActivityManagerInternal;
 
     @Before
     public void setUp() throws Exception {
@@ -210,6 +213,11 @@
         mMockContext.setMockPackageManager(mPackageManager);
         mMockContext.addMockSystemService(UserManager.class, mUserManager);
         doReturn(mWindowManager).when(() -> WindowManagerGlobal.getWindowManagerService());
+        mPreviousActivityManagerInternal = LocalServices.getService(
+                ActivityManagerInternal.class);
+        LocalServices.removeServiceForTest(ActivityManagerInternal.class);
+        LocalServices.addService(ActivityManagerInternal.class,
+                mActivityManagerInternal);
         LocalServices.addService(SystemServiceManager.class, mock(SystemServiceManager.class));
 
         grantPermission(Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE);
@@ -257,7 +265,14 @@
     @After
     public void tearDown() {
         LocalServices.removeServiceForTest(SystemServiceManager.class);
-        mHandlerThread.quit();
+        LocalServices.removeServiceForTest(ActivityManagerInternal.class);
+        if (mPreviousActivityManagerInternal != null) {
+            LocalServices.addService(ActivityManagerInternal.class,
+                    mPreviousActivityManagerInternal);
+        }
+        if (mHandlerThread != null) {
+            mHandlerThread.quit();
+        }
     }
 
     @Test
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockscreenRepairModeTest.java b/services/tests/servicestests/src/com/android/server/locksettings/LockscreenRepairModeTest.java
index 70150c5..4396c67 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockscreenRepairModeTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockscreenRepairModeTest.java
@@ -19,6 +19,8 @@
 import static com.android.internal.widget.LockPatternUtils.USER_REPAIR_MODE;
 import static com.android.internal.widget.LockPatternUtils.VERIFY_FLAG_WRITE_REPAIR_MODE_PW;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertSame;
 
@@ -199,6 +201,27 @@
                         .getResponseCode());
     }
 
+    @Test
+    public void writeRepairModeCredential_noLock() {
+        assertThat(mService.writeRepairModeCredential(PRIMARY_USER_ID)).isFalse();
+    }
+
+    @Test
+    public void writeRepairModeCredential_hasLock() {
+        mService.setLockCredential(newPin("1234"), nonePassword(), PRIMARY_USER_ID);
+        assertThat(mService.writeRepairModeCredential(PRIMARY_USER_ID)).isTrue();
+    }
+
+    @Test
+    public void writeRepairModeCredential_verifyRepairModeUser() {
+        mService.setLockCredential(newPin("1234"), nonePassword(), PRIMARY_USER_ID);
+        mService.writeRepairModeCredential(PRIMARY_USER_ID);
+        setRepairModeActive(true);
+
+        var response = mService.verifyCredential(newPin("1234"), USER_REPAIR_MODE, 0);
+        assertThat(response.isMatched()).isTrue();
+    }
+
     private void setRepairModeActive(boolean active) {
         Settings.Global.putInt(mContext.getContentResolver(),
                 Settings.Global.REPAIR_MODE_ACTIVE, active ? 1 : 0);
diff --git a/test-mock/src/android/test/mock/MockContext.java b/test-mock/src/android/test/mock/MockContext.java
index cf38bea..6bf7ff5 100644
--- a/test-mock/src/android/test/mock/MockContext.java
+++ b/test-mock/src/android/test/mock/MockContext.java
@@ -479,6 +479,15 @@
         throw new UnsupportedOperationException();
     }
 
+    /** @hide */
+    @Override
+    public void sendOrderedBroadcastAsUserMultiplePermissions(Intent intent, UserHandle user,
+            String[] receiverPermissions, int appOp, Bundle options,
+            BroadcastReceiver resultReceiver, Handler scheduler, int initialCode,
+            String initialData, Bundle initialExtras) {
+        throw new UnsupportedOperationException();
+    }
+
     @Override
     public void sendOrderedBroadcast(Intent intent, String receiverPermission,
             String receiverAppOp, BroadcastReceiver resultReceiver, Handler scheduler,
diff --git a/tests/PackageWatchdog/src/com/android/server/CrashRecoveryTest.java b/tests/PackageWatchdog/src/com/android/server/CrashRecoveryTest.java
index 489ef44..3722fef 100644
--- a/tests/PackageWatchdog/src/com/android/server/CrashRecoveryTest.java
+++ b/tests/PackageWatchdog/src/com/android/server/CrashRecoveryTest.java
@@ -47,6 +47,8 @@
 import android.os.Handler;
 import android.os.SystemProperties;
 import android.os.test.TestLooper;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
 import android.platform.test.flag.junit.SetFlagsRule;
 import android.provider.DeviceConfig;
 import android.util.AtomicFile;
@@ -288,7 +290,8 @@
     }
 
     @Test
-    public void testBootLoopWithRescuePartyAndRollbackPackageHealthObserver() throws Exception {
+    @DisableFlags(Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS)
+    public void testBootLoopWithRescuePartyAndRollbackObserver() throws Exception {
         PackageWatchdog watchdog = createWatchdog();
         RescuePartyObserver rescuePartyObserver = setUpRescuePartyObserver(watchdog);
         RollbackPackageHealthObserver rollbackObserver =
@@ -360,6 +363,56 @@
         verify(rescuePartyObserver, never()).executeBootLoopMitigation(2);
     }
 
+    @Test
+    @EnableFlags(Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS)
+    public void testBootLoopWithRescuePartyAndRollbackObserverNoFlags() throws Exception {
+        PackageWatchdog watchdog = createWatchdog();
+        RescuePartyObserver rescuePartyObserver = setUpRescuePartyObserver(watchdog);
+        RollbackPackageHealthObserver rollbackObserver =
+                setUpRollbackPackageHealthObserver(watchdog);
+
+        verify(rescuePartyObserver, never()).executeBootLoopMitigation(1);
+        verify(rollbackObserver, never()).executeBootLoopMitigation(1);
+        for (int i = 0; i < PackageWatchdog.DEFAULT_BOOT_LOOP_TRIGGER_COUNT; i++) {
+            watchdog.noteBoot();
+        }
+        verify(rescuePartyObserver).executeBootLoopMitigation(1);
+        verify(rescuePartyObserver, never()).executeBootLoopMitigation(2);
+        verify(rollbackObserver, never()).executeBootLoopMitigation(1);
+
+        watchdog.noteBoot();
+
+        verify(rescuePartyObserver, never()).executeBootLoopMitigation(2);
+        verify(rollbackObserver).executeBootLoopMitigation(1);
+        verify(rollbackObserver, never()).executeBootLoopMitigation(2);
+        // Update the list of available rollbacks after executing bootloop mitigation once
+        when(mRollbackManager.getAvailableRollbacks()).thenReturn(List.of(ROLLBACK_INFO_HIGH,
+                ROLLBACK_INFO_MANUAL));
+
+        watchdog.noteBoot();
+
+        verify(rescuePartyObserver, never()).executeBootLoopMitigation(2);
+        verify(rollbackObserver).executeBootLoopMitigation(2);
+        verify(rollbackObserver, never()).executeBootLoopMitigation(3);
+        // Update the list of available rollbacks after executing bootloop mitigation
+        when(mRollbackManager.getAvailableRollbacks()).thenReturn(List.of(ROLLBACK_INFO_MANUAL));
+
+        watchdog.noteBoot();
+
+        verify(rescuePartyObserver).executeBootLoopMitigation(2);
+        verify(rescuePartyObserver, never()).executeBootLoopMitigation(3);
+        verify(rollbackObserver, never()).executeBootLoopMitigation(3);
+
+        moveTimeForwardAndDispatch(PackageWatchdog.DEFAULT_DEESCALATION_WINDOW_MS + 1);
+        Mockito.reset(rescuePartyObserver);
+
+        for (int i = 0; i < PackageWatchdog.DEFAULT_BOOT_LOOP_TRIGGER_COUNT; i++) {
+            watchdog.noteBoot();
+        }
+        verify(rescuePartyObserver).executeBootLoopMitigation(1);
+        verify(rescuePartyObserver, never()).executeBootLoopMitigation(2);
+    }
+
     RollbackPackageHealthObserver setUpRollbackPackageHealthObserver(PackageWatchdog watchdog) {
         RollbackPackageHealthObserver rollbackObserver =
                 spy(new RollbackPackageHealthObserver(mSpyContext, mApexManager));
diff --git a/tests/TrustTests/AndroidManifest.xml b/tests/TrustTests/AndroidManifest.xml
index 30cf345..2f6c0dd 100644
--- a/tests/TrustTests/AndroidManifest.xml
+++ b/tests/TrustTests/AndroidManifest.xml
@@ -78,6 +78,7 @@
                 <action android:name="android.service.trust.TrustAgentService" />
             </intent-filter>
         </service>
+
         <service
             android:name=".IsActiveUnlockRunningTrustAgent"
             android:exported="true"
@@ -88,6 +89,16 @@
             </intent-filter>
         </service>
 
+        <service
+            android:name=".UnlockAttemptTrustAgent"
+            android:exported="true"
+            android:label="Test Agent"
+            android:permission="android.permission.BIND_TRUST_AGENT">
+            <intent-filter>
+                <action android:name="android.service.trust.TrustAgentService" />
+            </intent-filter>
+        </service>
+
     </application>
 
     <!--  self-instrumenting test package. -->
diff --git a/tests/TrustTests/src/android/trust/test/UnlockAttemptTest.kt b/tests/TrustTests/src/android/trust/test/UnlockAttemptTest.kt
new file mode 100644
index 0000000..2c9361d
--- /dev/null
+++ b/tests/TrustTests/src/android/trust/test/UnlockAttemptTest.kt
@@ -0,0 +1,227 @@
+/*
+ * Copyright (C) 2024 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.trust.test
+
+import android.app.trust.TrustManager
+import android.content.Context
+import android.trust.BaseTrustAgentService
+import android.trust.TrustTestActivity
+import android.trust.test.lib.LockStateTrackingRule
+import android.trust.test.lib.ScreenLockRule
+import android.trust.test.lib.TestTrustListener
+import android.trust.test.lib.TrustAgentRule
+import android.util.Log
+import androidx.test.core.app.ApplicationProvider.getApplicationContext
+import androidx.test.ext.junit.rules.ActivityScenarioRule
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.rules.RuleChain
+import org.junit.runner.RunWith
+
+/**
+ * Test for the impacts of reporting unlock attempts.
+ *
+ * atest TrustTests:UnlockAttemptTest
+ */
+@RunWith(AndroidJUnit4::class)
+class UnlockAttemptTest {
+    private val context = getApplicationContext<Context>()
+    private val trustManager = context.getSystemService(TrustManager::class.java) as TrustManager
+    private val userId = context.userId
+    private val activityScenarioRule = ActivityScenarioRule(TrustTestActivity::class.java)
+    private val screenLockRule = ScreenLockRule(requireStrongAuth = true)
+    private val lockStateTrackingRule = LockStateTrackingRule()
+    private val trustAgentRule =
+        TrustAgentRule<UnlockAttemptTrustAgent>(startUnlocked = false, startEnabled = false)
+
+    private val trustListener = UnlockAttemptTrustListener()
+    private val agent get() = trustAgentRule.agent
+
+    @get:Rule
+    val rule: RuleChain =
+        RuleChain.outerRule(activityScenarioRule)
+            .around(screenLockRule)
+            .around(lockStateTrackingRule)
+            .around(trustAgentRule)
+
+    @Before
+    fun setUp() {
+        trustManager.registerTrustListener(trustListener)
+    }
+
+    @Test
+    fun successfulUnlockAttempt_allowsTrustAgentToStart() =
+        runUnlockAttemptTest(enableAndVerifyTrustAgent = false, managingTrust = false) {
+            trustAgentRule.enableTrustAgent()
+
+            triggerSuccessfulUnlock()
+
+            trustAgentRule.verifyAgentIsRunning(MAX_WAIT_FOR_ENABLED_TRUST_AGENT_TO_START)
+        }
+
+    @Test
+    fun successfulUnlockAttempt_notifiesTrustAgent() =
+        runUnlockAttemptTest(enableAndVerifyTrustAgent = true, managingTrust = true) {
+            val oldSuccessfulCount = agent.successfulUnlockCallCount
+            val oldFailedCount = agent.failedUnlockCallCount
+
+            triggerSuccessfulUnlock()
+
+            assertThat(agent.successfulUnlockCallCount).isEqualTo(oldSuccessfulCount + 1)
+            assertThat(agent.failedUnlockCallCount).isEqualTo(oldFailedCount)
+        }
+
+    @Test
+    fun successfulUnlockAttempt_notifiesTrustListenerOfManagedTrust() =
+        runUnlockAttemptTest(enableAndVerifyTrustAgent = true, managingTrust = true) {
+            val oldTrustManagedChangedCount = trustListener.onTrustManagedChangedCount[userId] ?: 0
+
+            triggerSuccessfulUnlock()
+
+            assertThat(trustListener.onTrustManagedChangedCount[userId] ?: 0).isEqualTo(
+                oldTrustManagedChangedCount + 1
+            )
+        }
+
+    @Test
+    fun failedUnlockAttempt_doesNotAllowTrustAgentToStart() =
+        runUnlockAttemptTest(enableAndVerifyTrustAgent = false, managingTrust = false) {
+            trustAgentRule.enableTrustAgent()
+
+            triggerFailedUnlock()
+
+            trustAgentRule.ensureAgentIsNotRunning(MAX_WAIT_FOR_ENABLED_TRUST_AGENT_TO_START)
+        }
+
+    @Test
+    fun failedUnlockAttempt_notifiesTrustAgent() =
+        runUnlockAttemptTest(enableAndVerifyTrustAgent = true, managingTrust = true) {
+            val oldSuccessfulCount = agent.successfulUnlockCallCount
+            val oldFailedCount = agent.failedUnlockCallCount
+
+            triggerFailedUnlock()
+
+            assertThat(agent.successfulUnlockCallCount).isEqualTo(oldSuccessfulCount)
+            assertThat(agent.failedUnlockCallCount).isEqualTo(oldFailedCount + 1)
+        }
+
+    @Test
+    fun failedUnlockAttempt_doesNotNotifyTrustListenerOfManagedTrust() =
+        runUnlockAttemptTest(enableAndVerifyTrustAgent = true, managingTrust = true) {
+            val oldTrustManagedChangedCount = trustListener.onTrustManagedChangedCount[userId] ?: 0
+
+            triggerFailedUnlock()
+
+            assertThat(trustListener.onTrustManagedChangedCount[userId] ?: 0).isEqualTo(
+                oldTrustManagedChangedCount
+            )
+        }
+
+    private fun runUnlockAttemptTest(
+        enableAndVerifyTrustAgent: Boolean,
+        managingTrust: Boolean,
+        testBlock: () -> Unit,
+    ) {
+        if (enableAndVerifyTrustAgent) {
+            Log.i(TAG, "Triggering successful unlock")
+            triggerSuccessfulUnlock()
+            Log.i(TAG, "Enabling and waiting for trust agent")
+            trustAgentRule.enableAndVerifyTrustAgentIsRunning(
+                MAX_WAIT_FOR_ENABLED_TRUST_AGENT_TO_START
+            )
+            Log.i(TAG, "Managing trust: $managingTrust")
+            agent.setManagingTrust(managingTrust)
+            await()
+        }
+        testBlock()
+    }
+
+    private fun triggerSuccessfulUnlock() {
+        screenLockRule.successfulScreenLockAttempt()
+        trustAgentRule.reportSuccessfulUnlock()
+        await()
+    }
+
+    private fun triggerFailedUnlock() {
+        screenLockRule.failedScreenLockAttempt()
+        trustAgentRule.reportFailedUnlock()
+        await()
+    }
+
+    companion object {
+        private const val TAG = "UnlockAttemptTest"
+        private fun await(millis: Long = 500) = Thread.sleep(millis)
+        private const val MAX_WAIT_FOR_ENABLED_TRUST_AGENT_TO_START = 10000L
+    }
+}
+
+class UnlockAttemptTrustAgent : BaseTrustAgentService() {
+    var successfulUnlockCallCount: Long = 0
+        private set
+    var failedUnlockCallCount: Long = 0
+        private set
+
+    override fun onUnlockAttempt(successful: Boolean) {
+        super.onUnlockAttempt(successful)
+        if (successful) {
+            successfulUnlockCallCount++
+        } else {
+            failedUnlockCallCount++
+        }
+    }
+}
+
+private class UnlockAttemptTrustListener : TestTrustListener() {
+    var enabledTrustAgentsChangedCount = mutableMapOf<Int, Int>()
+    var onTrustManagedChangedCount = mutableMapOf<Int, Int>()
+
+    override fun onEnabledTrustAgentsChanged(userId: Int) {
+        enabledTrustAgentsChangedCount.compute(userId) { _: Int, curr: Int? ->
+            if (curr == null) 0 else curr + 1
+        }
+    }
+
+    data class TrustChangedParams(
+        val enabled: Boolean,
+        val newlyUnlocked: Boolean,
+        val userId: Int,
+        val flags: Int,
+        val trustGrantedMessages: MutableList<String>?
+    )
+
+    val onTrustChangedCalls = mutableListOf<TrustChangedParams>()
+
+    override fun onTrustChanged(
+        enabled: Boolean,
+        newlyUnlocked: Boolean,
+        userId: Int,
+        flags: Int,
+        trustGrantedMessages: MutableList<String>
+    ) {
+        onTrustChangedCalls += TrustChangedParams(
+            enabled, newlyUnlocked, userId, flags, trustGrantedMessages
+        )
+    }
+
+    override fun onTrustManagedChanged(enabled: Boolean, userId: Int) {
+        onTrustManagedChangedCount.compute(userId) { _: Int, curr: Int? ->
+            if (curr == null) 0 else curr + 1
+        }
+    }
+}
diff --git a/tests/TrustTests/src/android/trust/test/lib/ScreenLockRule.kt b/tests/TrustTests/src/android/trust/test/lib/ScreenLockRule.kt
index f1edca3..1ccdcc6 100644
--- a/tests/TrustTests/src/android/trust/test/lib/ScreenLockRule.kt
+++ b/tests/TrustTests/src/android/trust/test/lib/ScreenLockRule.kt
@@ -24,6 +24,8 @@
 import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
 import androidx.test.uiautomator.UiDevice
 import com.android.internal.widget.LockPatternUtils
+import com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED
+import com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN
 import com.android.internal.widget.LockscreenCredential
 import com.google.common.truth.Truth.assertWithMessage
 import org.junit.rules.TestRule
@@ -32,13 +34,18 @@
 
 /**
  * Sets a screen lock on the device for the duration of the test.
+ *
+ * @param requireStrongAuth Whether a strong auth is required at the beginning.
+ * If true, trust agents will not be available until the user verifies their credentials.
  */
-class ScreenLockRule : TestRule {
+class ScreenLockRule(val requireStrongAuth: Boolean = false) : TestRule {
     private val context: Context = getApplicationContext()
+    private val userId = context.userId
     private val uiDevice = UiDevice.getInstance(getInstrumentation())
     private val windowManager = checkNotNull(WindowManagerGlobal.getWindowManagerService())
     private val lockPatternUtils = LockPatternUtils(context)
     private var instantLockSavedValue = false
+    private var strongAuthSavedValue: Int = 0
 
     override fun apply(base: Statement, description: Description) = object : Statement() {
         override fun evaluate() {
@@ -46,10 +53,12 @@
             dismissKeyguard()
             setScreenLock()
             setLockOnPowerButton()
+            configureStrongAuthState()
 
             try {
                 base.evaluate()
             } finally {
+                restoreStrongAuthState()
                 removeScreenLock()
                 revertLockOnPowerButton()
                 dismissKeyguard()
@@ -57,6 +66,22 @@
         }
     }
 
+    private fun configureStrongAuthState() {
+        strongAuthSavedValue = lockPatternUtils.getStrongAuthForUser(userId)
+        if (requireStrongAuth) {
+            Log.d(TAG, "Triggering strong auth due to simulated lockdown")
+            lockPatternUtils.requireStrongAuth(STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN, userId)
+            wait("strong auth required after lockdown") {
+                lockPatternUtils.getStrongAuthForUser(userId) ==
+                        STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN
+            }
+        }
+    }
+
+    private fun restoreStrongAuthState() {
+        lockPatternUtils.requireStrongAuth(strongAuthSavedValue, userId)
+    }
+
     private fun verifyNoScreenLockAlreadySet() {
         assertWithMessage("Screen Lock must not already be set on device")
                 .that(lockPatternUtils.isSecure(context.userId))
@@ -82,6 +107,22 @@
         }
     }
 
+    fun successfulScreenLockAttempt() {
+        lockPatternUtils.verifyCredential(LockscreenCredential.createPin(PIN), context.userId, 0)
+        lockPatternUtils.userPresent(context.userId)
+        wait("strong auth not required") {
+            lockPatternUtils.getStrongAuthForUser(context.userId) == STRONG_AUTH_NOT_REQUIRED
+        }
+    }
+
+    fun failedScreenLockAttempt() {
+        lockPatternUtils.verifyCredential(
+            LockscreenCredential.createPin(WRONG_PIN),
+            context.userId,
+            0
+        )
+    }
+
     private fun setScreenLock() {
         lockPatternUtils.setLockCredential(
                 LockscreenCredential.createPin(PIN),
@@ -121,5 +162,6 @@
     companion object {
         private const val TAG = "ScreenLockRule"
         private const val PIN = "0000"
+        private const val WRONG_PIN = "0001"
     }
 }
diff --git a/tests/TrustTests/src/android/trust/test/lib/TrustAgentRule.kt b/tests/TrustTests/src/android/trust/test/lib/TrustAgentRule.kt
index 18bc029..404c6d9 100644
--- a/tests/TrustTests/src/android/trust/test/lib/TrustAgentRule.kt
+++ b/tests/TrustTests/src/android/trust/test/lib/TrustAgentRule.kt
@@ -20,14 +20,15 @@
 import android.content.ComponentName
 import android.content.Context
 import android.trust.BaseTrustAgentService
+import android.trust.test.lib.TrustAgentRule.Companion.invoke
 import android.util.Log
 import androidx.test.core.app.ApplicationProvider.getApplicationContext
 import com.android.internal.widget.LockPatternUtils
 import com.google.common.truth.Truth.assertWithMessage
+import kotlin.reflect.KClass
 import org.junit.rules.TestRule
 import org.junit.runner.Description
 import org.junit.runners.model.Statement
-import kotlin.reflect.KClass
 
 /**
  * Enables a trust agent and causes the system service to bind to it.
@@ -37,7 +38,9 @@
  * @constructor Creates the rule. Do not use; instead, use [invoke].
  */
 class TrustAgentRule<T : BaseTrustAgentService>(
-    private val serviceClass: KClass<T>
+    private val serviceClass: KClass<T>,
+    private val startUnlocked: Boolean,
+    private val startEnabled: Boolean,
 ) : TestRule {
     private val context: Context = getApplicationContext()
     private val trustManager = context.getSystemService(TrustManager::class.java) as TrustManager
@@ -48,11 +51,18 @@
     override fun apply(base: Statement, description: Description) = object : Statement() {
         override fun evaluate() {
             verifyTrustServiceRunning()
-            unlockDeviceWithCredential()
-            enableTrustAgent()
+            if (startUnlocked) {
+                reportSuccessfulUnlock()
+            } else {
+                Log.i(TAG, "Trust manager not starting in unlocked state")
+            }
 
             try {
-                verifyAgentIsRunning()
+                if (startEnabled) {
+                    enableAndVerifyTrustAgentIsRunning()
+                } else {
+                    Log.i(TAG, "Trust agent ${serviceClass.simpleName} not enabled")
+                }
                 base.evaluate()
             } finally {
                 disableTrustAgent()
@@ -64,12 +74,22 @@
         assertWithMessage("Trust service is not running").that(trustManager).isNotNull()
     }
 
-    private fun unlockDeviceWithCredential() {
-        Log.d(TAG, "Unlocking device with credential")
+    fun reportSuccessfulUnlock() {
+        Log.i(TAG, "Reporting successful unlock")
         trustManager.reportUnlockAttempt(true, context.userId)
     }
 
-    private fun enableTrustAgent() {
+    fun reportFailedUnlock() {
+        Log.i(TAG, "Reporting failed unlock")
+        trustManager.reportUnlockAttempt(false, context.userId)
+    }
+
+    fun enableAndVerifyTrustAgentIsRunning(maxWait: Long = 30000L) {
+        enableTrustAgent()
+        verifyAgentIsRunning(maxWait)
+    }
+
+    fun enableTrustAgent() {
         val componentName = ComponentName(context, serviceClass.java)
         val userId = context.userId
         Log.i(TAG, "Enabling trust agent ${componentName.flattenToString()} for user $userId")
@@ -79,12 +99,18 @@
         lockPatternUtils.setEnabledTrustAgents(agents, userId)
     }
 
-    private fun verifyAgentIsRunning() {
-        wait("${serviceClass.simpleName} to be running") {
+    fun verifyAgentIsRunning(maxWait: Long = 30000L) {
+        wait("${serviceClass.simpleName} to be running", maxWait) {
             BaseTrustAgentService.instance(serviceClass) != null
         }
     }
 
+    fun ensureAgentIsNotRunning(window: Long = 30000L) {
+        ensure("${serviceClass.simpleName} is not running", window) {
+            BaseTrustAgentService.instance(serviceClass) == null
+        }
+    }
+
     private fun disableTrustAgent() {
         val componentName = ComponentName(context, serviceClass.java)
         val userId = context.userId
@@ -97,13 +123,23 @@
 
     companion object {
         /**
-         * Creates a new rule for the specified agent class. Example usage:
+         * Creates a new rule for the specified agent class. Starts with the device unlocked and
+         * the trust agent enabled. Example usage:
          * ```
          *   @get:Rule val rule = TrustAgentRule<MyTestAgent>()
          * ```
+         *
+         * Also supports setting different device lock and trust agent enablement states:
+         * ```
+         *   @get:Rule val rule = TrustAgentRule<MyTestAgent>(startUnlocked = false, startEnabled = false)
+         * ```
          */
-        inline operator fun <reified T : BaseTrustAgentService> invoke() =
-            TrustAgentRule(T::class)
+        inline operator fun <reified T : BaseTrustAgentService> invoke(
+            startUnlocked: Boolean = true,
+            startEnabled: Boolean = true,
+        ) =
+            TrustAgentRule(T::class, startUnlocked, startEnabled)
+
 
         private const val TAG = "TrustAgentRule"
     }
diff --git a/tests/TrustTests/src/android/trust/test/lib/utils.kt b/tests/TrustTests/src/android/trust/test/lib/Utils.kt
similarity index 63%
rename from tests/TrustTests/src/android/trust/test/lib/utils.kt
rename to tests/TrustTests/src/android/trust/test/lib/Utils.kt
index e047202..3b32b47 100644
--- a/tests/TrustTests/src/android/trust/test/lib/utils.kt
+++ b/tests/TrustTests/src/android/trust/test/lib/Utils.kt
@@ -39,7 +39,7 @@
 ) {
     var waited = 0L
     var count = 0
-    while (!conditionFunction.invoke(count)) {
+    while (!conditionFunction(count)) {
         assertWithMessage("Condition exceeded maximum wait time of $maxWait ms: $description")
             .that(waited <= maxWait)
             .isTrue()
@@ -49,3 +49,34 @@
         Thread.sleep(rate)
     }
 }
+
+/**
+ * Ensures that [conditionFunction] is true with a failed assertion if it is not within [window]
+ * ms.
+ *
+ * The condition function can perform additional logic (for example, logging or attempting to make
+ * the condition become true).
+ *
+ * @param conditionFunction function which takes the attempt count & returns whether the condition
+ *                          is met
+ */
+internal fun ensure(
+    description: String? = null,
+    window: Long = 30000L,
+    rate: Long = 50L,
+    conditionFunction: (count: Int) -> Boolean
+) {
+    var waited = 0L
+    var count = 0
+    while (waited <= window) {
+        assertWithMessage("Condition failed within $window ms: $description").that(
+                conditionFunction(
+                    count
+                )
+            ).isTrue()
+        waited += rate
+        count++
+        Log.i(TAG, "Ensuring $description ($waited/$window) #$count")
+        Thread.sleep(rate)
+    }
+}