Do not change strong auth for users stopped with delayed locking

The private profile has the property allowStoppingUserWithDelayedLocking
set to true which ensures the user is stopped without evicting the CE
storage keys whenever the user is stopped for quiet mode. The change
here ensures that all such users that are stopped with delayed locking
and have their storage still unlocked are exempted from the strong auth
requirement changes. Additionally, user password metrics will also not
be removed on such user stops. Without this change, the StrongAuthTracker
will always force an LSKF check whenever the user is stopped.

Test: atest com.android.server.locksettings. Also,tested locally on device with private space setup and separate challenge enabled (with biometric added). Locking private space results in changing strong auth requirements to STRONG_AUTH_REQUIRED_AFTER_BOOT.

Bug: 312184187
Ignore-AOSP-First: Relies on private space feature flags

Change-Id: Iaad91abe392689988eeba7da72893b8b174f167e
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index ad09082..542b3b0 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -52,6 +52,7 @@
 import android.Manifest;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
 import android.annotation.UserIdInt;
 import android.app.ActivityManager;
 import android.app.IActivityManager;
@@ -74,6 +75,7 @@
 import android.content.IntentFilter;
 import android.content.pm.PackageManager;
 import android.content.pm.UserInfo;
+import android.content.pm.UserProperties;
 import android.content.res.Resources;
 import android.database.ContentObserver;
 import android.database.sqlite.SQLiteDatabase;
@@ -303,7 +305,7 @@
     private boolean mThirdPartyAppsStarted;
 
     // Current password metrics for all secured users on the device. Updated when user unlocks the
-    // device or changes password. Removed when user is stopped.
+    // device or changes password. Removed if user is stopped with its CE key evicted.
     @GuardedBy("this")
     private final SparseArray<PasswordMetrics> mUserPasswordMetrics = new SparseArray<>();
     @VisibleForTesting
@@ -793,13 +795,33 @@
     }
 
     @VisibleForTesting
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.MANAGE_USERS,
+            android.Manifest.permission.QUERY_USERS,
+            android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional = true)
     void onUserStopped(int userId) {
         hideEncryptionNotification(new UserHandle(userId));
-        // User is stopped with its CE key evicted. Restore strong auth requirement to the default
-        // flags after boot since stopping and restarting a user later is equivalent to rebooting
-        // the device.
+
+        // Normally, CE storage is locked when a user is stopped, and restarting the user requires
+        // strong auth.  Therefore, reset the user's strong auth flags.  The exception is users that
+        // allow delayed locking; under some circumstances, biometric authentication is allowed to
+        // restart such users.  Don't reset the strong auth flags for such users.
+        //
+        // TODO(b/319142556): It might make more sense to reset the strong auth flags when CE
+        // storage is locked, instead of when the user is stopped.  This would ensure the flags get
+        // reset if CE storage is locked later for a user that allows delayed locking.
+        if (android.os.Flags.allowPrivateProfile()
+                && android.multiuser.Flags.enableBiometricsToUnlockPrivateSpace()) {
+            UserProperties userProperties = mUserManager.getUserProperties(UserHandle.of(userId));
+            if (userProperties != null && userProperties.getAllowStoppingUserWithDelayedLocking()) {
+                return;
+            }
+        }
         int strongAuthRequired = LockPatternUtils.StrongAuthTracker.getDefaultFlags(mContext);
         requireStrongAuth(strongAuthRequired, userId);
+
+        // Don't keep the password metrics in memory for a stopped user that will require strong
+        // auth to start again, since strong auth will make the password metrics available again.
         synchronized (this) {
             mUserPasswordMetrics.remove(userId);
         }