LockSettingsService.java revision 450ce9fc8a1522819aec151433e6f509dfe60690
1/* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.server; 18 19import android.content.BroadcastReceiver; 20import android.content.ContentResolver; 21import android.content.Context; 22import android.content.Intent; 23import android.content.IntentFilter; 24import android.content.pm.PackageManager; 25import android.content.pm.UserInfo; 26 27import static android.Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE; 28import static android.content.Context.USER_SERVICE; 29import static android.Manifest.permission.READ_PROFILE; 30 31import android.database.sqlite.SQLiteDatabase; 32import android.os.Binder; 33import android.os.IBinder; 34import android.os.Process; 35import android.os.RemoteException; 36import android.os.storage.IMountService; 37import android.os.ServiceManager; 38import android.os.SystemProperties; 39import android.os.UserHandle; 40import android.os.UserManager; 41import android.provider.Settings; 42import android.provider.Settings.Secure; 43import android.provider.Settings.SettingNotFoundException; 44import android.security.KeyStore; 45import android.text.TextUtils; 46import android.util.Log; 47import android.util.Slog; 48 49import com.android.internal.widget.ILockSettings; 50import com.android.internal.widget.ILockSettingsObserver; 51import com.android.internal.widget.LockPatternUtils; 52import com.android.internal.widget.LockPatternUtilsCache; 53 54import java.util.ArrayList; 55import java.util.Arrays; 56import java.util.List; 57 58/** 59 * Keeps the lock pattern/password data and related settings for each user. 60 * Used by LockPatternUtils. Needs to be a service because Settings app also needs 61 * to be able to save lockscreen information for secondary users. 62 * @hide 63 */ 64public class LockSettingsService extends ILockSettings.Stub { 65 66 private static final String PERMISSION = ACCESS_KEYGUARD_SECURE_STORAGE; 67 68 private static final String SYSTEM_DEBUGGABLE = "ro.debuggable"; 69 70 71 private static final String TAG = "LockSettingsService"; 72 73 private final Context mContext; 74 75 private final LockSettingsStorage mStorage; 76 77 private LockPatternUtils mLockPatternUtils; 78 private boolean mFirstCallToVold; 79 80 private final ArrayList<LockSettingsObserver> mObservers = new ArrayList<>(); 81 82 public LockSettingsService(Context context) { 83 mContext = context; 84 // Open the database 85 86 mLockPatternUtils = new LockPatternUtils(context); 87 mFirstCallToVold = true; 88 89 IntentFilter filter = new IntentFilter(); 90 filter.addAction(Intent.ACTION_USER_ADDED); 91 mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null); 92 93 mStorage = new LockSettingsStorage(context, new LockSettingsStorage.Callback() { 94 @Override 95 public void initialize(SQLiteDatabase db) { 96 // Get the lockscreen default from a system property, if available 97 boolean lockScreenDisable = SystemProperties.getBoolean( 98 "ro.lockscreen.disable.default", false); 99 if (lockScreenDisable) { 100 mStorage.writeKeyValue(db, LockPatternUtils.DISABLE_LOCKSCREEN_KEY, "1", 0); 101 } 102 } 103 }); 104 } 105 106 private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { 107 @Override 108 public void onReceive(Context context, Intent intent) { 109 if (Intent.ACTION_USER_ADDED.equals(intent.getAction())) { 110 final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0); 111 final int userSysUid = UserHandle.getUid(userHandle, Process.SYSTEM_UID); 112 final KeyStore ks = KeyStore.getInstance(); 113 114 // Clear up keystore in case anything was left behind by previous users 115 ks.resetUid(userSysUid); 116 117 // If this user has a parent, sync with its keystore password 118 final UserManager um = (UserManager) mContext.getSystemService(USER_SERVICE); 119 final UserInfo parentInfo = um.getProfileParent(userHandle); 120 if (parentInfo != null) { 121 final int parentSysUid = UserHandle.getUid(parentInfo.id, Process.SYSTEM_UID); 122 ks.syncUid(parentSysUid, userSysUid); 123 } 124 } 125 } 126 }; 127 128 public void systemReady() { 129 migrateOldData(); 130 } 131 132 private void migrateOldData() { 133 try { 134 // These Settings moved before multi-user was enabled, so we only have to do it for the 135 // root user. 136 if (getString("migrated", null, 0) == null) { 137 final ContentResolver cr = mContext.getContentResolver(); 138 for (String validSetting : VALID_SETTINGS) { 139 String value = Settings.Secure.getString(cr, validSetting); 140 if (value != null) { 141 setString(validSetting, value, 0); 142 } 143 } 144 // No need to move the password / pattern files. They're already in the right place. 145 setString("migrated", "true", 0); 146 Slog.i(TAG, "Migrated lock settings to new location"); 147 } 148 149 // These Settings changed after multi-user was enabled, hence need to be moved per user. 150 if (getString("migrated_user_specific", null, 0) == null) { 151 final UserManager um = (UserManager) mContext.getSystemService(USER_SERVICE); 152 final ContentResolver cr = mContext.getContentResolver(); 153 List<UserInfo> users = um.getUsers(); 154 for (int user = 0; user < users.size(); user++) { 155 // Migrate owner info 156 final int userId = users.get(user).id; 157 final String OWNER_INFO = Secure.LOCK_SCREEN_OWNER_INFO; 158 String ownerInfo = Settings.Secure.getStringForUser(cr, OWNER_INFO, userId); 159 if (ownerInfo != null) { 160 setString(OWNER_INFO, ownerInfo, userId); 161 Settings.Secure.putStringForUser(cr, ownerInfo, "", userId); 162 } 163 164 // Migrate owner info enabled. Note there was a bug where older platforms only 165 // stored this value if the checkbox was toggled at least once. The code detects 166 // this case by handling the exception. 167 final String OWNER_INFO_ENABLED = Secure.LOCK_SCREEN_OWNER_INFO_ENABLED; 168 boolean enabled; 169 try { 170 int ivalue = Settings.Secure.getIntForUser(cr, OWNER_INFO_ENABLED, userId); 171 enabled = ivalue != 0; 172 setLong(OWNER_INFO_ENABLED, enabled ? 1 : 0, userId); 173 } catch (SettingNotFoundException e) { 174 // Setting was never stored. Store it if the string is not empty. 175 if (!TextUtils.isEmpty(ownerInfo)) { 176 setLong(OWNER_INFO_ENABLED, 1, userId); 177 } 178 } 179 Settings.Secure.putIntForUser(cr, OWNER_INFO_ENABLED, 0, userId); 180 } 181 // No need to move the password / pattern files. They're already in the right place. 182 setString("migrated_user_specific", "true", 0); 183 Slog.i(TAG, "Migrated per-user lock settings to new location"); 184 } 185 } catch (RemoteException re) { 186 Slog.e(TAG, "Unable to migrate old data", re); 187 } 188 } 189 190 private final void checkWritePermission(int userId) { 191 mContext.enforceCallingOrSelfPermission(PERMISSION, "LockSettingsWrite"); 192 } 193 194 private final void checkPasswordReadPermission(int userId) { 195 mContext.enforceCallingOrSelfPermission(PERMISSION, "LockSettingsRead"); 196 } 197 198 private final void checkReadPermission(String requestedKey, int userId) { 199 final int callingUid = Binder.getCallingUid(); 200 for (int i = 0; i < READ_PROFILE_PROTECTED_SETTINGS.length; i++) { 201 String key = READ_PROFILE_PROTECTED_SETTINGS[i]; 202 if (key.equals(requestedKey) && mContext.checkCallingOrSelfPermission(READ_PROFILE) 203 != PackageManager.PERMISSION_GRANTED) { 204 throw new SecurityException("uid=" + callingUid 205 + " needs permission " + READ_PROFILE + " to read " 206 + requestedKey + " for user " + userId); 207 } 208 } 209 } 210 211 @Override 212 public void setBoolean(String key, boolean value, int userId) throws RemoteException { 213 checkWritePermission(userId); 214 setStringUnchecked(key, userId, value ? "1" : "0"); 215 } 216 217 @Override 218 public void setLong(String key, long value, int userId) throws RemoteException { 219 checkWritePermission(userId); 220 setStringUnchecked(key, userId, Long.toString(value)); 221 } 222 223 @Override 224 public void setString(String key, String value, int userId) throws RemoteException { 225 checkWritePermission(userId); 226 setStringUnchecked(key, userId, value); 227 } 228 229 private void setStringUnchecked(String key, int userId, String value) { 230 mStorage.writeKeyValue(key, value, userId); 231 notifyObservers(key, userId); 232 } 233 234 @Override 235 public boolean getBoolean(String key, boolean defaultValue, int userId) throws RemoteException { 236 checkReadPermission(key, userId); 237 238 String value = mStorage.readKeyValue(key, null, userId); 239 return TextUtils.isEmpty(value) ? 240 defaultValue : (value.equals("1") || value.equals("true")); 241 } 242 243 @Override 244 public long getLong(String key, long defaultValue, int userId) throws RemoteException { 245 checkReadPermission(key, userId); 246 247 String value = mStorage.readKeyValue(key, null, userId); 248 return TextUtils.isEmpty(value) ? defaultValue : Long.parseLong(value); 249 } 250 251 @Override 252 public String getString(String key, String defaultValue, int userId) throws RemoteException { 253 checkReadPermission(key, userId); 254 255 return mStorage.readKeyValue(key, defaultValue, userId); 256 } 257 258 @Override 259 public void registerObserver(ILockSettingsObserver remote) throws RemoteException { 260 synchronized (mObservers) { 261 for (int i = 0; i < mObservers.size(); i++) { 262 if (mObservers.get(i).remote.asBinder() == remote.asBinder()) { 263 boolean isDebuggable = "1".equals(SystemProperties.get(SYSTEM_DEBUGGABLE, "0")); 264 if (isDebuggable) { 265 throw new IllegalStateException("Observer was already registered."); 266 } else { 267 Log.e(TAG, "Observer was already registered."); 268 return; 269 } 270 } 271 } 272 LockSettingsObserver o = new LockSettingsObserver(); 273 o.remote = remote; 274 o.remote.asBinder().linkToDeath(o, 0); 275 mObservers.add(o); 276 } 277 } 278 279 @Override 280 public void unregisterObserver(ILockSettingsObserver remote) throws RemoteException { 281 synchronized (mObservers) { 282 for (int i = 0; i < mObservers.size(); i++) { 283 if (mObservers.get(i).remote.asBinder() == remote.asBinder()) { 284 mObservers.remove(i); 285 return; 286 } 287 } 288 } 289 } 290 291 public void notifyObservers(String key, int userId) { 292 synchronized (mObservers) { 293 for (int i = 0; i < mObservers.size(); i++) { 294 try { 295 mObservers.get(i).remote.onLockSettingChanged(key, userId); 296 } catch (RemoteException e) { 297 // The stack trace is not really helpful here. 298 Log.e(TAG, "Failed to notify ILockSettingsObserver: " + e); 299 } 300 } 301 } 302 } 303 304 @Override 305 public boolean havePassword(int userId) throws RemoteException { 306 // Do we need a permissions check here? 307 308 return mStorage.hasPassword(userId); 309 } 310 311 @Override 312 public boolean havePattern(int userId) throws RemoteException { 313 // Do we need a permissions check here? 314 315 return mStorage.hasPattern(userId); 316 } 317 318 private void maybeUpdateKeystore(String password, int userHandle) { 319 final UserManager um = (UserManager) mContext.getSystemService(USER_SERVICE); 320 final KeyStore ks = KeyStore.getInstance(); 321 322 final List<UserInfo> profiles = um.getProfiles(userHandle); 323 boolean shouldReset = TextUtils.isEmpty(password); 324 325 // For historical reasons, don't wipe a non-empty keystore if we have a single user with a 326 // single profile. 327 if (userHandle == UserHandle.USER_OWNER && profiles.size() == 1) { 328 if (!ks.isEmpty()) { 329 shouldReset = false; 330 } 331 } 332 333 for (UserInfo pi : profiles) { 334 final int profileUid = UserHandle.getUid(pi.id, Process.SYSTEM_UID); 335 if (shouldReset) { 336 ks.resetUid(profileUid); 337 } else { 338 ks.passwordUid(password, profileUid); 339 } 340 } 341 } 342 343 @Override 344 public void setLockPattern(String pattern, int userId) throws RemoteException { 345 checkWritePermission(userId); 346 347 maybeUpdateKeystore(pattern, userId); 348 349 final byte[] hash = LockPatternUtils.patternToHash( 350 LockPatternUtils.stringToPattern(pattern)); 351 mStorage.writePatternHash(hash, userId); 352 notifyObservers(LockPatternUtilsCache.HAS_LOCK_PATTERN_CACHE_KEY, userId); 353 } 354 355 @Override 356 public void setLockPassword(String password, int userId) throws RemoteException { 357 checkWritePermission(userId); 358 359 maybeUpdateKeystore(password, userId); 360 361 mStorage.writePasswordHash(mLockPatternUtils.passwordToHash(password, userId), userId); 362 notifyObservers(LockPatternUtilsCache.HAS_LOCK_PASSWORD_CACHE_KEY, userId); 363 } 364 365 @Override 366 public boolean checkPattern(String pattern, int userId) throws RemoteException { 367 checkPasswordReadPermission(userId); 368 byte[] hash = LockPatternUtils.patternToHash(LockPatternUtils.stringToPattern(pattern)); 369 byte[] storedHash = mStorage.readPatternHash(userId); 370 371 if (storedHash == null) { 372 return true; 373 } 374 375 boolean matched = Arrays.equals(hash, storedHash); 376 if (matched && !TextUtils.isEmpty(pattern)) { 377 maybeUpdateKeystore(pattern, userId); 378 } 379 return matched; 380 } 381 382 @Override 383 public boolean checkPassword(String password, int userId) throws RemoteException { 384 checkPasswordReadPermission(userId); 385 386 byte[] hash = mLockPatternUtils.passwordToHash(password, userId); 387 byte[] storedHash = mStorage.readPasswordHash(userId); 388 389 if (storedHash == null) { 390 return true; 391 } 392 393 boolean matched = Arrays.equals(hash, storedHash); 394 if (matched && !TextUtils.isEmpty(password)) { 395 maybeUpdateKeystore(password, userId); 396 } 397 return matched; 398 } 399 400 @Override 401 public boolean checkVoldPassword(int userId) throws RemoteException { 402 if (!mFirstCallToVold) { 403 return false; 404 } 405 mFirstCallToVold = false; 406 407 checkPasswordReadPermission(userId); 408 409 // There's no guarantee that this will safely connect, but if it fails 410 // we will simply show the lock screen when we shouldn't, so relatively 411 // benign. There is an outside chance something nasty would happen if 412 // this service restarted before vold stales out the password in this 413 // case. The nastiness is limited to not showing the lock screen when 414 // we should, within the first minute of decrypting the phone if this 415 // service can't connect to vold, it restarts, and then the new instance 416 // does successfully connect. 417 final IMountService service = getMountService(); 418 String password = service.getPassword(); 419 service.clearPassword(); 420 if (password == null) { 421 return false; 422 } 423 424 try { 425 if (mLockPatternUtils.isLockPatternEnabled()) { 426 if (checkPattern(password, userId)) { 427 return true; 428 } 429 } 430 } catch (Exception e) { 431 } 432 433 try { 434 if (mLockPatternUtils.isLockPasswordEnabled()) { 435 if (checkPassword(password, userId)) { 436 return true; 437 } 438 } 439 } catch (Exception e) { 440 } 441 442 return false; 443 } 444 445 @Override 446 public void removeUser(int userId) { 447 checkWritePermission(userId); 448 449 mStorage.removeUser(userId); 450 notifyObservers(null /* key */, userId); 451 452 final KeyStore ks = KeyStore.getInstance(); 453 final int userUid = UserHandle.getUid(userId, Process.SYSTEM_UID); 454 ks.resetUid(userUid); 455 } 456 457 private static final String[] VALID_SETTINGS = new String[] { 458 LockPatternUtils.LOCKOUT_PERMANENT_KEY, 459 LockPatternUtils.LOCKOUT_ATTEMPT_DEADLINE, 460 LockPatternUtils.PATTERN_EVER_CHOSEN_KEY, 461 LockPatternUtils.PASSWORD_TYPE_KEY, 462 LockPatternUtils.PASSWORD_TYPE_ALTERNATE_KEY, 463 LockPatternUtils.LOCK_PASSWORD_SALT_KEY, 464 LockPatternUtils.DISABLE_LOCKSCREEN_KEY, 465 LockPatternUtils.LOCKSCREEN_OPTIONS, 466 LockPatternUtils.LOCKSCREEN_BIOMETRIC_WEAK_FALLBACK, 467 LockPatternUtils.BIOMETRIC_WEAK_EVER_CHOSEN_KEY, 468 LockPatternUtils.LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS, 469 LockPatternUtils.PASSWORD_HISTORY_KEY, 470 Secure.LOCK_PATTERN_ENABLED, 471 Secure.LOCK_BIOMETRIC_WEAK_FLAGS, 472 Secure.LOCK_PATTERN_VISIBLE, 473 Secure.LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED 474 }; 475 476 // These are protected with a read permission 477 private static final String[] READ_PROFILE_PROTECTED_SETTINGS = new String[] { 478 Secure.LOCK_SCREEN_OWNER_INFO_ENABLED, 479 Secure.LOCK_SCREEN_OWNER_INFO 480 }; 481 482 private IMountService getMountService() { 483 final IBinder service = ServiceManager.getService("mount"); 484 if (service != null) { 485 return IMountService.Stub.asInterface(service); 486 } 487 return null; 488 } 489 490 private class LockSettingsObserver implements DeathRecipient { 491 ILockSettingsObserver remote; 492 493 @Override 494 public void binderDied() { 495 mObservers.remove(this); 496 } 497 } 498} 499