Home | History | Annotate | Download | only in server
      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 
     17 package com.android.server;
     18 
     19 import android.app.admin.DevicePolicyManager;
     20 import android.app.backup.BackupManager;
     21 import android.content.BroadcastReceiver;
     22 import android.content.ContentResolver;
     23 import android.content.Context;
     24 import android.content.Intent;
     25 import android.content.IntentFilter;
     26 import android.content.pm.PackageManager;
     27 import android.content.pm.UserInfo;
     28 import static android.Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE;
     29 import static android.content.Context.USER_SERVICE;
     30 import static android.Manifest.permission.READ_CONTACTS;
     31 import android.database.sqlite.SQLiteDatabase;
     32 import android.os.Binder;
     33 import android.os.IBinder;
     34 import android.os.RemoteException;
     35 import android.os.storage.IMountService;
     36 import android.os.ServiceManager;
     37 import android.os.SystemProperties;
     38 import android.os.UserHandle;
     39 import android.os.UserManager;
     40 import android.provider.Settings;
     41 import android.provider.Settings.Secure;
     42 import android.provider.Settings.SettingNotFoundException;
     43 import android.security.KeyStore;
     44 import android.service.gatekeeper.GateKeeperResponse;
     45 import android.service.gatekeeper.IGateKeeperService;
     46 import android.text.TextUtils;
     47 import android.util.Slog;
     48 
     49 import com.android.internal.util.ArrayUtils;
     50 import com.android.internal.widget.ILockSettings;
     51 import com.android.internal.widget.LockPatternUtils;
     52 import com.android.internal.widget.VerifyCredentialResponse;
     53 import com.android.server.LockSettingsStorage.CredentialHash;
     54 
     55 import java.util.Arrays;
     56 import 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  */
     64 public class LockSettingsService extends ILockSettings.Stub {
     65 
     66     private static final String PERMISSION = ACCESS_KEYGUARD_SECURE_STORAGE;
     67 
     68     private static final String TAG = "LockSettingsService";
     69 
     70     private final Context mContext;
     71 
     72     private final LockSettingsStorage mStorage;
     73 
     74     private LockPatternUtils mLockPatternUtils;
     75     private boolean mFirstCallToVold;
     76     private IGateKeeperService mGateKeeperService;
     77 
     78     private interface CredentialUtil {
     79         void setCredential(String credential, String savedCredential, int userId)
     80                 throws RemoteException;
     81         byte[] toHash(String credential, int userId);
     82         String adjustForKeystore(String credential);
     83     }
     84 
     85     public LockSettingsService(Context context) {
     86         mContext = context;
     87         // Open the database
     88 
     89         mLockPatternUtils = new LockPatternUtils(context);
     90         mFirstCallToVold = true;
     91 
     92         IntentFilter filter = new IntentFilter();
     93         filter.addAction(Intent.ACTION_USER_ADDED);
     94         filter.addAction(Intent.ACTION_USER_STARTING);
     95         filter.addAction(Intent.ACTION_USER_REMOVED);
     96         mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null);
     97 
     98         mStorage = new LockSettingsStorage(context, new LockSettingsStorage.Callback() {
     99             @Override
    100             public void initialize(SQLiteDatabase db) {
    101                 // Get the lockscreen default from a system property, if available
    102                 boolean lockScreenDisable = SystemProperties.getBoolean(
    103                         "ro.lockscreen.disable.default", false);
    104                 if (lockScreenDisable) {
    105                     mStorage.writeKeyValue(db, LockPatternUtils.DISABLE_LOCKSCREEN_KEY, "1", 0);
    106                 }
    107             }
    108         });
    109     }
    110 
    111     private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
    112         @Override
    113         public void onReceive(Context context, Intent intent) {
    114             if (Intent.ACTION_USER_ADDED.equals(intent.getAction())) {
    115                 // Notify keystore that a new user was added.
    116                 final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
    117                 final KeyStore ks = KeyStore.getInstance();
    118                 final UserManager um = (UserManager) mContext.getSystemService(USER_SERVICE);
    119                 final UserInfo parentInfo = um.getProfileParent(userHandle);
    120                 final int parentHandle = parentInfo != null ? parentInfo.id : -1;
    121                 ks.onUserAdded(userHandle, parentHandle);
    122             } else if (Intent.ACTION_USER_STARTING.equals(intent.getAction())) {
    123                 final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
    124                 mStorage.prefetchUser(userHandle);
    125             } else if (Intent.ACTION_USER_REMOVED.equals(intent.getAction())) {
    126                 final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
    127                 if (userHandle > 0) {
    128                     removeUser(userHandle);
    129                 }
    130             }
    131         }
    132     };
    133 
    134     public void systemReady() {
    135         migrateOldData();
    136         try {
    137             getGateKeeperService();
    138         } catch (RemoteException e) {
    139             Slog.e(TAG, "Failure retrieving IGateKeeperService", e);
    140         }
    141         mStorage.prefetchUser(UserHandle.USER_OWNER);
    142     }
    143 
    144     private void migrateOldData() {
    145         try {
    146             // These Settings moved before multi-user was enabled, so we only have to do it for the
    147             // root user.
    148             if (getString("migrated", null, 0) == null) {
    149                 final ContentResolver cr = mContext.getContentResolver();
    150                 for (String validSetting : VALID_SETTINGS) {
    151                     String value = Settings.Secure.getString(cr, validSetting);
    152                     if (value != null) {
    153                         setString(validSetting, value, 0);
    154                     }
    155                 }
    156                 // No need to move the password / pattern files. They're already in the right place.
    157                 setString("migrated", "true", 0);
    158                 Slog.i(TAG, "Migrated lock settings to new location");
    159             }
    160 
    161             // These Settings changed after multi-user was enabled, hence need to be moved per user.
    162             if (getString("migrated_user_specific", null, 0) == null) {
    163                 final UserManager um = (UserManager) mContext.getSystemService(USER_SERVICE);
    164                 final ContentResolver cr = mContext.getContentResolver();
    165                 List<UserInfo> users = um.getUsers();
    166                 for (int user = 0; user < users.size(); user++) {
    167                     // Migrate owner info
    168                     final int userId = users.get(user).id;
    169                     final String OWNER_INFO = Secure.LOCK_SCREEN_OWNER_INFO;
    170                     String ownerInfo = Settings.Secure.getStringForUser(cr, OWNER_INFO, userId);
    171                     if (ownerInfo != null) {
    172                         setString(OWNER_INFO, ownerInfo, userId);
    173                         Settings.Secure.putStringForUser(cr, ownerInfo, "", userId);
    174                     }
    175 
    176                     // Migrate owner info enabled.  Note there was a bug where older platforms only
    177                     // stored this value if the checkbox was toggled at least once. The code detects
    178                     // this case by handling the exception.
    179                     final String OWNER_INFO_ENABLED = Secure.LOCK_SCREEN_OWNER_INFO_ENABLED;
    180                     boolean enabled;
    181                     try {
    182                         int ivalue = Settings.Secure.getIntForUser(cr, OWNER_INFO_ENABLED, userId);
    183                         enabled = ivalue != 0;
    184                         setLong(OWNER_INFO_ENABLED, enabled ? 1 : 0, userId);
    185                     } catch (SettingNotFoundException e) {
    186                         // Setting was never stored. Store it if the string is not empty.
    187                         if (!TextUtils.isEmpty(ownerInfo)) {
    188                             setLong(OWNER_INFO_ENABLED, 1, userId);
    189                         }
    190                     }
    191                     Settings.Secure.putIntForUser(cr, OWNER_INFO_ENABLED, 0, userId);
    192                 }
    193                 // No need to move the password / pattern files. They're already in the right place.
    194                 setString("migrated_user_specific", "true", 0);
    195                 Slog.i(TAG, "Migrated per-user lock settings to new location");
    196             }
    197 
    198             // Migrates biometric weak such that the fallback mechanism becomes the primary.
    199             if (getString("migrated_biometric_weak", null, 0) == null) {
    200                 final UserManager um = (UserManager) mContext.getSystemService(USER_SERVICE);
    201                 List<UserInfo> users = um.getUsers();
    202                 for (int i = 0; i < users.size(); i++) {
    203                     int userId = users.get(i).id;
    204                     long type = getLong(LockPatternUtils.PASSWORD_TYPE_KEY,
    205                             DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
    206                             userId);
    207                     long alternateType = getLong(LockPatternUtils.PASSWORD_TYPE_ALTERNATE_KEY,
    208                             DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
    209                             userId);
    210                     if (type == DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK) {
    211                         setLong(LockPatternUtils.PASSWORD_TYPE_KEY,
    212                                 alternateType,
    213                                 userId);
    214                     }
    215                     setLong(LockPatternUtils.PASSWORD_TYPE_ALTERNATE_KEY,
    216                             DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
    217                             userId);
    218                 }
    219                 setString("migrated_biometric_weak", "true", 0);
    220                 Slog.i(TAG, "Migrated biometric weak to use the fallback instead");
    221             }
    222 
    223             // Migrates lockscreen.disabled. Prior to M, the flag was ignored when more than one
    224             // user was present on the system, so if we're upgrading to M and there is more than one
    225             // user we disable the flag to remain consistent.
    226             if (getString("migrated_lockscreen_disabled", null, 0) == null) {
    227                 final UserManager um = (UserManager) mContext.getSystemService(USER_SERVICE);
    228 
    229                 final List<UserInfo> users = um.getUsers();
    230                 final int userCount = users.size();
    231                 int switchableUsers = 0;
    232                 for (int i = 0; i < userCount; i++) {
    233                     if (users.get(i).supportsSwitchTo()) {
    234                         switchableUsers++;
    235                     }
    236                 }
    237 
    238                 if (switchableUsers > 1) {
    239                     for (int i = 0; i < userCount; i++) {
    240                         int id = users.get(i).id;
    241 
    242                         if (getBoolean(LockPatternUtils.DISABLE_LOCKSCREEN_KEY, false, id)) {
    243                             setBoolean(LockPatternUtils.DISABLE_LOCKSCREEN_KEY, false, id);
    244                         }
    245                     }
    246                 }
    247 
    248                 setString("migrated_lockscreen_disabled", "true", 0);
    249                 Slog.i(TAG, "Migrated lockscreen disabled flag");
    250             }
    251         } catch (RemoteException re) {
    252             Slog.e(TAG, "Unable to migrate old data", re);
    253         }
    254     }
    255 
    256     private final void checkWritePermission(int userId) {
    257         mContext.enforceCallingOrSelfPermission(PERMISSION, "LockSettingsWrite");
    258     }
    259 
    260     private final void checkPasswordReadPermission(int userId) {
    261         mContext.enforceCallingOrSelfPermission(PERMISSION, "LockSettingsRead");
    262     }
    263 
    264     private final void checkReadPermission(String requestedKey, int userId) {
    265         final int callingUid = Binder.getCallingUid();
    266 
    267         for (int i = 0; i < READ_CONTACTS_PROTECTED_SETTINGS.length; i++) {
    268             String key = READ_CONTACTS_PROTECTED_SETTINGS[i];
    269             if (key.equals(requestedKey) && mContext.checkCallingOrSelfPermission(READ_CONTACTS)
    270                     != PackageManager.PERMISSION_GRANTED) {
    271                 throw new SecurityException("uid=" + callingUid
    272                         + " needs permission " + READ_CONTACTS + " to read "
    273                         + requestedKey + " for user " + userId);
    274             }
    275         }
    276 
    277         for (int i = 0; i < READ_PASSWORD_PROTECTED_SETTINGS.length; i++) {
    278             String key = READ_PASSWORD_PROTECTED_SETTINGS[i];
    279             if (key.equals(requestedKey) && mContext.checkCallingOrSelfPermission(PERMISSION)
    280                     != PackageManager.PERMISSION_GRANTED) {
    281                 throw new SecurityException("uid=" + callingUid
    282                         + " needs permission " + PERMISSION + " to read "
    283                         + requestedKey + " for user " + userId);
    284             }
    285         }
    286     }
    287 
    288     @Override
    289     public void setBoolean(String key, boolean value, int userId) throws RemoteException {
    290         checkWritePermission(userId);
    291         setStringUnchecked(key, userId, value ? "1" : "0");
    292     }
    293 
    294     @Override
    295     public void setLong(String key, long value, int userId) throws RemoteException {
    296         checkWritePermission(userId);
    297         setStringUnchecked(key, userId, Long.toString(value));
    298     }
    299 
    300     @Override
    301     public void setString(String key, String value, int userId) throws RemoteException {
    302         checkWritePermission(userId);
    303         setStringUnchecked(key, userId, value);
    304     }
    305 
    306     private void setStringUnchecked(String key, int userId, String value) {
    307         mStorage.writeKeyValue(key, value, userId);
    308         if (ArrayUtils.contains(SETTINGS_TO_BACKUP, key)) {
    309             BackupManager.dataChanged("com.android.providers.settings");
    310         }
    311     }
    312 
    313     @Override
    314     public boolean getBoolean(String key, boolean defaultValue, int userId) throws RemoteException {
    315         checkReadPermission(key, userId);
    316         String value = getStringUnchecked(key, null, userId);
    317         return TextUtils.isEmpty(value) ?
    318                 defaultValue : (value.equals("1") || value.equals("true"));
    319     }
    320 
    321     @Override
    322     public long getLong(String key, long defaultValue, int userId) throws RemoteException {
    323         checkReadPermission(key, userId);
    324 
    325         String value = getStringUnchecked(key, null, userId);
    326         return TextUtils.isEmpty(value) ? defaultValue : Long.parseLong(value);
    327     }
    328 
    329     @Override
    330     public String getString(String key, String defaultValue, int userId) throws RemoteException {
    331         checkReadPermission(key, userId);
    332 
    333         return getStringUnchecked(key, defaultValue, userId);
    334     }
    335 
    336     public String getStringUnchecked(String key, String defaultValue, int userId) {
    337         if (Settings.Secure.LOCK_PATTERN_ENABLED.equals(key)) {
    338             long ident = Binder.clearCallingIdentity();
    339             try {
    340                 return mLockPatternUtils.isLockPatternEnabled(userId) ? "1" : "0";
    341             } finally {
    342                 Binder.restoreCallingIdentity(ident);
    343             }
    344         }
    345 
    346         return mStorage.readKeyValue(key, defaultValue, userId);
    347     }
    348 
    349     @Override
    350     public boolean havePassword(int userId) throws RemoteException {
    351         // Do we need a permissions check here?
    352 
    353         return mStorage.hasPassword(userId);
    354     }
    355 
    356     @Override
    357     public boolean havePattern(int userId) throws RemoteException {
    358         // Do we need a permissions check here?
    359 
    360         return mStorage.hasPattern(userId);
    361     }
    362 
    363     private void setKeystorePassword(String password, int userHandle) {
    364         final UserManager um = (UserManager) mContext.getSystemService(USER_SERVICE);
    365         final KeyStore ks = KeyStore.getInstance();
    366 
    367         final List<UserInfo> profiles = um.getProfiles(userHandle);
    368         for (UserInfo pi : profiles) {
    369             ks.onUserPasswordChanged(pi.id, password);
    370         }
    371     }
    372 
    373     private void unlockKeystore(String password, int userHandle) {
    374         final UserManager um = (UserManager) mContext.getSystemService(USER_SERVICE);
    375         final KeyStore ks = KeyStore.getInstance();
    376 
    377         final List<UserInfo> profiles = um.getProfiles(userHandle);
    378         for (UserInfo pi : profiles) {
    379             ks.unlock(pi.id, password);
    380         }
    381     }
    382 
    383 
    384     private byte[] getCurrentHandle(int userId) {
    385         CredentialHash credential;
    386         byte[] currentHandle;
    387 
    388         int currentHandleType = mStorage.getStoredCredentialType(userId);
    389         switch (currentHandleType) {
    390             case CredentialHash.TYPE_PATTERN:
    391                 credential = mStorage.readPatternHash(userId);
    392                 currentHandle = credential != null
    393                         ? credential.hash
    394                         : null;
    395                 break;
    396             case CredentialHash.TYPE_PASSWORD:
    397                 credential = mStorage.readPasswordHash(userId);
    398                 currentHandle = credential != null
    399                         ? credential.hash
    400                         : null;
    401                 break;
    402             case CredentialHash.TYPE_NONE:
    403             default:
    404                 currentHandle = null;
    405                 break;
    406         }
    407 
    408         // sanity check
    409         if (currentHandleType != CredentialHash.TYPE_NONE && currentHandle == null) {
    410             Slog.e(TAG, "Stored handle type [" + currentHandleType + "] but no handle available");
    411         }
    412 
    413         return currentHandle;
    414     }
    415 
    416 
    417     @Override
    418     public void setLockPattern(String pattern, String savedCredential, int userId)
    419             throws RemoteException {
    420         byte[] currentHandle = getCurrentHandle(userId);
    421 
    422         if (pattern == null) {
    423             getGateKeeperService().clearSecureUserId(userId);
    424             mStorage.writePatternHash(null, userId);
    425             setKeystorePassword(null, userId);
    426             return;
    427         }
    428 
    429         if (currentHandle == null) {
    430             if (savedCredential != null) {
    431                 Slog.w(TAG, "Saved credential provided, but none stored");
    432             }
    433             savedCredential = null;
    434         }
    435 
    436         byte[] enrolledHandle = enrollCredential(currentHandle, savedCredential, pattern, userId);
    437         if (enrolledHandle != null) {
    438             mStorage.writePatternHash(enrolledHandle, userId);
    439         } else {
    440             Slog.e(TAG, "Failed to enroll pattern");
    441         }
    442     }
    443 
    444 
    445     @Override
    446     public void setLockPassword(String password, String savedCredential, int userId)
    447             throws RemoteException {
    448         byte[] currentHandle = getCurrentHandle(userId);
    449 
    450         if (password == null) {
    451             getGateKeeperService().clearSecureUserId(userId);
    452             mStorage.writePasswordHash(null, userId);
    453             setKeystorePassword(null, userId);
    454             return;
    455         }
    456 
    457         if (currentHandle == null) {
    458             if (savedCredential != null) {
    459                 Slog.w(TAG, "Saved credential provided, but none stored");
    460             }
    461             savedCredential = null;
    462         }
    463 
    464         byte[] enrolledHandle = enrollCredential(currentHandle, savedCredential, password, userId);
    465         if (enrolledHandle != null) {
    466             mStorage.writePasswordHash(enrolledHandle, userId);
    467         } else {
    468             Slog.e(TAG, "Failed to enroll password");
    469         }
    470     }
    471 
    472     private byte[] enrollCredential(byte[] enrolledHandle,
    473             String enrolledCredential, String toEnroll, int userId)
    474             throws RemoteException {
    475         checkWritePermission(userId);
    476         byte[] enrolledCredentialBytes = enrolledCredential == null
    477                 ? null
    478                 : enrolledCredential.getBytes();
    479         byte[] toEnrollBytes = toEnroll == null
    480                 ? null
    481                 : toEnroll.getBytes();
    482         GateKeeperResponse response = getGateKeeperService().enroll(userId, enrolledHandle,
    483                 enrolledCredentialBytes, toEnrollBytes);
    484 
    485         if (response == null) {
    486             return null;
    487         }
    488 
    489         byte[] hash = response.getPayload();
    490         if (hash != null) {
    491             setKeystorePassword(toEnroll, userId);
    492         } else {
    493             // Should not happen
    494             Slog.e(TAG, "Throttled while enrolling a password");
    495         }
    496         return hash;
    497     }
    498 
    499     @Override
    500     public VerifyCredentialResponse checkPattern(String pattern, int userId) throws RemoteException {
    501         return doVerifyPattern(pattern, false, 0, userId);
    502     }
    503 
    504     @Override
    505     public VerifyCredentialResponse verifyPattern(String pattern, long challenge, int userId)
    506             throws RemoteException {
    507         return doVerifyPattern(pattern, true, challenge, userId);
    508     }
    509 
    510     private VerifyCredentialResponse doVerifyPattern(String pattern, boolean hasChallenge,
    511             long challenge, int userId) throws RemoteException {
    512        checkPasswordReadPermission(userId);
    513        CredentialHash storedHash = mStorage.readPatternHash(userId);
    514        boolean shouldReEnrollBaseZero = storedHash != null && storedHash.isBaseZeroPattern;
    515 
    516        String patternToVerify;
    517        if (shouldReEnrollBaseZero) {
    518            patternToVerify = LockPatternUtils.patternStringToBaseZero(pattern);
    519        } else {
    520            patternToVerify = pattern;
    521        }
    522 
    523        VerifyCredentialResponse response = verifyCredential(userId, storedHash, patternToVerify,
    524                hasChallenge, challenge,
    525                new CredentialUtil() {
    526                    @Override
    527                    public void setCredential(String pattern, String oldPattern, int userId)
    528                            throws RemoteException {
    529                        setLockPattern(pattern, oldPattern, userId);
    530                    }
    531 
    532                    @Override
    533                    public byte[] toHash(String pattern, int userId) {
    534                        return LockPatternUtils.patternToHash(
    535                                LockPatternUtils.stringToPattern(pattern));
    536                    }
    537 
    538                    @Override
    539                    public String adjustForKeystore(String pattern) {
    540                        return LockPatternUtils.patternStringToBaseZero(pattern);
    541                    }
    542                }
    543        );
    544 
    545        if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK
    546                && shouldReEnrollBaseZero) {
    547            setLockPattern(pattern, patternToVerify, userId);
    548        }
    549 
    550        return response;
    551 
    552     }
    553 
    554     @Override
    555     public VerifyCredentialResponse checkPassword(String password, int userId)
    556             throws RemoteException {
    557         return doVerifyPassword(password, false, 0, userId);
    558     }
    559 
    560     @Override
    561     public VerifyCredentialResponse verifyPassword(String password, long challenge, int userId)
    562             throws RemoteException {
    563         return doVerifyPassword(password, true, challenge, userId);
    564     }
    565 
    566     private VerifyCredentialResponse doVerifyPassword(String password, boolean hasChallenge,
    567             long challenge, int userId) throws RemoteException {
    568        checkPasswordReadPermission(userId);
    569        CredentialHash storedHash = mStorage.readPasswordHash(userId);
    570        return verifyCredential(userId, storedHash, password, hasChallenge, challenge,
    571                new CredentialUtil() {
    572                    @Override
    573                    public void setCredential(String password, String oldPassword, int userId)
    574                            throws RemoteException {
    575                        setLockPassword(password, oldPassword, userId);
    576                    }
    577 
    578                    @Override
    579                    public byte[] toHash(String password, int userId) {
    580                        return mLockPatternUtils.passwordToHash(password, userId);
    581                    }
    582 
    583                    @Override
    584                    public String adjustForKeystore(String password) {
    585                        return password;
    586                    }
    587                }
    588        );
    589     }
    590 
    591     private VerifyCredentialResponse verifyCredential(int userId, CredentialHash storedHash,
    592             String credential, boolean hasChallenge, long challenge, CredentialUtil credentialUtil)
    593                 throws RemoteException {
    594         if ((storedHash == null || storedHash.hash.length == 0) && TextUtils.isEmpty(credential)) {
    595             // don't need to pass empty credentials to GateKeeper
    596             return VerifyCredentialResponse.OK;
    597         }
    598 
    599         if (TextUtils.isEmpty(credential)) {
    600             return VerifyCredentialResponse.ERROR;
    601         }
    602 
    603         if (storedHash.version == CredentialHash.VERSION_LEGACY) {
    604             byte[] hash = credentialUtil.toHash(credential, userId);
    605             if (Arrays.equals(hash, storedHash.hash)) {
    606                 unlockKeystore(credentialUtil.adjustForKeystore(credential), userId);
    607                 // migrate credential to GateKeeper
    608                 credentialUtil.setCredential(credential, null, userId);
    609                 if (!hasChallenge) {
    610                     return VerifyCredentialResponse.OK;
    611                 }
    612                 // Fall through to get the auth token. Technically this should never happen,
    613                 // as a user that had a legacy credential would have to unlock their device
    614                 // before getting to a flow with a challenge, but supporting for consistency.
    615             } else {
    616                 return VerifyCredentialResponse.ERROR;
    617             }
    618         }
    619 
    620         VerifyCredentialResponse response;
    621         boolean shouldReEnroll = false;;
    622         if (hasChallenge) {
    623             byte[] token = null;
    624             GateKeeperResponse gateKeeperResponse = getGateKeeperService()
    625                     .verifyChallenge(userId, challenge, storedHash.hash, credential.getBytes());
    626             int responseCode = gateKeeperResponse.getResponseCode();
    627             if (responseCode == GateKeeperResponse.RESPONSE_RETRY) {
    628                  response = new VerifyCredentialResponse(gateKeeperResponse.getTimeout());
    629             } else if (responseCode == GateKeeperResponse.RESPONSE_OK) {
    630                 token = gateKeeperResponse.getPayload();
    631                 if (token == null) {
    632                     // something's wrong if there's no payload with a challenge
    633                     Slog.e(TAG, "verifyChallenge response had no associated payload");
    634                     response = VerifyCredentialResponse.ERROR;
    635                 } else {
    636                     shouldReEnroll = gateKeeperResponse.getShouldReEnroll();
    637                     response = new VerifyCredentialResponse(token);
    638                 }
    639             } else {
    640                 response = VerifyCredentialResponse.ERROR;
    641             }
    642         } else {
    643             GateKeeperResponse gateKeeperResponse = getGateKeeperService().verify(
    644                     userId, storedHash.hash, credential.getBytes());
    645             int responseCode = gateKeeperResponse.getResponseCode();
    646             if (responseCode == GateKeeperResponse.RESPONSE_RETRY) {
    647                 response = new VerifyCredentialResponse(gateKeeperResponse.getTimeout());
    648             } else if (responseCode == GateKeeperResponse.RESPONSE_OK) {
    649                 shouldReEnroll = gateKeeperResponse.getShouldReEnroll();
    650                 response = VerifyCredentialResponse.OK;
    651             } else {
    652                 response = VerifyCredentialResponse.ERROR;
    653             }
    654         }
    655 
    656         if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
    657             // credential has matched
    658             unlockKeystore(credential, userId);
    659             if (shouldReEnroll) {
    660                 credentialUtil.setCredential(credential, credential, userId);
    661             }
    662         }
    663 
    664         return response;
    665     }
    666 
    667     @Override
    668     public boolean checkVoldPassword(int userId) throws RemoteException {
    669         if (!mFirstCallToVold) {
    670             return false;
    671         }
    672         mFirstCallToVold = false;
    673 
    674         checkPasswordReadPermission(userId);
    675 
    676         // There's no guarantee that this will safely connect, but if it fails
    677         // we will simply show the lock screen when we shouldn't, so relatively
    678         // benign. There is an outside chance something nasty would happen if
    679         // this service restarted before vold stales out the password in this
    680         // case. The nastiness is limited to not showing the lock screen when
    681         // we should, within the first minute of decrypting the phone if this
    682         // service can't connect to vold, it restarts, and then the new instance
    683         // does successfully connect.
    684         final IMountService service = getMountService();
    685         String password = service.getPassword();
    686         service.clearPassword();
    687         if (password == null) {
    688             return false;
    689         }
    690 
    691         try {
    692             if (mLockPatternUtils.isLockPatternEnabled(userId)) {
    693                 if (checkPattern(password, userId).getResponseCode()
    694                         == GateKeeperResponse.RESPONSE_OK) {
    695                     return true;
    696                 }
    697             }
    698         } catch (Exception e) {
    699         }
    700 
    701         try {
    702             if (mLockPatternUtils.isLockPasswordEnabled(userId)) {
    703                 if (checkPassword(password, userId).getResponseCode()
    704                         == GateKeeperResponse.RESPONSE_OK) {
    705                     return true;
    706                 }
    707             }
    708         } catch (Exception e) {
    709         }
    710 
    711         return false;
    712     }
    713 
    714     private void removeUser(int userId) {
    715         mStorage.removeUser(userId);
    716 
    717         final KeyStore ks = KeyStore.getInstance();
    718         ks.onUserRemoved(userId);
    719 
    720         try {
    721             final IGateKeeperService gk = getGateKeeperService();
    722             if (gk != null) {
    723                     gk.clearSecureUserId(userId);
    724             }
    725         } catch (RemoteException ex) {
    726             Slog.w(TAG, "unable to clear GK secure user id");
    727         }
    728     }
    729 
    730     private static final String[] VALID_SETTINGS = new String[] {
    731         LockPatternUtils.LOCKOUT_PERMANENT_KEY,
    732         LockPatternUtils.LOCKOUT_ATTEMPT_DEADLINE,
    733         LockPatternUtils.PATTERN_EVER_CHOSEN_KEY,
    734         LockPatternUtils.PASSWORD_TYPE_KEY,
    735         LockPatternUtils.PASSWORD_TYPE_ALTERNATE_KEY,
    736         LockPatternUtils.LOCK_PASSWORD_SALT_KEY,
    737         LockPatternUtils.DISABLE_LOCKSCREEN_KEY,
    738         LockPatternUtils.LOCKSCREEN_OPTIONS,
    739         LockPatternUtils.LOCKSCREEN_BIOMETRIC_WEAK_FALLBACK,
    740         LockPatternUtils.BIOMETRIC_WEAK_EVER_CHOSEN_KEY,
    741         LockPatternUtils.LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS,
    742         LockPatternUtils.PASSWORD_HISTORY_KEY,
    743         Secure.LOCK_PATTERN_ENABLED,
    744         Secure.LOCK_BIOMETRIC_WEAK_FLAGS,
    745         Secure.LOCK_PATTERN_VISIBLE,
    746         Secure.LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED
    747     };
    748 
    749     // Reading these settings needs the contacts permission
    750     private static final String[] READ_CONTACTS_PROTECTED_SETTINGS = new String[] {
    751         Secure.LOCK_SCREEN_OWNER_INFO_ENABLED,
    752         Secure.LOCK_SCREEN_OWNER_INFO
    753     };
    754 
    755     // Reading these settings needs the same permission as checking the password
    756     private static final String[] READ_PASSWORD_PROTECTED_SETTINGS = new String[] {
    757             LockPatternUtils.LOCK_PASSWORD_SALT_KEY,
    758             LockPatternUtils.PASSWORD_HISTORY_KEY,
    759             LockPatternUtils.PASSWORD_TYPE_KEY,
    760     };
    761 
    762     private static final String[] SETTINGS_TO_BACKUP = new String[] {
    763         Secure.LOCK_SCREEN_OWNER_INFO_ENABLED,
    764         Secure.LOCK_SCREEN_OWNER_INFO
    765     };
    766 
    767     private IMountService getMountService() {
    768         final IBinder service = ServiceManager.getService("mount");
    769         if (service != null) {
    770             return IMountService.Stub.asInterface(service);
    771         }
    772         return null;
    773     }
    774 
    775     private class GateKeeperDiedRecipient implements IBinder.DeathRecipient {
    776         @Override
    777         public void binderDied() {
    778             mGateKeeperService.asBinder().unlinkToDeath(this, 0);
    779             mGateKeeperService = null;
    780         }
    781     }
    782 
    783     private synchronized IGateKeeperService getGateKeeperService()
    784             throws RemoteException {
    785         if (mGateKeeperService != null) {
    786             return mGateKeeperService;
    787         }
    788 
    789         final IBinder service =
    790             ServiceManager.getService("android.service.gatekeeper.IGateKeeperService");
    791         if (service != null) {
    792             service.linkToDeath(new GateKeeperDiedRecipient(), 0);
    793             mGateKeeperService = IGateKeeperService.Stub.asInterface(service);
    794             return mGateKeeperService;
    795         }
    796 
    797         Slog.e(TAG, "Unable to acquire GateKeeperService");
    798         return null;
    799     }
    800 
    801 }
    802