Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3e5a0605 authored by Kenny Root's avatar Kenny Root Committed by Android (Google) Code Review
Browse files

Merge changes Ief1cac19,Ibc9236a1 into rvc-dev

* changes:
  Resume-on-Reboot: add storage for armed status
  LockSettingsService: move database storage
parents ae5a3ee6 ea134edc
Loading
Loading
Loading
Loading
+14 −69
Original line number Diff line number Diff line
@@ -50,7 +50,6 @@ import android.app.admin.DevicePolicyManager;
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.GuardedBy;
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 @@ public class LockSettingsService extends ILockSettings.Stub {
        // 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 @@ public class LockSettingsService extends ILockSettings.Stub {
            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 @@ public class LockSettingsService extends ILockSettings.Stub {

    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 @@ public class LockSettingsService extends ILockSettings.Stub {
    @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);
        if (Settings.Secure.LOCK_PATTERN_ENABLED.equals(key)) {
            return getCredentialTypeInternal(userId) == CREDENTIAL_TYPE_PATTERN;
        }

    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"));
        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 @@ public class LockSettingsService extends ILockSettings.Stub {
            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() {
+94 −0
Original line number Diff line number Diff line
@@ -18,8 +18,12 @@ package com.android.server.locksettings;

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.database.sqlite.SQLiteOpenHelper;
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 @@ class LockSettingsStorage {

    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 @@ class LockSettingsStorage {
        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 @@ class LockSettingsStorage {

    }

    @VisibleForTesting
    public String readKeyValue(String key, String defaultValue, int userId) {
        int version;
        synchronized (mCache) {
@@ -184,6 +200,28 @@ class LockSettingsStorage {
        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 @@ class LockSettingsStorage {
        }
    }

    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 @@ class LockSettingsStorage {
            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 @@ class LockSettingsStorage {
            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.
+56 −4
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

package com.android.server.locksettings;

import static android.os.UserHandle.USER_SYSTEM;

import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.content.Context;
@@ -24,6 +26,7 @@ import android.hardware.rebootescrow.IRebootEscrow;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserManager;
import android.provider.Settings;
import android.util.Slog;

import com.android.internal.annotations.GuardedBy;
@@ -39,6 +42,26 @@ import java.util.NoSuchElementException;
class RebootEscrowManager {
    private static final String TAG = "RebootEscrowManager";

    /**
     * Used in the database storage to indicate the boot count at which the reboot escrow was
     * previously armed.
     */
    @VisibleForTesting
    public static final String REBOOT_ESCROW_ARMED_KEY = "reboot_escrow_armed_count";

    /**
     * Number of boots until we consider the escrow data to be stale for the purposes of metrics.
     * <p>
     * If the delta between the current boot number and the boot number stored when the mechanism
     * was armed is under this number and the escrow mechanism fails, we report it as a failure of
     * the mechanism.
     * <p>
     * If the delta over this number and escrow fails, we will not report the metric as failed
     * since there most likely was some other issue if the device rebooted several times before
     * getting to the escrow restore code.
     */
    private static final int BOOT_COUNT_TOLERANCE = 5;

    /**
     * Used to track when the reboot escrow is wanted. Should stay true once escrow is requested
     * unless clearRebootEscrow is called. This will allow all the active users to be unlocked
@@ -74,6 +97,7 @@ class RebootEscrowManager {

    interface Callbacks {
        boolean isUserSecure(int userId);

        void onRebootEscrowRestored(byte spVersion, byte[] syntheticPassword, int userId);
    }

@@ -92,7 +116,8 @@ class RebootEscrowManager {
            return (UserManager) mContext.getSystemService(Context.USER_SERVICE);
        }

        public @Nullable IRebootEscrow getRebootEscrow() {
        @Nullable
        public IRebootEscrow getRebootEscrow() {
            try {
                return IRebootEscrow.Stub.asInterface(ServiceManager.getService(
                        "android.hardware.rebootescrow.IRebootEscrow/default"));
@@ -101,6 +126,15 @@ class RebootEscrowManager {
            }
            return null;
        }

        public int getBootCount() {
            return Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.BOOT_COUNT,
                    0);
        }

        public void reportMetric(boolean success) {
            FrameworkStatsLog.write(FrameworkStatsLog.REBOOT_ESCROW_RECOVERY_REPORTED, success);
        }
    }

    RebootEscrowManager(Context context, Callbacks callbacks, LockSettingsStorage storage) {
@@ -135,7 +169,7 @@ class RebootEscrowManager {
            for (UserInfo user : users) {
                mStorage.removeRebootEscrow(user.id);
            }
            FrameworkStatsLog.write(FrameworkStatsLog.REBOOT_ESCROW_RECOVERY_REPORTED, false);
            onEscrowRestoreComplete(false);
            return;
        }

@@ -143,8 +177,19 @@ class RebootEscrowManager {
        for (UserInfo user : rebootEscrowUsers) {
            allUsersUnlocked &= restoreRebootEscrowForUser(user.id, escrowKey);
        }
        FrameworkStatsLog.write(FrameworkStatsLog.REBOOT_ESCROW_RECOVERY_REPORTED,
                allUsersUnlocked);
        onEscrowRestoreComplete(allUsersUnlocked);
    }

    private void onEscrowRestoreComplete(boolean success) {
        int previousBootCount = mStorage.getInt(REBOOT_ESCROW_ARMED_KEY, 0, USER_SYSTEM);
        mStorage.removeKey(REBOOT_ESCROW_ARMED_KEY, USER_SYSTEM);

        int bootCountDelta = mInjector.getBootCount() - previousBootCount;
        if (bootCountDelta > BOOT_COUNT_TOLERANCE) {
            return;
        }

        mInjector.reportMetric(success);
    }

    private RebootEscrowKey getAndClearRebootEscrowKey() {
@@ -267,6 +312,8 @@ class RebootEscrowManager {
            return;
        }

        mStorage.removeKey(REBOOT_ESCROW_ARMED_KEY, USER_SYSTEM);

        try {
            rebootEscrow.storeKey(new byte[32]);
        } catch (RemoteException e) {
@@ -308,6 +355,11 @@ class RebootEscrowManager {
        } catch (RemoteException e) {
            Slog.e(TAG, "Failed escrow secret to RebootEscrow HAL", e);
        }

        if (armedRebootEscrow) {
            mStorage.setInt(REBOOT_ESCROW_ARMED_KEY, mInjector.getBootCount(), USER_SYSTEM);
        }

        return armedRebootEscrow;
    }

+145 −4

File changed.

Preview size limit exceeded, changes collapsed.