LockSettingsService: move database storage

The database storage commands are part of ILockSettings, but the actual
storage takes place on LockSettingsStorage. Redirect the calls in
LockSettingsService to LockSettingsStorage to make the ownership a bit
more clear.

(cherry picked from commit 366c310e4ada13d629bc0dce14f71cad122db9e8)

Bug: 149833390
Test: atest LockSettingsStorageTests LockSettingsServiceTests
Change-Id: Ibc9236a171cedd3b09b1afed70895bc91e895a1c
Merged-In: Ibc9236a171cedd3b09b1afed70895bc91e895a1c
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 15dfab9..6faf674 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -50,7 +50,6 @@
 import android.app.admin.DevicePolicyManagerInternal;
 import android.app.admin.DeviceStateCache;
 import android.app.admin.PasswordMetrics;
-import android.app.backup.BackupManager;
 import android.app.trust.IStrongAuthTracker;
 import android.app.trust.TrustManager;
 import android.content.BroadcastReceiver;
@@ -112,10 +111,8 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
 import com.android.internal.notification.SystemNotificationChannels;
-import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.IndentingPrintWriter;
-import com.android.internal.util.Preconditions;
 import com.android.internal.widget.ICheckCredentialProgressCallback;
 import com.android.internal.widget.ILockSettings;
 import com.android.internal.widget.LockPatternUtils;
@@ -701,7 +698,7 @@
         // Serial number is never reusued, so we can use it as a distinguisher for user Id reuse.
         int serialNumber = mUserManager.getUserSerialNumber(userId);
 
-        int storedSerialNumber = getIntUnchecked(USER_SERIAL_NUMBER_KEY, -1, userId);
+        int storedSerialNumber = mStorage.getInt(USER_SERIAL_NUMBER_KEY, -1, userId);
         if (storedSerialNumber != serialNumber) {
             // If LockSettingsStorage does not have a copy of the serial number, it could be either
             // this is a user created before the serial number recording logic is introduced, or
@@ -710,7 +707,7 @@
             if (storedSerialNumber != -1) {
                 removeUser(userId, /* unknownUser */ true);
             }
-            setIntUnchecked(USER_SERIAL_NUMBER_KEY, serialNumber, userId);
+            mStorage.setInt(USER_SERIAL_NUMBER_KEY, serialNumber, userId);
         }
     }
 
@@ -1069,7 +1066,7 @@
 
     private boolean getSeparateProfileChallengeEnabledInternal(int userId) {
         synchronized (mSeparateChallengeLock) {
-            return getBooleanUnchecked(SEPARATE_PROFILE_CHALLENGE_KEY, false, userId);
+            return mStorage.getBoolean(SEPARATE_PROFILE_CHALLENGE_KEY, false, userId);
         }
     }
 
