Merge "profcollect: collect intilization code behavior for camera open events" into main
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/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/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..a4026eb 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;
+            }
         }
     }
 
@@ -731,11 +806,15 @@
             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()) {
+                        return mapRescueLevelToUserImpact(getRescueLevel(mitigationCount,
+                                mayPerformReboot(failedPackage), failedPackage));
+                    } else {
+                        return mapRescueLevelToUserImpact(getRescueLevel(mitigationCount));
+                    }
                 } else {
                     return mapRescueLevelToUserImpact(getRescueLevel(mitigationCount,
-                        mayPerformReboot(failedPackage)));
+                            mayPerformReboot(failedPackage)));
                 }
             } else {
                 return PackageHealthObserverImpact.USER_IMPACT_LEVEL_0;
@@ -750,10 +829,17 @@
             }
             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 +873,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 +890,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 +926,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 +938,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 +969,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 +1019,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/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/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/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);