FileDocCategorySizeDatePackage
LockSettingsService.javaAPI DocAndroid 5.1 API16997Thu Mar 12 22:22:42 GMT 2015com.android.server

LockSettingsService

public class LockSettingsService extends ILockSettings.Stub
Keeps the lock pattern/password data and related settings for each user. Used by LockPatternUtils. Needs to be a service because Settings app also needs to be able to save lockscreen information for secondary users.
hide

Fields Summary
private static final String
PERMISSION
private static final String
TAG
private final android.content.Context
mContext
private final LockSettingsStorage
mStorage
private com.android.internal.widget.LockPatternUtils
mLockPatternUtils
private boolean
mFirstCallToVold
private final android.content.BroadcastReceiver
mBroadcastReceiver
private static final String[]
VALID_SETTINGS
private static final String[]
READ_PROFILE_PROTECTED_SETTINGS
Constructors Summary
public LockSettingsService(android.content.Context context)


       
        mContext = context;
        // Open the database

        mLockPatternUtils = new LockPatternUtils(context);
        mFirstCallToVold = true;

        IntentFilter filter = new IntentFilter();
        filter.addAction(Intent.ACTION_USER_ADDED);
        filter.addAction(Intent.ACTION_USER_STARTING);
        mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null);

        mStorage = new LockSettingsStorage(context, new LockSettingsStorage.Callback() {
            @Override
            public void initialize(SQLiteDatabase db) {
                // Get the lockscreen default from a system property, if available
                boolean lockScreenDisable = SystemProperties.getBoolean(
                        "ro.lockscreen.disable.default", false);
                if (lockScreenDisable) {
                    mStorage.writeKeyValue(db, LockPatternUtils.DISABLE_LOCKSCREEN_KEY, "1", 0);
                }
            }
        });
    
Methods Summary
public booleancheckPassword(java.lang.String password, int userId)

        checkPasswordReadPermission(userId);

        byte[] hash = mLockPatternUtils.passwordToHash(password, userId);
        byte[] storedHash = mStorage.readPasswordHash(userId);

        if (storedHash == null) {
            return true;
        }

        boolean matched = Arrays.equals(hash, storedHash);
        if (matched && !TextUtils.isEmpty(password)) {
            maybeUpdateKeystore(password, userId);
        }
        return matched;
    
private final voidcheckPasswordReadPermission(int userId)

        mContext.enforceCallingOrSelfPermission(PERMISSION, "LockSettingsRead");
    
public booleancheckPattern(java.lang.String pattern, int userId)

        checkPasswordReadPermission(userId);
        byte[] hash = LockPatternUtils.patternToHash(LockPatternUtils.stringToPattern(pattern));
        byte[] storedHash = mStorage.readPatternHash(userId);

        if (storedHash == null) {
            return true;
        }

        boolean matched = Arrays.equals(hash, storedHash);
        if (matched && !TextUtils.isEmpty(pattern)) {
            maybeUpdateKeystore(pattern, userId);
        }
        return matched;
    
private final voidcheckReadPermission(java.lang.String requestedKey, int userId)

        final int callingUid = Binder.getCallingUid();
        for (int i = 0; i < READ_PROFILE_PROTECTED_SETTINGS.length; i++) {
            String key = READ_PROFILE_PROTECTED_SETTINGS[i];
            if (key.equals(requestedKey) && mContext.checkCallingOrSelfPermission(READ_PROFILE)
                    != PackageManager.PERMISSION_GRANTED) {
                throw new SecurityException("uid=" + callingUid
                        + " needs permission " + READ_PROFILE + " to read "
                        + requestedKey + " for user " + userId);
            }
        }
    
public booleancheckVoldPassword(int userId)

        if (!mFirstCallToVold) {
            return false;
        }
        mFirstCallToVold = false;

        checkPasswordReadPermission(userId);

        // There's no guarantee that this will safely connect, but if it fails
        // we will simply show the lock screen when we shouldn't, so relatively
        // benign. There is an outside chance something nasty would happen if
        // this service restarted before vold stales out the password in this
        // case. The nastiness is limited to not showing the lock screen when
        // we should, within the first minute of decrypting the phone if this
        // service can't connect to vold, it restarts, and then the new instance
        // does successfully connect.
        final IMountService service = getMountService();
        String password = service.getPassword();
        service.clearPassword();
        if (password == null) {
            return false;
        }

        try {
            if (mLockPatternUtils.isLockPatternEnabled()) {
                if (checkPattern(password, userId)) {
                    return true;
                }
            }
        } catch (Exception e) {
        }

        try {
            if (mLockPatternUtils.isLockPasswordEnabled()) {
                if (checkPassword(password, userId)) {
                    return true;
                }
            }
        } catch (Exception e) {
        }

        return false;
    
private final voidcheckWritePermission(int userId)

        mContext.enforceCallingOrSelfPermission(PERMISSION, "LockSettingsWrite");
    
public booleangetBoolean(java.lang.String key, boolean defaultValue, int userId)

        checkReadPermission(key, userId);

        String value = mStorage.readKeyValue(key, null, userId);
        return TextUtils.isEmpty(value) ?
                defaultValue : (value.equals("1") || value.equals("true"));
    
public longgetLong(java.lang.String key, long defaultValue, int userId)

        checkReadPermission(key, userId);

        String value = mStorage.readKeyValue(key, null, userId);
        return TextUtils.isEmpty(value) ? defaultValue : Long.parseLong(value);
    
private android.os.storage.IMountServicegetMountService()


       
        final IBinder service = ServiceManager.getService("mount");
        if (service != null) {
            return IMountService.Stub.asInterface(service);
        }
        return null;
    