@@ -1122,94 +1119,49 @@
     @Override
     public void setBoolean(String key, boolean value, int userId) {
         checkWritePermission(userId);
-        setStringUnchecked(key, userId, value ? "1" : "0");
+        mStorage.setBoolean(key, value, userId);
     }
 
     @Override
     public void setLong(String key, long value, int userId) {
         checkWritePermission(userId);
-        setLongUnchecked(key, value, userId);
-    }
-
-    private void setLongUnchecked(String key, long value, int userId) {
-        setStringUnchecked(key, userId, Long.toString(value));
-    }
-
-    private void setIntUnchecked(String key, int value, int userId) {
-        setStringUnchecked(key, userId, Integer.toString(value));
+        mStorage.setLong(key, value, userId);
     }
 
     @Override
     public void setString(String key, String value, int userId) {
         checkWritePermission(userId);
-        setStringUnchecked(key, userId, value);
-    }
-
-    private void setStringUnchecked(String key, int userId, String value) {
-        Preconditions.checkArgument(userId != USER_FRP, "cannot store lock settings for FRP user");
-
-        mStorage.writeKeyValue(key, value, userId);
-        if (ArrayUtils.contains(SETTINGS_TO_BACKUP, key)) {
-            BackupManager.dataChanged("com.android.providers.settings");
-        }
+        mStorage.setString(key, value, userId);
     }
 
     @Override
     public boolean getBoolean(String key, boolean defaultValue, int userId) {
         checkReadPermission(key, userId);
-        return getBooleanUnchecked(key, defaultValue, userId);
-    }
-
-    private boolean getBooleanUnchecked(String key, boolean defaultValue, int userId) {
-        String value = getStringUnchecked(key, null, userId);
-        return TextUtils.isEmpty(value) ?
-                defaultValue : (value.equals("1") || value.equals("true"));
+        if (Settings.Secure.LOCK_PATTERN_ENABLED.equals(key)) {
+            return getCredentialTypeInternal(userId) == CREDENTIAL_TYPE_PATTERN;
+        }
+        return mStorage.getBoolean(key, defaultValue, userId);
     }
 
     @Override
     public long getLong(String key, long defaultValue, int userId) {
         checkReadPermission(key, userId);
-        return getLongUnchecked(key, defaultValue, userId);
-    }
-
-    private long getLongUnchecked(String key, long defaultValue, int userId) {
-        String value = getStringUnchecked(key, null, userId);
-        return TextUtils.isEmpty(value) ? defaultValue : Long.parseLong(value);
-    }
-
-    private int getIntUnchecked(String key, int defaultValue, int userId) {
-        String value = getStringUnchecked(key, null, userId);
-        return TextUtils.isEmpty(value) ? defaultValue : Integer.parseInt(value);
+        return mStorage.getLong(key, defaultValue, userId);
     }
 
     @Override
     public String getString(String key, String defaultValue, int userId) {
         checkReadPermission(key, userId);
-        return getStringUnchecked(key, defaultValue, userId);
-    }
-
-    private String getStringUnchecked(String key, String defaultValue, int userId) {
-        if (Settings.Secure.LOCK_PATTERN_ENABLED.equals(key)) {
-            return getCredentialTypeInternal(userId) == CREDENTIAL_TYPE_PATTERN ? "1" : "0";
-        }
-        if (userId == USER_FRP) {
-            return null;
-        }
-
-        if (LockPatternUtils.LEGACY_LOCK_PATTERN_ENABLED.equals(key)) {
-            key = Settings.Secure.LOCK_PATTERN_ENABLED;
-        }
-
-        return mStorage.readKeyValue(key, defaultValue, userId);
+        return mStorage.getString(key, defaultValue, userId);
     }
 
     private void setKeyguardStoredQuality(int quality, int userId) {
         if (DEBUG) Slog.d(TAG, "setKeyguardStoredQuality: user=" + userId + " quality=" + quality);
-        setLongUnchecked(LockPatternUtils.PASSWORD_TYPE_KEY, quality, userId);
+        mStorage.setLong(LockPatternUtils.PASSWORD_TYPE_KEY, quality, userId);
     }
 
     private int getKeyguardStoredQuality(int userId) {
-        return (int) getLongUnchecked(LockPatternUtils.PASSWORD_TYPE_KEY,
+        return (int) mStorage.getLong(LockPatternUtils.PASSWORD_TYPE_KEY,
                 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, userId);
     }
 
@@ -2493,13 +2445,6 @@
             SEPARATE_PROFILE_CHALLENGE_KEY
     };
 
