LockSettingsServicepublic 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. |
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 boolean | checkPassword(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 void | checkPasswordReadPermission(int userId)
mContext.enforceCallingOrSelfPermission(PERMISSION, "LockSettingsRead");
| public boolean | checkPattern(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 void | checkReadPermission(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 boolean | checkVoldPassword(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 void | checkWritePermission(int userId)
mContext.enforceCallingOrSelfPermission(PERMISSION, "LockSettingsWrite");
| public boolean | getBoolean(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 long | getLong(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.IMountService | getMountService()
final IBinder service = ServiceManager.getService("mount");
if (service != null) {
return IMountService.Stub.asInterface(service);
}
return null;
| public java.lang.String | getString(java.lang.String key, java.lang.String defaultValue, int userId)
checkReadPermission(key, userId);
return mStorage.readKeyValue(key, defaultValue, userId);
| public boolean | havePassword(int userId)
// Do we need a permissions check here?
return mStorage.hasPassword(userId);
| public boolean | havePattern(int userId)
// Do we need a permissions check here?
return mStorage.hasPattern(userId);
| private void | maybeUpdateKeystore(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 void | migrateOldData()
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 void | removeUser(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 void | setBoolean(java.lang.String key, boolean value, int userId)
checkWritePermission(userId);
setStringUnchecked(key, userId, value ? "1" : "0");
| public void | setLockPassword(java.lang.String password, int userId)
checkWritePermission(userId);
maybeUpdateKeystore(password, userId);
mStorage.writePasswordHash(mLockPatternUtils.passwordToHash(password, userId), userId);
| public void | setLockPattern(java.lang.String pattern, int userId)
checkWritePermission(userId);
maybeUpdateKeystore(pattern, userId);
final byte[] hash = LockPatternUtils.patternToHash(
LockPatternUtils.stringToPattern(pattern));
mStorage.writePatternHash(hash, userId);
| public void | setLong(java.lang.String key, long value, int userId)
checkWritePermission(userId);
setStringUnchecked(key, userId, Long.toString(value));
| public void | setString(java.lang.String key, java.lang.String value, int userId)
checkWritePermission(userId);
setStringUnchecked(key, userId, value);
| private void | setStringUnchecked(java.lang.String key, int userId, java.lang.String value)
mStorage.writeKeyValue(key, value, userId);
| public void | systemReady()
migrateOldData();
mStorage.prefetchUser(UserHandle.USER_OWNER);
|
|