OSDN Git Service

FBE notification improvements
[android-x86/frameworks-base.git] / services / core / java / com / android / server / LockSettingsService.java
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.ActivityManagerNative;
20 import android.app.Notification;
21 import android.app.NotificationManager;
22 import android.app.PendingIntent;
23 import android.app.admin.DevicePolicyManager;
24 import android.app.backup.BackupManager;
25 import android.app.trust.IStrongAuthTracker;
26 import android.app.trust.TrustManager;
27 import android.content.BroadcastReceiver;
28 import android.content.ContentResolver;
29 import android.content.Context;
30 import android.content.Intent;
31 import android.content.IntentFilter;
32 import android.content.pm.PackageManager;
33 import android.content.pm.UserInfo;
34 import android.content.res.Resources;
35
36 import static android.Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE;
37 import static android.content.Context.USER_SERVICE;
38 import static android.Manifest.permission.READ_CONTACTS;
39 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT;
40
41 import android.database.sqlite.SQLiteDatabase;
42 import android.os.Binder;
43 import android.os.IBinder;
44 import android.os.RemoteException;
45 import android.os.storage.IMountService;
46 import android.os.ServiceManager;
47 import android.os.SystemProperties;
48 import android.os.UserHandle;
49 import android.os.UserManager;
50 import android.provider.Settings;
51 import android.provider.Settings.Secure;
52 import android.provider.Settings.SettingNotFoundException;
53 import android.security.KeyStore;
54 import android.service.gatekeeper.GateKeeperResponse;
55 import android.service.gatekeeper.IGateKeeperService;
56 import android.text.TextUtils;
57 import android.util.Slog;
58
59 import com.android.internal.util.ArrayUtils;
60 import com.android.internal.widget.ILockSettings;
61 import com.android.internal.widget.LockPatternUtils;
62 import com.android.internal.widget.VerifyCredentialResponse;
63 import com.android.server.LockSettingsStorage.CredentialHash;
64
65 import java.util.Arrays;
66 import java.util.List;
67
68 /**
69  * Keeps the lock pattern/password data and related settings for each user.
70  * Used by LockPatternUtils. Needs to be a service because Settings app also needs
71  * to be able to save lockscreen information for secondary users.
72  * @hide
73  */
74 public class LockSettingsService extends ILockSettings.Stub {
75     private static final String TAG = "LockSettingsService";
76     private static final String PERMISSION = ACCESS_KEYGUARD_SECURE_STORAGE;
77     private static final Intent ACTION_NULL; // hack to ensure notification shows the bouncer
78     private static final int FBE_ENCRYPTED_NOTIFICATION = 0;
79     private static final boolean DEBUG = false;
80
81     private final Context mContext;
82     private final LockSettingsStorage mStorage;
83     private final LockSettingsStrongAuth mStrongAuth;
84
85     private LockPatternUtils mLockPatternUtils;
86     private boolean mFirstCallToVold;
87     private IGateKeeperService mGateKeeperService;
88     private NotificationManager mNotificationManager;
89     private UserManager mUserManager;
90
91     static {
92         // Just launch the home screen, which happens anyway
93         ACTION_NULL = new Intent(Intent.ACTION_MAIN);
94         ACTION_NULL.addCategory(Intent.CATEGORY_HOME);
95     }
96
97     private interface CredentialUtil {
98         void setCredential(String credential, String savedCredential, int userId)
99                 throws RemoteException;
100         byte[] toHash(String credential, int userId);
101         String adjustForKeystore(String credential);
102     }
103
104     // This class manages life cycle events for encrypted users on File Based Encryption (FBE)
105     // devices. The most basic of these is to show/hide notifications about missing features until
106     // the user unlocks the account and credential-encrypted storage is available.
107     public static final class Lifecycle extends SystemService {
108         private LockSettingsService mLockSettingsService;
109
110         public Lifecycle(Context context) {
111             super(context);
112         }
113
114         @Override
115         public void onStart() {
116             mLockSettingsService = new LockSettingsService(getContext());
117             publishBinderService("lock_settings", mLockSettingsService);
118         }
119
120         @Override
121         public void onBootPhase(int phase) {
122             if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
123                 mLockSettingsService.maybeShowEncryptionNotification(UserHandle.ALL);
124             } else if (phase == SystemService.PHASE_BOOT_COMPLETED) {
125                 // TODO
126             }
127         }
128
129         @Override
130         public void onUnlockUser(int userHandle) {
131             mLockSettingsService.onUnlockUser(userHandle);
132         }
133
134         @Override
135         public void onCleanupUser(int userHandle) {
136             mLockSettingsService.onCleanupUser(userHandle);
137         }
138     }
139
140     public LockSettingsService(Context context) {
141         mContext = context;
142         mStrongAuth = new LockSettingsStrongAuth(context);
143         // Open the database
144
145         mLockPatternUtils = new LockPatternUtils(context);
146         mFirstCallToVold = true;
147
148         IntentFilter filter = new IntentFilter();
149         filter.addAction(Intent.ACTION_USER_ADDED);
150         filter.addAction(Intent.ACTION_USER_STARTING);
151         filter.addAction(Intent.ACTION_USER_REMOVED);
152         filter.addAction(Intent.ACTION_USER_PRESENT);
153         mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null);
154
155         mStorage = new LockSettingsStorage(context, new LockSettingsStorage.Callback() {
156             @Override
157             public void initialize(SQLiteDatabase db) {
158                 // Get the lockscreen default from a system property, if available
159                 boolean lockScreenDisable = SystemProperties.getBoolean(
160                         "ro.lockscreen.disable.default", false);
161                 if (lockScreenDisable) {
162                     mStorage.writeKeyValue(db, LockPatternUtils.DISABLE_LOCKSCREEN_KEY, "1", 0);
163                 }
164             }
165         });
166         mNotificationManager = (NotificationManager)
167                 mContext.getSystemService(Context.NOTIFICATION_SERVICE);
168         mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
169     }
170
171     /**
172      * If the account is credential-encrypted, show notification requesting the user to unlock
173      * the device.
174      */
175     private void maybeShowEncryptionNotification(UserHandle userHandle) {
176         if (UserHandle.ALL.equals(userHandle)) {
177             final List<UserInfo> users = mUserManager.getUsers();
178             for (int i = 0; i < users.size(); i++) {
179                 UserHandle user = users.get(i).getUserHandle();
180                 if (!mUserManager.isUserUnlocked(user)) {
181                     showEncryptionNotification(user);
182                 }
183             }
184         } else if (!mUserManager.isUserUnlocked(userHandle)){
185             showEncryptionNotification(userHandle);
186         }
187     }
188
189     private void showEncryptionNotification(UserHandle user) {
190         if (DEBUG) Slog.v(TAG, "showing encryption notification, user: " + user.getIdentifier());
191         Resources r = mContext.getResources();
192         CharSequence title = r.getText(
193                 com.android.internal.R.string.user_encrypted_title);
194         CharSequence message = r.getText(
195                 com.android.internal.R.string.user_encrypted_message);
196         CharSequence detail = r.getText(
197                 com.android.internal.R.string.user_encrypted_detail);
198
199         PendingIntent intent = PendingIntent.getBroadcast(mContext, 0, ACTION_NULL,
200                 PendingIntent.FLAG_UPDATE_CURRENT);
201
202         Notification notification = new Notification.Builder(mContext)
203                 .setSmallIcon(com.android.internal.R.drawable.ic_secure)
204                 .setWhen(0)
205                 .setOngoing(true)
206                 .setTicker(title)
207                 .setDefaults(0)  // please be quiet
208                 .setPriority(Notification.PRIORITY_MAX)
209                 .setColor(mContext.getColor(
210                         com.android.internal.R.color.system_notification_accent_color))
211                 .setContentTitle(title)
212                 .setContentText(message)
213                 .setContentInfo(detail)
214                 .setVisibility(Notification.VISIBILITY_PUBLIC)
215                 .setContentIntent(intent)
216                 .build();
217         mNotificationManager.notifyAsUser(null, FBE_ENCRYPTED_NOTIFICATION, notification, user);
218     }
219
220     public void hideEncryptionNotification(UserHandle userHandle) {
221         if (DEBUG) Slog.v(TAG, "hide encryption notification, user: "+ userHandle.getIdentifier());
222         mNotificationManager.cancelAsUser(null, FBE_ENCRYPTED_NOTIFICATION, userHandle);
223     }
224
225     public void onCleanupUser(int userId) {
226         hideEncryptionNotification(new UserHandle(userId));
227     }
228
229     public void onUnlockUser(int userHandle) {
230         hideEncryptionNotification(new UserHandle(userHandle));
231     }
232
233     private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
234         @Override
235         public void onReceive(Context context, Intent intent) {
236             if (Intent.ACTION_USER_ADDED.equals(intent.getAction())) {
237                 // Notify keystore that a new user was added.
238                 final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
239                 final KeyStore ks = KeyStore.getInstance();
240                 final UserManager um = (UserManager) mContext.getSystemService(USER_SERVICE);
241                 final UserInfo parentInfo = um.getProfileParent(userHandle);
242                 final int parentHandle = parentInfo != null ? parentInfo.id : -1;
243                 ks.onUserAdded(userHandle, parentHandle);
244             } else if (Intent.ACTION_USER_STARTING.equals(intent.getAction())) {
245                 final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
246                 mStorage.prefetchUser(userHandle);
247             } else if (Intent.ACTION_USER_PRESENT.equals(intent.getAction())) {
248                 mStrongAuth.reportUnlock(getSendingUserId());
249             } else if (Intent.ACTION_USER_REMOVED.equals(intent.getAction())) {
250                 final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
251                 if (userHandle > 0) {
252                     removeUser(userHandle);
253                 }
254             }
255         }
256     };
257
258     @Override // binder interface
259     public void systemReady() {
260         migrateOldData();
261         try {
262             getGateKeeperService();
263         } catch (RemoteException e) {
264             Slog.e(TAG, "Failure retrieving IGateKeeperService", e);
265         }
266         // TODO: maybe skip this for split system user mode.
267         mStorage.prefetchUser(UserHandle.USER_SYSTEM);
268     }
269
270     private void migrateOldData() {
271         try {
272             // These Settings moved before multi-user was enabled, so we only have to do it for the
273             // root user.
274             if (getString("migrated", null, 0) == null) {
275                 final ContentResolver cr = mContext.getContentResolver();
276                 for (String validSetting : VALID_SETTINGS) {
277                     String value = Settings.Secure.getString(cr, validSetting);
278                     if (value != null) {
279                         setString(validSetting, value, 0);
280                     }
281                 }
282                 // No need to move the password / pattern files. They're already in the right place.
283                 setString("migrated", "true", 0);
284                 Slog.i(TAG, "Migrated lock settings to new location");
285             }
286
287             // These Settings changed after multi-user was enabled, hence need to be moved per user.
288             if (getString("migrated_user_specific", null, 0) == null) {
289                 final UserManager um = (UserManager) mContext.getSystemService(USER_SERVICE);
290                 final ContentResolver cr = mContext.getContentResolver();
291                 List<UserInfo> users = um.getUsers();
292                 for (int user = 0; user < users.size(); user++) {
293                     // Migrate owner info
294                     final int userId = users.get(user).id;
295                     final String OWNER_INFO = Secure.LOCK_SCREEN_OWNER_INFO;
296                     String ownerInfo = Settings.Secure.getStringForUser(cr, OWNER_INFO, userId);
297                     if (ownerInfo != null) {
298                         setString(OWNER_INFO, ownerInfo, userId);
299                         Settings.Secure.putStringForUser(cr, ownerInfo, "", userId);
300                     }
301
302                     // Migrate owner info enabled.  Note there was a bug where older platforms only
303                     // stored this value if the checkbox was toggled at least once. The code detects
304                     // this case by handling the exception.
305                     final String OWNER_INFO_ENABLED = Secure.LOCK_SCREEN_OWNER_INFO_ENABLED;
306                     boolean enabled;
307                     try {
308                         int ivalue = Settings.Secure.getIntForUser(cr, OWNER_INFO_ENABLED, userId);
309                         enabled = ivalue != 0;
310                         setLong(OWNER_INFO_ENABLED, enabled ? 1 : 0, userId);
311                     } catch (SettingNotFoundException e) {
312                         // Setting was never stored. Store it if the string is not empty.
313                         if (!TextUtils.isEmpty(ownerInfo)) {
314                             setLong(OWNER_INFO_ENABLED, 1, userId);
315                         }
316                     }
317                     Settings.Secure.putIntForUser(cr, OWNER_INFO_ENABLED, 0, userId);
318                 }
319                 // No need to move the password / pattern files. They're already in the right place.
320                 setString("migrated_user_specific", "true", 0);
321                 Slog.i(TAG, "Migrated per-user lock settings to new location");
322             }
323
324             // Migrates biometric weak such that the fallback mechanism becomes the primary.
325             if (getString("migrated_biometric_weak", null, 0) == null) {
326                 final UserManager um = (UserManager) mContext.getSystemService(USER_SERVICE);
327                 List<UserInfo> users = um.getUsers();
328                 for (int i = 0; i < users.size(); i++) {
329                     int userId = users.get(i).id;
330                     long type = getLong(LockPatternUtils.PASSWORD_TYPE_KEY,
331                             DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
332                             userId);
333                     long alternateType = getLong(LockPatternUtils.PASSWORD_TYPE_ALTERNATE_KEY,
334                             DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
335                             userId);
336                     if (type == DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK) {
337                         setLong(LockPatternUtils.PASSWORD_TYPE_KEY,
338                                 alternateType,
339                                 userId);
340                     }
341                     setLong(LockPatternUtils.PASSWORD_TYPE_ALTERNATE_KEY,
342                             DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
343                             userId);
344                 }
345                 setString("migrated_biometric_weak", "true", 0);
346                 Slog.i(TAG, "Migrated biometric weak to use the fallback instead");
347             }
348
349             // Migrates lockscreen.disabled. Prior to M, the flag was ignored when more than one
350             // user was present on the system, so if we're upgrading to M and there is more than one
351             // user we disable the flag to remain consistent.
352             if (getString("migrated_lockscreen_disabled", null, 0) == null) {
353                 final UserManager um = (UserManager) mContext.getSystemService(USER_SERVICE);
354
355                 final List<UserInfo> users = um.getUsers();
356                 final int userCount = users.size();
357                 int switchableUsers = 0;
358                 for (int i = 0; i < userCount; i++) {
359                     if (users.get(i).supportsSwitchTo()) {
360                         switchableUsers++;
361                     }
362                 }
363
364                 if (switchableUsers > 1) {
365                     for (int i = 0; i < userCount; i++) {
366                         int id = users.get(i).id;
367
368                         if (getBoolean(LockPatternUtils.DISABLE_LOCKSCREEN_KEY, false, id)) {
369                             setBoolean(LockPatternUtils.DISABLE_LOCKSCREEN_KEY, false, id);
370                         }
371                     }
372                 }
373
374                 setString("migrated_lockscreen_disabled", "true", 0);
375                 Slog.i(TAG, "Migrated lockscreen disabled flag");
376             }
377         } catch (RemoteException re) {
378             Slog.e(TAG, "Unable to migrate old data", re);
379         }
380     }
381
382     private final void checkWritePermission(int userId) {
383         mContext.enforceCallingOrSelfPermission(PERMISSION, "LockSettingsWrite");
384     }
385
386     private final void checkPasswordReadPermission(int userId) {
387         mContext.enforceCallingOrSelfPermission(PERMISSION, "LockSettingsRead");
388     }
389
390     private final void checkReadPermission(String requestedKey, int userId) {
391         final int callingUid = Binder.getCallingUid();
392
393         for (int i = 0; i < READ_CONTACTS_PROTECTED_SETTINGS.length; i++) {
394             String key = READ_CONTACTS_PROTECTED_SETTINGS[i];
395             if (key.equals(requestedKey) && mContext.checkCallingOrSelfPermission(READ_CONTACTS)
396                     != PackageManager.PERMISSION_GRANTED) {
397                 throw new SecurityException("uid=" + callingUid
398                         + " needs permission " + READ_CONTACTS + " to read "
399                         + requestedKey + " for user " + userId);
400             }
401         }
402
403         for (int i = 0; i < READ_PASSWORD_PROTECTED_SETTINGS.length; i++) {
404             String key = READ_PASSWORD_PROTECTED_SETTINGS[i];
405             if (key.equals(requestedKey) && mContext.checkCallingOrSelfPermission(PERMISSION)
406                     != PackageManager.PERMISSION_GRANTED) {
407                 throw new SecurityException("uid=" + callingUid
408                         + " needs permission " + PERMISSION + " to read "
409                         + requestedKey + " for user " + userId);
410             }
411         }
412     }
413
414     @Override
415     public void setBoolean(String key, boolean value, int userId) throws RemoteException {
416         checkWritePermission(userId);
417         setStringUnchecked(key, userId, value ? "1" : "0");
418     }
419
420     @Override
421     public void setLong(String key, long value, int userId) throws RemoteException {
422         checkWritePermission(userId);
423         setStringUnchecked(key, userId, Long.toString(value));
424     }
425
426     @Override
427     public void setString(String key, String value, int userId) throws RemoteException {
428         checkWritePermission(userId);
429         setStringUnchecked(key, userId, value);
430     }
431
432     private void setStringUnchecked(String key, int userId, String value) {
433         mStorage.writeKeyValue(key, value, userId);
434         if (ArrayUtils.contains(SETTINGS_TO_BACKUP, key)) {
435             BackupManager.dataChanged("com.android.providers.settings");
436         }
437     }
438
439     @Override
440     public boolean getBoolean(String key, boolean defaultValue, int userId) throws RemoteException {
441         checkReadPermission(key, userId);
442         String value = getStringUnchecked(key, null, userId);
443         return TextUtils.isEmpty(value) ?
444                 defaultValue : (value.equals("1") || value.equals("true"));
445     }
446
447     @Override
448     public long getLong(String key, long defaultValue, int userId) throws RemoteException {
449         checkReadPermission(key, userId);
450
451         String value = getStringUnchecked(key, null, userId);
452         return TextUtils.isEmpty(value) ? defaultValue : Long.parseLong(value);
453     }
454
455     @Override
456     public String getString(String key, String defaultValue, int userId) throws RemoteException {
457         checkReadPermission(key, userId);
458
459         return getStringUnchecked(key, defaultValue, userId);
460     }
461
462     public String getStringUnchecked(String key, String defaultValue, int userId) {
463         if (Settings.Secure.LOCK_PATTERN_ENABLED.equals(key)) {
464             long ident = Binder.clearCallingIdentity();
465             try {
466                 return mLockPatternUtils.isLockPatternEnabled(userId) ? "1" : "0";
467             } finally {
468                 Binder.restoreCallingIdentity(ident);
469             }
470         }
471
472         if (LockPatternUtils.LEGACY_LOCK_PATTERN_ENABLED.equals(key)) {
473             key = Settings.Secure.LOCK_PATTERN_ENABLED;
474         }
475
476         return mStorage.readKeyValue(key, defaultValue, userId);
477     }
478
479     @Override
480     public boolean havePassword(int userId) throws RemoteException {
481         // Do we need a permissions check here?
482
483         return mStorage.hasPassword(userId);
484     }
485
486     @Override
487     public boolean havePattern(int userId) throws RemoteException {
488         // Do we need a permissions check here?
489
490         return mStorage.hasPattern(userId);
491     }
492
493     private void setKeystorePassword(String password, int userHandle) {
494         final UserManager um = (UserManager) mContext.getSystemService(USER_SERVICE);
495         final KeyStore ks = KeyStore.getInstance();
496
497         final List<UserInfo> profiles = um.getProfiles(userHandle);
498         for (UserInfo pi : profiles) {
499             ks.onUserPasswordChanged(pi.id, password);
500         }
501     }
502
503     private void unlockKeystore(String password, int userHandle) {
504         final UserManager um = (UserManager) mContext.getSystemService(USER_SERVICE);
505         final KeyStore ks = KeyStore.getInstance();
506
507         final List<UserInfo> profiles = um.getProfiles(userHandle);
508         for (UserInfo pi : profiles) {
509             ks.unlock(pi.id, password);
510         }
511     }
512
513     private void unlockUser(int userId, byte[] token) {
514         try {
515             ActivityManagerNative.getDefault().unlockUser(userId, token);
516         } catch (RemoteException e) {
517             throw e.rethrowAsRuntimeException();
518         }
519     }
520
521     private byte[] getCurrentHandle(int userId) {
522         CredentialHash credential;
523         byte[] currentHandle;
524
525         int currentHandleType = mStorage.getStoredCredentialType(userId);
526         switch (currentHandleType) {
527             case CredentialHash.TYPE_PATTERN:
528                 credential = mStorage.readPatternHash(userId);
529                 currentHandle = credential != null
530                         ? credential.hash
531                         : null;
532                 break;
533             case CredentialHash.TYPE_PASSWORD:
534                 credential = mStorage.readPasswordHash(userId);
535                 currentHandle = credential != null
536                         ? credential.hash
537                         : null;
538                 break;
539             case CredentialHash.TYPE_NONE:
540             default:
541                 currentHandle = null;
542                 break;
543         }
544
545         // sanity check
546         if (currentHandleType != CredentialHash.TYPE_NONE && currentHandle == null) {
547             Slog.e(TAG, "Stored handle type [" + currentHandleType + "] but no handle available");
548         }
549
550         return currentHandle;
551     }
552
553
554     @Override
555     public void setLockPattern(String pattern, String savedCredential, int userId)
556             throws RemoteException {
557         byte[] currentHandle = getCurrentHandle(userId);
558
559         if (pattern == null) {
560             getGateKeeperService().clearSecureUserId(userId);
561             mStorage.writePatternHash(null, userId);
562             setKeystorePassword(null, userId);
563             return;
564         }
565
566         if (currentHandle == null) {
567             if (savedCredential != null) {
568                 Slog.w(TAG, "Saved credential provided, but none stored");
569             }
570             savedCredential = null;
571         }
572
573         byte[] enrolledHandle = enrollCredential(currentHandle, savedCredential, pattern, userId);
574         if (enrolledHandle != null) {
575             mStorage.writePatternHash(enrolledHandle, userId);
576         } else {
577             throw new RemoteException("Failed to enroll pattern");
578         }
579     }
580
581
582     @Override
583     public void setLockPassword(String password, String savedCredential, int userId)
584             throws RemoteException {
585         byte[] currentHandle = getCurrentHandle(userId);
586
587         if (password == null) {
588             getGateKeeperService().clearSecureUserId(userId);
589             mStorage.writePasswordHash(null, userId);
590             setKeystorePassword(null, userId);
591             return;
592         }
593
594         if (currentHandle == null) {
595             if (savedCredential != null) {
596                 Slog.w(TAG, "Saved credential provided, but none stored");
597             }
598             savedCredential = null;
599         }
600
601         byte[] enrolledHandle = enrollCredential(currentHandle, savedCredential, password, userId);
602         if (enrolledHandle != null) {
603             mStorage.writePasswordHash(enrolledHandle, userId);
604         } else {
605             throw new RemoteException("Failed to enroll password");
606         }
607     }
608
609     private byte[] enrollCredential(byte[] enrolledHandle,
610             String enrolledCredential, String toEnroll, int userId)
611             throws RemoteException {
612         checkWritePermission(userId);
613         byte[] enrolledCredentialBytes = enrolledCredential == null
614                 ? null
615                 : enrolledCredential.getBytes();
616         byte[] toEnrollBytes = toEnroll == null
617                 ? null
618                 : toEnroll.getBytes();
619         GateKeeperResponse response = getGateKeeperService().enroll(userId, enrolledHandle,
620                 enrolledCredentialBytes, toEnrollBytes);
621
622         if (response == null) {
623             return null;
624         }
625
626         byte[] hash = response.getPayload();
627         if (hash != null) {
628             setKeystorePassword(toEnroll, userId);
629         } else {
630             // Should not happen
631             Slog.e(TAG, "Throttled while enrolling a password");
632         }
633         return hash;
634     }
635
636     @Override
637     public VerifyCredentialResponse checkPattern(String pattern, int userId) throws RemoteException {
638         return doVerifyPattern(pattern, false, 0, userId);
639     }
640
641     @Override
642     public VerifyCredentialResponse verifyPattern(String pattern, long challenge, int userId)
643             throws RemoteException {
644         return doVerifyPattern(pattern, true, challenge, userId);
645     }
646
647     private VerifyCredentialResponse doVerifyPattern(String pattern, boolean hasChallenge,
648             long challenge, int userId) throws RemoteException {
649        checkPasswordReadPermission(userId);
650        CredentialHash storedHash = mStorage.readPatternHash(userId);
651        boolean shouldReEnrollBaseZero = storedHash != null && storedHash.isBaseZeroPattern;
652
653        String patternToVerify;
654        if (shouldReEnrollBaseZero) {
655            patternToVerify = LockPatternUtils.patternStringToBaseZero(pattern);
656        } else {
657            patternToVerify = pattern;
658        }
659
660        VerifyCredentialResponse response = verifyCredential(userId, storedHash, patternToVerify,
661                hasChallenge, challenge,
662                new CredentialUtil() {
663                    @Override
664                    public void setCredential(String pattern, String oldPattern, int userId)
665                            throws RemoteException {
666                        setLockPattern(pattern, oldPattern, userId);
667                    }
668
669                    @Override
670                    public byte[] toHash(String pattern, int userId) {
671                        return LockPatternUtils.patternToHash(
672                                LockPatternUtils.stringToPattern(pattern));
673                    }
674
675                    @Override
676                    public String adjustForKeystore(String pattern) {
677                        return LockPatternUtils.patternStringToBaseZero(pattern);
678                    }
679                }
680        );
681
682        if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK
683                && shouldReEnrollBaseZero) {
684            setLockPattern(pattern, patternToVerify, userId);
685        }
686
687        return response;
688
689     }
690
691     @Override
692     public VerifyCredentialResponse checkPassword(String password, int userId)
693             throws RemoteException {
694         return doVerifyPassword(password, false, 0, userId);
695     }
696
697     @Override
698     public VerifyCredentialResponse verifyPassword(String password, long challenge, int userId)
699             throws RemoteException {
700         return doVerifyPassword(password, true, challenge, userId);
701     }
702
703     private VerifyCredentialResponse doVerifyPassword(String password, boolean hasChallenge,
704             long challenge, int userId) throws RemoteException {
705        checkPasswordReadPermission(userId);
706        CredentialHash storedHash = mStorage.readPasswordHash(userId);
707        return verifyCredential(userId, storedHash, password, hasChallenge, challenge,
708                new CredentialUtil() {
709                    @Override
710                    public void setCredential(String password, String oldPassword, int userId)
711                            throws RemoteException {
712                        setLockPassword(password, oldPassword, userId);
713                    }
714
715                    @Override
716                    public byte[] toHash(String password, int userId) {
717                        return mLockPatternUtils.passwordToHash(password, userId);
718                    }
719
720                    @Override
721                    public String adjustForKeystore(String password) {
722                        return password;
723                    }
724                }
725        );
726     }
727
728     private VerifyCredentialResponse verifyCredential(int userId, CredentialHash storedHash,
729             String credential, boolean hasChallenge, long challenge, CredentialUtil credentialUtil)
730                 throws RemoteException {
731         if ((storedHash == null || storedHash.hash.length == 0) && TextUtils.isEmpty(credential)) {
732             // don't need to pass empty credentials to GateKeeper
733             return VerifyCredentialResponse.OK;
734         }
735
736         if (TextUtils.isEmpty(credential)) {
737             return VerifyCredentialResponse.ERROR;
738         }
739
740         if (storedHash.version == CredentialHash.VERSION_LEGACY) {
741             byte[] hash = credentialUtil.toHash(credential, userId);
742             if (Arrays.equals(hash, storedHash.hash)) {
743                 unlockKeystore(credentialUtil.adjustForKeystore(credential), userId);
744
745                 // TODO: pass through a meaningful token from gatekeeper to
746                 // unlock credential keys; for now pass through a stub value to
747                 // indicate that we came from a user challenge.
748                 final byte[] token = String.valueOf(userId).getBytes();
749                 unlockUser(userId, token);
750
751                 // migrate credential to GateKeeper
752                 credentialUtil.setCredential(credential, null, userId);
753                 if (!hasChallenge) {
754                     return VerifyCredentialResponse.OK;
755                 }
756                 // Fall through to get the auth token. Technically this should never happen,
757                 // as a user that had a legacy credential would have to unlock their device
758                 // before getting to a flow with a challenge, but supporting for consistency.
759             } else {
760                 return VerifyCredentialResponse.ERROR;
761             }
762         }
763
764         VerifyCredentialResponse response;
765         boolean shouldReEnroll = false;;
766         if (hasChallenge) {
767             byte[] token = null;
768             GateKeeperResponse gateKeeperResponse = getGateKeeperService()
769                     .verifyChallenge(userId, challenge, storedHash.hash, credential.getBytes());
770             int responseCode = gateKeeperResponse.getResponseCode();
771             if (responseCode == GateKeeperResponse.RESPONSE_RETRY) {
772                  response = new VerifyCredentialResponse(gateKeeperResponse.getTimeout());
773             } else if (responseCode == GateKeeperResponse.RESPONSE_OK) {
774                 token = gateKeeperResponse.getPayload();
775                 if (token == null) {
776                     // something's wrong if there's no payload with a challenge
777                     Slog.e(TAG, "verifyChallenge response had no associated payload");
778                     response = VerifyCredentialResponse.ERROR;
779                 } else {
780                     shouldReEnroll = gateKeeperResponse.getShouldReEnroll();
781                     response = new VerifyCredentialResponse(token);
782                 }
783             } else {
784                 response = VerifyCredentialResponse.ERROR;
785             }
786         } else {
787             GateKeeperResponse gateKeeperResponse = getGateKeeperService().verify(
788                     userId, storedHash.hash, credential.getBytes());
789             int responseCode = gateKeeperResponse.getResponseCode();
790             if (responseCode == GateKeeperResponse.RESPONSE_RETRY) {
791                 response = new VerifyCredentialResponse(gateKeeperResponse.getTimeout());
792             } else if (responseCode == GateKeeperResponse.RESPONSE_OK) {
793                 shouldReEnroll = gateKeeperResponse.getShouldReEnroll();
794                 response = VerifyCredentialResponse.OK;
795             } else {
796                 response = VerifyCredentialResponse.ERROR;
797             }
798         }
799
800         if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
801             // credential has matched
802             unlockKeystore(credential, userId);
803
804             // TODO: pass through a meaningful token from gatekeeper to
805             // unlock credential keys; for now pass through a stub value to
806             // indicate that we came from a user challenge.
807             final byte[] token = String.valueOf(userId).getBytes();
808             unlockUser(userId, token);
809
810             UserInfo info = UserManager.get(mContext).getUserInfo(userId);
811             if (mLockPatternUtils.isSeparateProfileChallengeEnabled(userId)) {
812                 TrustManager trustManager =
813                         (TrustManager) mContext.getSystemService(Context.TRUST_SERVICE);
814                 trustManager.setDeviceLockedForUser(userId, false);
815             }
816             if (shouldReEnroll) {
817                 credentialUtil.setCredential(credential, credential, userId);
818             }
819         } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {
820             if (response.getTimeout() > 0) {
821                 requireStrongAuth(STRONG_AUTH_REQUIRED_AFTER_LOCKOUT, userId);
822             }
823         }
824
825         return response;
826     }
827
828     @Override
829     public boolean checkVoldPassword(int userId) throws RemoteException {
830         if (!mFirstCallToVold) {
831             return false;
832         }
833         mFirstCallToVold = false;
834
835         checkPasswordReadPermission(userId);
836
837         // There's no guarantee that this will safely connect, but if it fails
838         // we will simply show the lock screen when we shouldn't, so relatively
839         // benign. There is an outside chance something nasty would happen if
840         // this service restarted before vold stales out the password in this
841         // case. The nastiness is limited to not showing the lock screen when
842         // we should, within the first minute of decrypting the phone if this
843         // service can't connect to vold, it restarts, and then the new instance
844         // does successfully connect.
845         final IMountService service = getMountService();
846         String password = service.getPassword();
847         service.clearPassword();
848         if (password == null) {
849             return false;
850         }
851
852         try {
853             if (mLockPatternUtils.isLockPatternEnabled(userId)) {
854                 if (checkPattern(password, userId).getResponseCode()
855                         == GateKeeperResponse.RESPONSE_OK) {
856                     return true;
857                 }
858             }
859         } catch (Exception e) {
860         }
861
862         try {
863             if (mLockPatternUtils.isLockPasswordEnabled(userId)) {
864                 if (checkPassword(password, userId).getResponseCode()
865                         == GateKeeperResponse.RESPONSE_OK) {
866                     return true;
867                 }
868             }
869         } catch (Exception e) {
870         }
871
872         return false;
873     }
874
875     private void removeUser(int userId) {
876         mStorage.removeUser(userId);
877         mStrongAuth.removeUser(userId);
878
879         final KeyStore ks = KeyStore.getInstance();
880         ks.onUserRemoved(userId);
881
882         try {
883             final IGateKeeperService gk = getGateKeeperService();
884             if (gk != null) {
885                     gk.clearSecureUserId(userId);
886             }
887         } catch (RemoteException ex) {
888             Slog.w(TAG, "unable to clear GK secure user id");
889         }
890     }
891
892     @Override
893     public void registerStrongAuthTracker(IStrongAuthTracker tracker) {
894         checkPasswordReadPermission(UserHandle.USER_ALL);
895         mStrongAuth.registerStrongAuthTracker(tracker);
896     }
897
898     @Override
899     public void unregisterStrongAuthTracker(IStrongAuthTracker tracker) {
900         checkPasswordReadPermission(UserHandle.USER_ALL);
901         mStrongAuth.unregisterStrongAuthTracker(tracker);
902     }
903
904     @Override
905     public void requireStrongAuth(int strongAuthReason, int userId) {
906         checkWritePermission(userId);
907         mStrongAuth.requireStrongAuth(strongAuthReason, userId);
908     }
909
910     private static final String[] VALID_SETTINGS = new String[] {
911         LockPatternUtils.LOCKOUT_PERMANENT_KEY,
912         LockPatternUtils.LOCKOUT_ATTEMPT_DEADLINE,
913         LockPatternUtils.PATTERN_EVER_CHOSEN_KEY,
914         LockPatternUtils.PASSWORD_TYPE_KEY,
915         LockPatternUtils.PASSWORD_TYPE_ALTERNATE_KEY,
916         LockPatternUtils.LOCK_PASSWORD_SALT_KEY,
917         LockPatternUtils.DISABLE_LOCKSCREEN_KEY,
918         LockPatternUtils.LOCKSCREEN_OPTIONS,
919         LockPatternUtils.LOCKSCREEN_BIOMETRIC_WEAK_FALLBACK,
920         LockPatternUtils.BIOMETRIC_WEAK_EVER_CHOSEN_KEY,
921         LockPatternUtils.LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS,
922         LockPatternUtils.PASSWORD_HISTORY_KEY,
923         Secure.LOCK_PATTERN_ENABLED,
924         Secure.LOCK_BIOMETRIC_WEAK_FLAGS,
925         Secure.LOCK_PATTERN_VISIBLE,
926         Secure.LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED
927     };
928
929     // Reading these settings needs the contacts permission
930     private static final String[] READ_CONTACTS_PROTECTED_SETTINGS = new String[] {
931         Secure.LOCK_SCREEN_OWNER_INFO_ENABLED,
932         Secure.LOCK_SCREEN_OWNER_INFO
933     };
934
935     // Reading these settings needs the same permission as checking the password
936     private static final String[] READ_PASSWORD_PROTECTED_SETTINGS = new String[] {
937             LockPatternUtils.LOCK_PASSWORD_SALT_KEY,
938             LockPatternUtils.PASSWORD_HISTORY_KEY,
939             LockPatternUtils.PASSWORD_TYPE_KEY,
940     };
941
942     private static final String[] SETTINGS_TO_BACKUP = new String[] {
943         Secure.LOCK_SCREEN_OWNER_INFO_ENABLED,
944         Secure.LOCK_SCREEN_OWNER_INFO
945     };
946
947     private IMountService getMountService() {
948         final IBinder service = ServiceManager.getService("mount");
949         if (service != null) {
950             return IMountService.Stub.asInterface(service);
951         }
952         return null;
953     }
954
955     private class GateKeeperDiedRecipient implements IBinder.DeathRecipient {
956         @Override
957         public void binderDied() {
958             mGateKeeperService.asBinder().unlinkToDeath(this, 0);
959             mGateKeeperService = null;
960         }
961     }
962
963     private synchronized IGateKeeperService getGateKeeperService()
964             throws RemoteException {
965         if (mGateKeeperService != null) {
966             return mGateKeeperService;
967         }
968
969         final IBinder service =
970             ServiceManager.getService("android.service.gatekeeper.IGateKeeperService");
971         if (service != null) {
972             service.linkToDeath(new GateKeeperDiedRecipient(), 0);
973             mGateKeeperService = IGateKeeperService.Stub.asInterface(service);
974             return mGateKeeperService;
975         }
976
977         Slog.e(TAG, "Unable to acquire GateKeeperService");
978         return null;
979     }
980 }