public java.lang.StringgetString(java.lang.String key, java.lang.String defaultValue, int userId)

        checkReadPermission(key, userId);

        return mStorage.readKeyValue(key, defaultValue, userId);
    
public booleanhavePassword(int userId)

        // Do we need a permissions check here?

        return mStorage.hasPassword(userId);
    
public booleanhavePattern(int userId)

        // Do we need a permissions check here?

        return mStorage.hasPattern(userId);
    
private voidmaybeUpdateKeystore(java.lang.String password, int userHandle)

        final UserManager um = (UserManager) mContext.getSystemService(USER_SERVICE);
        final KeyStore ks = KeyStore.getInstance();

        final List<UserInfo> profiles = um.getProfiles(userHandle);
        boolean shouldReset = TextUtils.isEmpty(password);

        // For historical reasons, don't wipe a non-empty keystore if we have a single user with a
        // single profile.
        if (userHandle == UserHandle.USER_OWNER && profiles.size() == 1) {
            if (!ks.isEmpty()) {
                shouldReset = false;
            }
        }

        for (UserInfo pi : profiles) {
            final int profileUid = UserHandle.getUid(pi.id, Process.SYSTEM_UID);
            if (shouldReset) {
                ks.resetUid(profileUid);
            } else {
                ks.passwordUid(password, profileUid);
            }
        }
    
private voidmigrateOldData()

        try {
            // These Settings moved before multi-user was enabled, so we only have to do it for the
            // root user.
            if (getString("migrated", null, 0) == null) {
                final ContentResolver cr = mContext.getContentResolver();
                for (String validSetting : VALID_SETTINGS) {
                    String value = Settings.Secure.getString(cr, validSetting);
                    if (value != null) {
                        setString(validSetting, value, 0);
                    }
                }
                // No need to move the password / pattern files. They're already in the right place.
                setString("migrated", "true", 0);
                Slog.i(TAG, "Migrated lock settings to new location");
            }

            // These Settings changed after multi-user was enabled, hence need to be moved per user.
            if (getString("migrated_user_specific", null, 0) == null) {
                final UserManager um = (UserManager) mContext.getSystemService(USER_SERVICE);
                final ContentResolver cr = mContext.getContentResolver();
                List<UserInfo> users = um.getUsers();
                for (int user = 0; user < users.size(); user++) {
                    // Migrate owner info
                    final int userId = users.get(user).id;
                    final String OWNER_INFO = Secure.LOCK_SCREEN_OWNER_INFO;
                    String ownerInfo = Settings.Secure.getStringForUser(cr, OWNER_INFO, userId);
                    if (ownerInfo != null) {
                        setString(OWNER_INFO, ownerInfo, userId);
                        Settings.Secure.putStringForUser(cr, ownerInfo, "", userId);
                    }

                    // Migrate owner info enabled.  Note there was a bug where older platforms only
                    // stored this value if the checkbox was toggled at least once. The code detects
                    // this case by handling the exception.
                    final String OWNER_INFO_ENABLED = Secure.LOCK_SCREEN_OWNER_INFO_ENABLED;
                    boolean enabled;
                    try {
                        int ivalue = Settings.Secure.getIntForUser(cr, OWNER_INFO_ENABLED, userId);
                        enabled = ivalue != 0;
                        setLong(OWNER_INFO_ENABLED, enabled ? 1 : 0, userId);
                    } catch (SettingNotFoundException e) {
                        // Setting was never stored. Store it if the string is not empty.
                        if (!TextUtils.isEmpty(ownerInfo)) {
                            setLong(OWNER_INFO_ENABLED, 1, userId);
                        }
                    }
                    Settings.Secure.putIntForUser(cr, OWNER_INFO_ENABLED, 0, userId);
                }
                // No need to move the password / pattern files. They're already in the right place.
                setString("migrated_user_specific", "true", 0);
                Slog.i(TAG, "Migrated per-user lock settings to new location");
            }
        } catch (RemoteException re) {
            Slog.e(TAG, "Unable to migrate old data", re);
        }
    
public voidremoveUser(int userId)

        checkWritePermission(userId);

        mStorage.removeUser(userId);

        final KeyStore ks = KeyStore.getInstance();
        final int userUid = UserHandle.getUid(userId, Process.SYSTEM_UID);
        ks.resetUid(userUid);
    
public voidsetBoolean(java.lang.String key, boolean value, int userId)

        checkWritePermission(userId);
        setStringUnchecked(key, userId, value ? "1" : "0");
    
public voidsetLockPassword(java.lang.String password, int userId)

        checkWritePermission(userId);

        maybeUpdateKeystore(password, userId);

        mStorage.writePasswordHash(mLockPatternUtils.passwordToHash(password, userId), userId);
    
public voidsetLockPattern(java.lang.String pattern, int userId)

        checkWritePermission(userId);

        maybeUpdateKeystore(pattern, userId);

        final byte[] hash = LockPatternUtils.patternToHash(
                LockPatternUtils.stringToPattern(pattern));
        mStorage.writePatternHash(hash, userId);
    
public voidsetLong(java.lang.String key, long value, int userId)

        checkWritePermission(userId);
        setStringUnchecked(key, userId, Long.toString(value));
    
public voidsetString(java.lang.String key, java.lang.String value, int userId)

        checkWritePermission(userId);
        setStringUnchecked(key, userId, value);
    
private voidsetStringUnchecked(java.lang.String key, int userId, java.lang.String value)

        mStorage.writeKeyValue(key, value, userId);
    
public voidsystemReady()


       
        migrateOldData();
        mStorage.prefetchUser(UserHandle.USER_OWNER);