-    private static final String[] SETTINGS_TO_BACKUP = new String[] {
-            Secure.LOCK_SCREEN_OWNER_INFO_ENABLED,
-            Secure.LOCK_SCREEN_OWNER_INFO,
-            Secure.LOCK_PATTERN_VISIBLE,
-            LockPatternUtils.LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS
-    };
-
     private class GateKeeperDiedRecipient implements IBinder.DeathRecipient {
         @Override
         public void binderDied() {
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsStorage.java b/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
index fec0189..81d07cc 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
@@ -18,8 +18,12 @@
 
 import static android.content.Context.USER_SERVICE;
 
+import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
+import static com.android.internal.widget.LockPatternUtils.USER_FRP;
+
 import android.annotation.Nullable;
 import android.app.admin.DevicePolicyManager;
+import android.app.backup.BackupManager;
 import android.content.ContentValues;
 import android.content.Context;
 import android.content.pm.UserInfo;
@@ -29,6 +33,8 @@
 import android.os.Environment;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.provider.Settings;
+import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.Slog;
 
@@ -87,6 +93,13 @@
 
     private static final Object DEFAULT = new Object();
 
+    private static final String[] SETTINGS_TO_BACKUP = new String[] {
+            Settings.Secure.LOCK_SCREEN_OWNER_INFO_ENABLED,
+            Settings.Secure.LOCK_SCREEN_OWNER_INFO,
+            Settings.Secure.LOCK_PATTERN_VISIBLE,
+            LockPatternUtils.LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS
+    };
+
     private final DatabaseHelper mOpenHelper;
     private final Context mContext;
     private final Cache mCache = new Cache();
@@ -136,10 +149,12 @@
         mOpenHelper.setCallback(callback);
     }
 
+    @VisibleForTesting(visibility = PACKAGE)
     public void writeKeyValue(String key, String value, int userId) {
         writeKeyValue(mOpenHelper.getWritableDatabase(), key, value, userId);
     }
 
+    @VisibleForTesting
     public void writeKeyValue(SQLiteDatabase db, String key, String value, int userId) {
         ContentValues cv = new ContentValues();
         cv.put(COLUMN_KEY, key);
@@ -159,6 +174,7 @@
 
     }
 
+    @VisibleForTesting
     public String readKeyValue(String key, String defaultValue, int userId) {
         int version;
         synchronized (mCache) {
@@ -184,6 +200,28 @@
         return result == DEFAULT ? defaultValue : (String) result;
     }
 
+    @VisibleForTesting
+    public void removeKey(String key, int userId) {
+        removeKey(mOpenHelper.getWritableDatabase(), key, userId);
+    }
+
+    private void removeKey(SQLiteDatabase db, String key, int userId) {
+        ContentValues cv = new ContentValues();
+        cv.put(COLUMN_KEY, key);
+        cv.put(COLUMN_USERID, userId);
+
+        db.beginTransaction();
+        try {
+            db.delete(TABLE, COLUMN_KEY + "=? AND " + COLUMN_USERID + "=?",
+                    new String[] {key, Integer.toString(userId)});
+            db.setTransactionSuccessful();
+            mCache.removeKey(key, userId);
+        } finally {
+            db.endTransaction();
+        }
+
+    }
+
     public void prefetchUser(int userId) {
         int version;
         synchronized (mCache) {
@@ -537,6 +575,55 @@
         }
     }
 
+    public void setBoolean(String key, boolean value, int userId) {
+        setString(key, value ? "1" : "0", userId);
+    }
+
+    public void setLong(String key, long value, int userId) {
+        setString(key, Long.toString(value), userId);
+    }
+
+    public void setInt(String key, int value, int userId) {
+        setString(key, Integer.toString(value), userId);
+    }
+
+    public void setString(String key, String value, int userId) {
+        Preconditions.checkArgument(userId != USER_FRP, "cannot store lock settings for FRP user");
+
+        writeKeyValue(key, value, userId);
+        if (ArrayUtils.contains(SETTINGS_TO_BACKUP, key)) {
+            BackupManager.dataChanged("com.android.providers.settings");
+        }
+    }
+
+    public boolean getBoolean(String key, boolean defaultValue, int userId) {
+        String value = getString(key, null, userId);
+        return TextUtils.isEmpty(value)
+                ? defaultValue : (value.equals("1") || value.equals("true"));
+    }
+
+    public long getLong(String key, long defaultValue, int userId) {
+        String value = getString(key, null, userId);
+        return TextUtils.isEmpty(value) ? defaultValue : Long.parseLong(value);
+    }
+
+    public int getInt(String key, int defaultValue, int userId) {
+        String value = getString(key, null, userId);
+        return TextUtils.isEmpty(value) ? defaultValue : Integer.parseInt(value);
+    }
+
+    public String getString(String key, String defaultValue, int userId) {
+        if (userId == USER_FRP) {
+            return null;
+        }
+
+        if (LockPatternUtils.LEGACY_LOCK_PATTERN_ENABLED.equals(key)) {
+            key = Settings.Secure.LOCK_PATTERN_ENABLED;
+        }
+
+        return readKeyValue(key, defaultValue, userId);
+    }
+
     @VisibleForTesting
     void closeDatabase() {
         mOpenHelper.close();
@@ -764,6 +851,10 @@
             putIfUnchanged(CacheKey.TYPE_KEY_VALUE, key, value, userId, version);
         }
 
+        void removeKey(String key, int userId) {
+            remove(CacheKey.TYPE_KEY_VALUE, key, userId);
+        }
+
         byte[] peekFile(String fileName) {
             return copyOf((byte[]) peek(CacheKey.TYPE_FILE, fileName, -1 /* userId */));
         }
@@ -788,6 +879,9 @@
             return contains(CacheKey.TYPE_FETCHED, "", userId);
         }
 
+        private synchronized void remove(int type, String key, int userId) {
+            mCache.remove(mCacheKey.set(type, key, userId));
+        }
 
         private synchronized void put(int type, String key, Object value, int userId) {
             // Create a new CachKey here because it may be saved in the map if the key is absent.