1 /*
2  * Copyright (C) 2007 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.internal.widget;
18 
19 import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC;
20 import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC;
21 import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
22 import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_MANAGED;
23 import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
24 import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX;
25 import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
26 import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
27 
28 import android.annotation.IntDef;
29 import android.annotation.Nullable;
30 import android.app.admin.DevicePolicyManager;
31 import android.app.admin.PasswordMetrics;
32 import android.app.trust.IStrongAuthTracker;
33 import android.app.trust.TrustManager;
34 import android.content.ComponentName;
35 import android.content.ContentResolver;
36 import android.content.Context;
37 import android.content.pm.UserInfo;
38 import android.os.AsyncTask;
39 import android.os.Handler;
40 import android.os.IBinder;
41 import android.os.Looper;
42 import android.os.Message;
43 import android.os.RemoteException;
44 import android.os.ServiceManager;
45 import android.os.SystemClock;
46 import android.os.UserHandle;
47 import android.os.UserManager;
48 import android.os.storage.IStorageManager;
49 import android.os.storage.StorageManager;
50 import android.provider.Settings;
51 import android.text.TextUtils;
52 import android.util.Log;
53 import android.util.SparseIntArray;
54 import android.util.SparseLongArray;
55 
56 import com.android.internal.annotations.VisibleForTesting;
57 import com.android.server.LocalServices;
58 import com.google.android.collect.Lists;
59 
60 import libcore.util.HexEncoding;
61 
62 import java.lang.annotation.Retention;
63 import java.lang.annotation.RetentionPolicy;
64 import java.nio.charset.StandardCharsets;
65 import java.security.MessageDigest;
66 import java.security.NoSuchAlgorithmException;
67 import java.security.SecureRandom;
68 import java.util.ArrayList;
69 import java.util.Arrays;
70 import java.util.Collection;
71 import java.util.List;
72 import java.util.StringJoiner;
73 /**
74  * Utilities for the lock pattern and its settings.
75  */
76 public class LockPatternUtils {
77 
78     private static final String TAG = "LockPatternUtils";
79     private static final boolean DEBUG = false;
80     private static final boolean FRP_CREDENTIAL_ENABLED = true;
81 
82     /**
83      * The key to identify when the lock pattern enabled flag is being accessed for legacy reasons.
84      */
85     public static final String LEGACY_LOCK_PATTERN_ENABLED = "legacy_lock_pattern_enabled";
86 
87     /**
88      * The number of incorrect attempts before which we fall back on an alternative
89      * method of verifying the user, and resetting their lock pattern.
90      */
91     public static final int FAILED_ATTEMPTS_BEFORE_RESET = 20;
92 
93     /**
94      * The interval of the countdown for showing progress of the lockout.
95      */
96     public static final long FAILED_ATTEMPT_COUNTDOWN_INTERVAL_MS = 1000L;
97 
98 
99     /**
100      * This dictates when we start telling the user that continued failed attempts will wipe
101      * their device.
102      */
103     public static final int FAILED_ATTEMPTS_BEFORE_WIPE_GRACE = 5;
104 
105     /**
106      * The minimum number of dots in a valid pattern.
107      */
108     public static final int MIN_LOCK_PATTERN_SIZE = 4;
109 
110     /**
111      * The minimum size of a valid password.
112      */
113     public static final int MIN_LOCK_PASSWORD_SIZE = 4;
114 
115     /**
116      * The minimum number of dots the user must include in a wrong pattern
117      * attempt for it to be counted against the counts that affect
118      * {@link #FAILED_ATTEMPTS_BEFORE_TIMEOUT} and {@link #FAILED_ATTEMPTS_BEFORE_RESET}
119      */
120     public static final int MIN_PATTERN_REGISTER_FAIL = MIN_LOCK_PATTERN_SIZE;
121 
122     public static final int CREDENTIAL_TYPE_NONE = -1;
123 
124     public static final int CREDENTIAL_TYPE_PATTERN = 1;
125 
126     public static final int CREDENTIAL_TYPE_PASSWORD = 2;
127 
128     /**
129      * Special user id for triggering the FRP verification flow.
130      */
131     public static final int USER_FRP = UserHandle.USER_NULL + 1;
132 
133     @Deprecated
134     public final static String LOCKOUT_PERMANENT_KEY = "lockscreen.lockedoutpermanently";
135     public final static String PATTERN_EVER_CHOSEN_KEY = "lockscreen.patterneverchosen";
136     public final static String PASSWORD_TYPE_KEY = "lockscreen.password_type";
137     @Deprecated
138     public final static String PASSWORD_TYPE_ALTERNATE_KEY = "lockscreen.password_type_alternate";
139     public final static String LOCK_PASSWORD_SALT_KEY = "lockscreen.password_salt";
140     public final static String DISABLE_LOCKSCREEN_KEY = "lockscreen.disabled";
141     public final static String LOCKSCREEN_OPTIONS = "lockscreen.options";
142     @Deprecated
143     public final static String LOCKSCREEN_BIOMETRIC_WEAK_FALLBACK
144             = "lockscreen.biometric_weak_fallback";
145     @Deprecated
146     public final static String BIOMETRIC_WEAK_EVER_CHOSEN_KEY
147             = "lockscreen.biometricweakeverchosen";
148     public final static String LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS
149             = "lockscreen.power_button_instantly_locks";
150     @Deprecated
151     public final static String LOCKSCREEN_WIDGETS_ENABLED = "lockscreen.widgets_enabled";
152 
153     public final static String PASSWORD_HISTORY_KEY = "lockscreen.passwordhistory";
154 
155     private static final String LOCK_SCREEN_OWNER_INFO = Settings.Secure.LOCK_SCREEN_OWNER_INFO;
156     private static final String LOCK_SCREEN_OWNER_INFO_ENABLED =
157             Settings.Secure.LOCK_SCREEN_OWNER_INFO_ENABLED;
158 
159     private static final String LOCK_SCREEN_DEVICE_OWNER_INFO = "lockscreen.device_owner_info";
160 
161     private static final String ENABLED_TRUST_AGENTS = "lockscreen.enabledtrustagents";
162     private static final String IS_TRUST_USUALLY_MANAGED = "lockscreen.istrustusuallymanaged";
163 
164     public static final String PROFILE_KEY_NAME_ENCRYPT = "profile_key_name_encrypt_";
165     public static final String PROFILE_KEY_NAME_DECRYPT = "profile_key_name_decrypt_";
166     public static final String SYNTHETIC_PASSWORD_KEY_PREFIX = "synthetic_password_";
167 
168     public static final String SYNTHETIC_PASSWORD_HANDLE_KEY = "sp-handle";
169     public static final String SYNTHETIC_PASSWORD_ENABLED_KEY = "enable-sp";
170     private static final String HISTORY_DELIMITER = ",";
171 
172     private final Context mContext;
173     private final ContentResolver mContentResolver;
174     private DevicePolicyManager mDevicePolicyManager;
175     private ILockSettings mLockSettingsService;
176     private UserManager mUserManager;
177     private final Handler mHandler;
178     private final SparseLongArray mLockoutDeadlines = new SparseLongArray();
179 
180     /**
181      * Use {@link TrustManager#isTrustUsuallyManaged(int)}.
182      *
183      * This returns the lazily-peristed value and should only be used by TrustManagerService.
184      */
isTrustUsuallyManaged(int userId)185     public boolean isTrustUsuallyManaged(int userId) {
186         if (!(mLockSettingsService instanceof ILockSettings.Stub)) {
187             throw new IllegalStateException("May only be called by TrustManagerService. "
188                     + "Use TrustManager.isTrustUsuallyManaged()");
189         }
190         try {
191             return getLockSettings().getBoolean(IS_TRUST_USUALLY_MANAGED, false, userId);
192         } catch (RemoteException e) {
193             return false;
194         }
195     }
196 
setTrustUsuallyManaged(boolean managed, int userId)197     public void setTrustUsuallyManaged(boolean managed, int userId) {
198         try {
199             getLockSettings().setBoolean(IS_TRUST_USUALLY_MANAGED, managed, userId);
200         } catch (RemoteException e) {
201             // System dead.
202         }
203     }
204 
userPresent(int userId)205     public void userPresent(int userId) {
206         try {
207             getLockSettings().userPresent(userId);
208         } catch (RemoteException e) {
209             throw e.rethrowFromSystemServer();
210         }
211     }
212 
213     public static final class RequestThrottledException extends Exception {
214         private int mTimeoutMs;
RequestThrottledException(int timeoutMs)215         public RequestThrottledException(int timeoutMs) {
216             mTimeoutMs = timeoutMs;
217         }
218 
219         /**
220          * @return The amount of time in ms before another request may
221          * be executed
222          */
getTimeoutMs()223         public int getTimeoutMs() {
224             return mTimeoutMs;
225         }
226 
227     }
228 
getDevicePolicyManager()229     public DevicePolicyManager getDevicePolicyManager() {
230         if (mDevicePolicyManager == null) {
231             mDevicePolicyManager =
232                 (DevicePolicyManager)mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
233             if (mDevicePolicyManager == null) {
234                 Log.e(TAG, "Can't get DevicePolicyManagerService: is it running?",
235                         new IllegalStateException("Stack trace:"));
236             }
237         }
238         return mDevicePolicyManager;
239     }
240 
getUserManager()241     private UserManager getUserManager() {
242         if (mUserManager == null) {
243             mUserManager = UserManager.get(mContext);
244         }
245         return mUserManager;
246     }
247 
getTrustManager()248     private TrustManager getTrustManager() {
249         TrustManager trust = (TrustManager) mContext.getSystemService(Context.TRUST_SERVICE);
250         if (trust == null) {
251             Log.e(TAG, "Can't get TrustManagerService: is it running?",
252                     new IllegalStateException("Stack trace:"));
253         }
254         return trust;
255     }
256 
LockPatternUtils(Context context)257     public LockPatternUtils(Context context) {
258         mContext = context;
259         mContentResolver = context.getContentResolver();
260 
261         Looper looper = Looper.myLooper();
262         mHandler = looper != null ? new Handler(looper) : null;
263     }
264 
265     @VisibleForTesting
getLockSettings()266     public ILockSettings getLockSettings() {
267         if (mLockSettingsService == null) {
268             ILockSettings service = ILockSettings.Stub.asInterface(
269                     ServiceManager.getService("lock_settings"));
270             mLockSettingsService = service;
271         }
272         return mLockSettingsService;
273     }
274 
getRequestedMinimumPasswordLength(int userId)275     public int getRequestedMinimumPasswordLength(int userId) {
276         return getDevicePolicyManager().getPasswordMinimumLength(null, userId);
277     }
278 
279     /**
280      * Gets the device policy password mode. If the mode is non-specific, returns
281      * MODE_PATTERN which allows the user to choose anything.
282      */
getRequestedPasswordQuality(int userId)283     public int getRequestedPasswordQuality(int userId) {
284         return getDevicePolicyManager().getPasswordQuality(null, userId);
285     }
286 
getRequestedPasswordHistoryLength(int userId)287     private int getRequestedPasswordHistoryLength(int userId) {
288         return getDevicePolicyManager().getPasswordHistoryLength(null, userId);
289     }
290 
getRequestedPasswordMinimumLetters(int userId)291     public int getRequestedPasswordMinimumLetters(int userId) {
292         return getDevicePolicyManager().getPasswordMinimumLetters(null, userId);
293     }
294 
getRequestedPasswordMinimumUpperCase(int userId)295     public int getRequestedPasswordMinimumUpperCase(int userId) {
296         return getDevicePolicyManager().getPasswordMinimumUpperCase(null, userId);
297     }
298 
getRequestedPasswordMinimumLowerCase(int userId)299     public int getRequestedPasswordMinimumLowerCase(int userId) {
300         return getDevicePolicyManager().getPasswordMinimumLowerCase(null, userId);
301     }
302 
getRequestedPasswordMinimumNumeric(int userId)303     public int getRequestedPasswordMinimumNumeric(int userId) {
304         return getDevicePolicyManager().getPasswordMinimumNumeric(null, userId);
305     }
306 
getRequestedPasswordMinimumSymbols(int userId)307     public int getRequestedPasswordMinimumSymbols(int userId) {
308         return getDevicePolicyManager().getPasswordMinimumSymbols(null, userId);
309     }
310 
getRequestedPasswordMinimumNonLetter(int userId)311     public int getRequestedPasswordMinimumNonLetter(int userId) {
312         return getDevicePolicyManager().getPasswordMinimumNonLetter(null, userId);
313     }
314 
reportFailedPasswordAttempt(int userId)315     public void reportFailedPasswordAttempt(int userId) {
316         if (userId == USER_FRP && frpCredentialEnabled(mContext)) {
317             return;
318         }
319         getDevicePolicyManager().reportFailedPasswordAttempt(userId);
320         getTrustManager().reportUnlockAttempt(false /* authenticated */, userId);
321     }
322 
reportSuccessfulPasswordAttempt(int userId)323     public void reportSuccessfulPasswordAttempt(int userId) {
324         if (userId == USER_FRP && frpCredentialEnabled(mContext)) {
325             return;
326         }
327         getDevicePolicyManager().reportSuccessfulPasswordAttempt(userId);
328         getTrustManager().reportUnlockAttempt(true /* authenticated */, userId);
329     }
330 
reportPasswordLockout(int timeoutMs, int userId)331     public void reportPasswordLockout(int timeoutMs, int userId) {
332         if (userId == USER_FRP && frpCredentialEnabled(mContext)) {
333             return;
334         }
335         getTrustManager().reportUnlockLockout(timeoutMs, userId);
336     }
337 
getCurrentFailedPasswordAttempts(int userId)338     public int getCurrentFailedPasswordAttempts(int userId) {
339         if (userId == USER_FRP && frpCredentialEnabled(mContext)) {
340             return 0;
341         }
342         return getDevicePolicyManager().getCurrentFailedPasswordAttempts(userId);
343     }
344 
getMaximumFailedPasswordsForWipe(int userId)345     public int getMaximumFailedPasswordsForWipe(int userId) {
346         if (userId == USER_FRP && frpCredentialEnabled(mContext)) {
347             return 0;
348         }
349         return getDevicePolicyManager().getMaximumFailedPasswordsForWipe(
350                 null /* componentName */, userId);
351     }
352 
verifyCredential(String credential, int type, long challenge, int userId)353     private byte[] verifyCredential(String credential, int type, long challenge, int userId)
354             throws RequestThrottledException {
355         try {
356             VerifyCredentialResponse response = getLockSettings().verifyCredential(credential,
357                     type, challenge, userId);
358             if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
359                 return response.getPayload();
360             } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {
361                 throw new RequestThrottledException(response.getTimeout());
362             } else {
363                 return null;
364             }
365         } catch (RemoteException re) {
366             return null;
367         }
368     }
369 
checkCredential(String credential, int type, int userId, @Nullable CheckCredentialProgressCallback progressCallback)370     private boolean checkCredential(String credential, int type, int userId,
371             @Nullable CheckCredentialProgressCallback progressCallback)
372             throws RequestThrottledException {
373         try {
374             VerifyCredentialResponse response = getLockSettings().checkCredential(credential, type,
375                     userId, wrapCallback(progressCallback));
376 
377             if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
378                 return true;
379             } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {
380                 throw new RequestThrottledException(response.getTimeout());
381             } else {
382                 return false;
383             }
384         } catch (RemoteException re) {
385             return false;
386         }
387     }
388 
389     /**
390      * Check to see if a pattern matches the saved pattern.
391      * If pattern matches, return an opaque attestation that the challenge
392      * was verified.
393      *
394      * @param pattern The pattern to check.
395      * @param challenge The challenge to verify against the pattern
396      * @return the attestation that the challenge was verified, or null.
397      */
verifyPattern(List<LockPatternView.Cell> pattern, long challenge, int userId)398     public byte[] verifyPattern(List<LockPatternView.Cell> pattern, long challenge, int userId)
399             throws RequestThrottledException {
400         throwIfCalledOnMainThread();
401         return verifyCredential(patternToString(pattern), CREDENTIAL_TYPE_PATTERN, challenge,
402                 userId);
403     }
404 
405     /**
406      * Check to see if a pattern matches the saved pattern.  If no pattern exists,
407      * always returns true.
408      * @param pattern The pattern to check.
409      * @return Whether the pattern matches the stored one.
410      */
checkPattern(List<LockPatternView.Cell> pattern, int userId)411     public boolean checkPattern(List<LockPatternView.Cell> pattern, int userId)
412             throws RequestThrottledException {
413         return checkPattern(pattern, userId, null /* progressCallback */);
414     }
415 
416     /**
417      * Check to see if a pattern matches the saved pattern.  If no pattern exists,
418      * always returns true.
419      * @param pattern The pattern to check.
420      * @return Whether the pattern matches the stored one.
421      */
checkPattern(List<LockPatternView.Cell> pattern, int userId, @Nullable CheckCredentialProgressCallback progressCallback)422     public boolean checkPattern(List<LockPatternView.Cell> pattern, int userId,
423             @Nullable CheckCredentialProgressCallback progressCallback)
424             throws RequestThrottledException {
425         throwIfCalledOnMainThread();
426         return checkCredential(patternToString(pattern), CREDENTIAL_TYPE_PATTERN, userId,
427                 progressCallback);
428     }
429 
430     /**
431      * Check to see if a password matches the saved password.
432      * If password matches, return an opaque attestation that the challenge
433      * was verified.
434      *
435      * @param password The password to check.
436      * @param challenge The challenge to verify against the password
437      * @return the attestation that the challenge was verified, or null.
438      */
verifyPassword(String password, long challenge, int userId)439     public byte[] verifyPassword(String password, long challenge, int userId)
440             throws RequestThrottledException {
441         throwIfCalledOnMainThread();
442         return verifyCredential(password, CREDENTIAL_TYPE_PASSWORD, challenge, userId);
443     }
444 
445 
446     /**
447      * Check to see if a password matches the saved password.
448      * If password matches, return an opaque attestation that the challenge
449      * was verified.
450      *
451      * @param password The password to check.
452      * @param challenge The challenge to verify against the password
453      * @return the attestation that the challenge was verified, or null.
454      */
verifyTiedProfileChallenge(String password, boolean isPattern, long challenge, int userId)455     public byte[] verifyTiedProfileChallenge(String password, boolean isPattern, long challenge,
456             int userId) throws RequestThrottledException {
457         throwIfCalledOnMainThread();
458         try {
459             VerifyCredentialResponse response =
460                     getLockSettings().verifyTiedProfileChallenge(password,
461                             isPattern ? CREDENTIAL_TYPE_PATTERN : CREDENTIAL_TYPE_PASSWORD, challenge,
462                             userId);
463 
464             if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
465                 return response.getPayload();
466             } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {
467                 throw new RequestThrottledException(response.getTimeout());
468             } else {
469                 return null;
470             }
471         } catch (RemoteException re) {
472             return null;
473         }
474     }
475 
476     /**
477      * Check to see if a password matches the saved password.  If no password exists,
478      * always returns true.
479      * @param password The password to check.
480      * @return Whether the password matches the stored one.
481      */
checkPassword(String password, int userId)482     public boolean checkPassword(String password, int userId) throws RequestThrottledException {
483         return checkPassword(password, userId, null /* progressCallback */);
484     }
485 
486     /**
487      * Check to see if a password matches the saved password.  If no password exists,
488      * always returns true.
489      * @param password The password to check.
490      * @return Whether the password matches the stored one.
491      */
checkPassword(String password, int userId, @Nullable CheckCredentialProgressCallback progressCallback)492     public boolean checkPassword(String password, int userId,
493             @Nullable CheckCredentialProgressCallback progressCallback)
494             throws RequestThrottledException {
495         throwIfCalledOnMainThread();
496         return checkCredential(password, CREDENTIAL_TYPE_PASSWORD, userId, progressCallback);
497     }
498 
499     /**
500      * Check to see if vold already has the password.
501      * Note that this also clears vold's copy of the password.
502      * @return Whether the vold password matches or not.
503      */
checkVoldPassword(int userId)504     public boolean checkVoldPassword(int userId) {
505         try {
506             return getLockSettings().checkVoldPassword(userId);
507         } catch (RemoteException re) {
508             return false;
509         }
510     }
511 
512     /**
513      * Returns the password history hash factor, needed to check new password against password
514      * history with {@link #checkPasswordHistory(String, byte[], int)}
515      */
getPasswordHistoryHashFactor(String currentPassword, int userId)516     public byte[] getPasswordHistoryHashFactor(String currentPassword, int userId) {
517         try {
518             return getLockSettings().getHashFactor(currentPassword, userId);
519         } catch (RemoteException e) {
520             Log.e(TAG, "failed to get hash factor", e);
521             return null;
522         }
523     }
524 
525     /**
526      * Check to see if a password matches any of the passwords stored in the
527      * password history.
528      *
529      * @param passwordToCheck The password to check.
530      * @param hashFactor Hash factor of the current user returned from
531      *        {@link ILockSettings#getHashFactor}
532      * @return Whether the password matches any in the history.
533      */
checkPasswordHistory(String passwordToCheck, byte[] hashFactor, int userId)534     public boolean checkPasswordHistory(String passwordToCheck, byte[] hashFactor, int userId) {
535         if (TextUtils.isEmpty(passwordToCheck)) {
536             Log.e(TAG, "checkPasswordHistory: empty password");
537             return false;
538         }
539         String passwordHistory = getString(PASSWORD_HISTORY_KEY, userId);
540         if (TextUtils.isEmpty(passwordHistory)) {
541             return false;
542         }
543         int passwordHistoryLength = getRequestedPasswordHistoryLength(userId);
544         if(passwordHistoryLength == 0) {
545             return false;
546         }
547         String legacyHash = legacyPasswordToHash(passwordToCheck, userId);
548         String passwordHash = passwordToHistoryHash(passwordToCheck, hashFactor, userId);
549         String[] history = passwordHistory.split(HISTORY_DELIMITER);
550         // Password History may be too long...
551         for (int i = 0; i < Math.min(passwordHistoryLength, history.length); i++) {
552             if (history[i].equals(legacyHash) || history[i].equals(passwordHash)) {
553                 return true;
554             }
555         }
556         return false;
557     }
558 
559     /**
560      * Check to see if the user has stored a lock pattern.
561      * @return Whether a saved pattern exists.
562      */
savedPatternExists(int userId)563     private boolean savedPatternExists(int userId) {
564         try {
565             return getLockSettings().havePattern(userId);
566         } catch (RemoteException re) {
567             return false;
568         }
569     }
570 
571     /**
572      * Check to see if the user has stored a lock pattern.
573      * @return Whether a saved pattern exists.
574      */
savedPasswordExists(int userId)575     private boolean savedPasswordExists(int userId) {
576         try {
577             return getLockSettings().havePassword(userId);
578         } catch (RemoteException re) {
579             return false;
580         }
581     }
582 
583     /**
584      * Return true if the user has ever chosen a pattern.  This is true even if the pattern is
585      * currently cleared.
586      *
587      * @return True if the user has ever chosen a pattern.
588      */
isPatternEverChosen(int userId)589     public boolean isPatternEverChosen(int userId) {
590         return getBoolean(PATTERN_EVER_CHOSEN_KEY, false, userId);
591     }
592 
593     /**
594      * Records that the user has chosen a pattern at some time, even if the pattern is
595      * currently cleared.
596      */
reportPatternWasChosen(int userId)597     public void reportPatternWasChosen(int userId) {
598         setBoolean(PATTERN_EVER_CHOSEN_KEY, true, userId);
599     }
600 
601     /**
602      * Used by device policy manager to validate the current password
603      * information it has.
604      */
getActivePasswordQuality(int userId)605     public int getActivePasswordQuality(int userId) {
606         int quality = getKeyguardStoredPasswordQuality(userId);
607 
608         if (isLockPasswordEnabled(quality, userId)) {
609             // Quality is a password and a password exists. Return the quality.
610             return quality;
611         }
612 
613         if (isLockPatternEnabled(quality, userId)) {
614             // Quality is a pattern and a pattern exists. Return the quality.
615             return quality;
616         }
617 
618         return PASSWORD_QUALITY_UNSPECIFIED;
619     }
620 
621     /**
622      * Use it to reset keystore without wiping work profile
623      */
resetKeyStore(int userId)624     public void resetKeyStore(int userId) {
625         try {
626             getLockSettings().resetKeyStore(userId);
627         } catch (RemoteException e) {
628             // It should not happen
629             Log.e(TAG, "Couldn't reset keystore " + e);
630         }
631     }
632 
633     /**
634      * Clear any lock pattern or password.
635      */
clearLock(String savedCredential, int userHandle)636     public void clearLock(String savedCredential, int userHandle) {
637         final int currentQuality = getKeyguardStoredPasswordQuality(userHandle);
638         setKeyguardStoredPasswordQuality(PASSWORD_QUALITY_UNSPECIFIED, userHandle);
639 
640         try{
641             getLockSettings().setLockCredential(null, CREDENTIAL_TYPE_NONE, savedCredential,
642                     PASSWORD_QUALITY_UNSPECIFIED, userHandle);
643         } catch (Exception e) {
644             Log.e(TAG, "Failed to clear lock", e);
645             setKeyguardStoredPasswordQuality(currentQuality, userHandle);
646             return;
647         }
648 
649         if (userHandle == UserHandle.USER_SYSTEM) {
650             // Set the encryption password to default.
651             updateEncryptionPassword(StorageManager.CRYPT_TYPE_DEFAULT, null);
652             setCredentialRequiredToDecrypt(false);
653         }
654 
655         onAfterChangingPassword(userHandle);
656     }
657 
658     /**
659      * Disable showing lock screen at all for a given user.
660      * This is only meaningful if pattern, pin or password are not set.
661      *
662      * @param disable Disables lock screen when true
663      * @param userId User ID of the user this has effect on
664      */
setLockScreenDisabled(boolean disable, int userId)665     public void setLockScreenDisabled(boolean disable, int userId) {
666         setBoolean(DISABLE_LOCKSCREEN_KEY, disable, userId);
667     }
668 
669     /**
670      * Determine if LockScreen is disabled for the current user. This is used to decide whether
671      * LockScreen is shown after reboot or after screen timeout / short press on power.
672      *
673      * @return true if lock screen is disabled
674      */
isLockScreenDisabled(int userId)675     public boolean isLockScreenDisabled(int userId) {
676         if (isSecure(userId)) {
677             return false;
678         }
679         boolean disabledByDefault = mContext.getResources().getBoolean(
680                 com.android.internal.R.bool.config_disableLockscreenByDefault);
681         boolean isSystemUser = UserManager.isSplitSystemUser() && userId == UserHandle.USER_SYSTEM;
682         UserInfo userInfo = getUserManager().getUserInfo(userId);
683         boolean isDemoUser = UserManager.isDeviceInDemoMode(mContext) && userInfo != null
684                 && userInfo.isDemo();
685         return getBoolean(DISABLE_LOCKSCREEN_KEY, false, userId)
686                 || (disabledByDefault && !isSystemUser)
687                 || isDemoUser;
688     }
689 
690     /**
691      * Save a lock pattern.
692      * @param pattern The new pattern to save.
693      * @param userId the user whose pattern is to be saved.
694      */
saveLockPattern(List<LockPatternView.Cell> pattern, int userId)695     public void saveLockPattern(List<LockPatternView.Cell> pattern, int userId) {
696         this.saveLockPattern(pattern, null, userId);
697     }
698     /**
699      * Save a lock pattern.
700      * @param pattern The new pattern to save.
701      * @param savedPattern The previously saved pattern, converted to String format
702      * @param userId the user whose pattern is to be saved.
703      */
saveLockPattern(List<LockPatternView.Cell> pattern, String savedPattern, int userId)704     public void saveLockPattern(List<LockPatternView.Cell> pattern, String savedPattern, int userId) {
705         if (pattern == null || pattern.size() < MIN_LOCK_PATTERN_SIZE) {
706             throw new IllegalArgumentException("pattern must not be null and at least "
707                     + MIN_LOCK_PATTERN_SIZE + " dots long.");
708         }
709 
710         final String stringPattern = patternToString(pattern);
711         final int currentQuality = getKeyguardStoredPasswordQuality(userId);
712         setKeyguardStoredPasswordQuality(PASSWORD_QUALITY_SOMETHING, userId);
713         try {
714             getLockSettings().setLockCredential(stringPattern, CREDENTIAL_TYPE_PATTERN,
715                     savedPattern, PASSWORD_QUALITY_SOMETHING, userId);
716         } catch (Exception e) {
717             Log.e(TAG, "Couldn't save lock pattern", e);
718             setKeyguardStoredPasswordQuality(currentQuality, userId);
719             return;
720         }
721         // Update the device encryption password.
722         if (userId == UserHandle.USER_SYSTEM
723                 && LockPatternUtils.isDeviceEncryptionEnabled()) {
724             if (!shouldEncryptWithCredentials(true)) {
725                 clearEncryptionPassword();
726             } else {
727                 updateEncryptionPassword(StorageManager.CRYPT_TYPE_PATTERN, stringPattern);
728             }
729         }
730 
731         reportPatternWasChosen(userId);
732         onAfterChangingPassword(userId);
733     }
734 
updateCryptoUserInfo(int userId)735     private void updateCryptoUserInfo(int userId) {
736         if (userId != UserHandle.USER_SYSTEM) {
737             return;
738         }
739 
740         final String ownerInfo = isOwnerInfoEnabled(userId) ? getOwnerInfo(userId) : "";
741 
742         IBinder service = ServiceManager.getService("mount");
743         if (service == null) {
744             Log.e(TAG, "Could not find the mount service to update the user info");
745             return;
746         }
747 
748         IStorageManager storageManager = IStorageManager.Stub.asInterface(service);
749         try {
750             Log.d(TAG, "Setting owner info");
751             storageManager.setField(StorageManager.OWNER_INFO_KEY, ownerInfo);
752         } catch (RemoteException e) {
753             Log.e(TAG, "Error changing user info", e);
754         }
755     }
756 
setOwnerInfo(String info, int userId)757     public void setOwnerInfo(String info, int userId) {
758         setString(LOCK_SCREEN_OWNER_INFO, info, userId);
759         updateCryptoUserInfo(userId);
760     }
761 
setOwnerInfoEnabled(boolean enabled, int userId)762     public void setOwnerInfoEnabled(boolean enabled, int userId) {
763         setBoolean(LOCK_SCREEN_OWNER_INFO_ENABLED, enabled, userId);
764         updateCryptoUserInfo(userId);
765     }
766 
getOwnerInfo(int userId)767     public String getOwnerInfo(int userId) {
768         return getString(LOCK_SCREEN_OWNER_INFO, userId);
769     }
770 
isOwnerInfoEnabled(int userId)771     public boolean isOwnerInfoEnabled(int userId) {
772         return getBoolean(LOCK_SCREEN_OWNER_INFO_ENABLED, false, userId);
773     }
774 
775     /**
776      * Sets the device owner information. If the information is {@code null} or empty then the
777      * device owner info is cleared.
778      *
779      * @param info Device owner information which will be displayed instead of the user
780      * owner info.
781      */
setDeviceOwnerInfo(String info)782     public void setDeviceOwnerInfo(String info) {
783         if (info != null && info.isEmpty()) {
784             info = null;
785         }
786 
787         setString(LOCK_SCREEN_DEVICE_OWNER_INFO, info, UserHandle.USER_SYSTEM);
788     }
789 
getDeviceOwnerInfo()790     public String getDeviceOwnerInfo() {
791         return getString(LOCK_SCREEN_DEVICE_OWNER_INFO, UserHandle.USER_SYSTEM);
792     }
793 
isDeviceOwnerInfoEnabled()794     public boolean isDeviceOwnerInfoEnabled() {
795         return getDeviceOwnerInfo() != null;
796     }
797 
798     /** Update the encryption password if it is enabled **/
updateEncryptionPassword(final int type, final String password)799     private void updateEncryptionPassword(final int type, final String password) {
800         if (!isDeviceEncryptionEnabled()) {
801             return;
802         }
803         final IBinder service = ServiceManager.getService("mount");
804         if (service == null) {
805             Log.e(TAG, "Could not find the mount service to update the encryption password");
806             return;
807         }
808 
809         new AsyncTask<Void, Void, Void>() {
810             @Override
811             protected Void doInBackground(Void... dummy) {
812                 IStorageManager storageManager = IStorageManager.Stub.asInterface(service);
813                 try {
814                     storageManager.changeEncryptionPassword(type, password);
815                 } catch (RemoteException e) {
816                     Log.e(TAG, "Error changing encryption password", e);
817                 }
818                 return null;
819             }
820         }.execute();
821     }
822 
823     /**
824      * Save a lock password.  Does not ensure that the password is as good
825      * as the requested mode, but will adjust the mode to be as good as the
826      * password.
827      * @param password The password to save
828      * @param savedPassword The previously saved lock password, or null if none
829      * @param requestedQuality {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
830      * @param userHandle The userId of the user to change the password for
831      */
saveLockPassword(String password, String savedPassword, int requestedQuality, int userHandle)832     public void saveLockPassword(String password, String savedPassword, int requestedQuality,
833             int userHandle) {
834         if (password == null || password.length() < MIN_LOCK_PASSWORD_SIZE) {
835             throw new IllegalArgumentException("password must not be null and at least "
836                     + "of length " + MIN_LOCK_PASSWORD_SIZE);
837         }
838 
839         final int currentQuality = getKeyguardStoredPasswordQuality(userHandle);
840         setKeyguardStoredPasswordQuality(
841                 computePasswordQuality(CREDENTIAL_TYPE_PASSWORD, password, requestedQuality),
842                 userHandle);
843         try {
844             getLockSettings().setLockCredential(password, CREDENTIAL_TYPE_PASSWORD,
845                     savedPassword, requestedQuality, userHandle);
846         } catch (Exception e) {
847             Log.e(TAG, "Unable to save lock password", e);
848             setKeyguardStoredPasswordQuality(currentQuality, userHandle);
849             return;
850         }
851 
852         updateEncryptionPasswordIfNeeded(password,
853                 PasswordMetrics.computeForPassword(password).quality, userHandle);
854         updatePasswordHistory(password, userHandle);
855         onAfterChangingPassword(userHandle);
856     }
857 
858     /**
859      * Update device encryption password if calling user is USER_SYSTEM and device supports
860      * encryption.
861      */
updateEncryptionPasswordIfNeeded(String password, int quality, int userHandle)862     private void updateEncryptionPasswordIfNeeded(String password, int quality, int userHandle) {
863         // Update the device encryption password.
864         if (userHandle == UserHandle.USER_SYSTEM
865                 && LockPatternUtils.isDeviceEncryptionEnabled()) {
866             if (!shouldEncryptWithCredentials(true)) {
867                 clearEncryptionPassword();
868             } else {
869                 boolean numeric = quality == PASSWORD_QUALITY_NUMERIC;
870                 boolean numericComplex = quality == PASSWORD_QUALITY_NUMERIC_COMPLEX;
871                 int type = numeric || numericComplex ? StorageManager.CRYPT_TYPE_PIN
872                         : StorageManager.CRYPT_TYPE_PASSWORD;
873                 updateEncryptionPassword(type, password);
874             }
875         }
876     }
877 
878     /**
879      * Store the hash of the *current* password in the password history list, if device policy
880      * enforces password history requirement.
881      */
updatePasswordHistory(String password, int userHandle)882     private void updatePasswordHistory(String password, int userHandle) {
883         if (TextUtils.isEmpty(password)) {
884             Log.e(TAG, "checkPasswordHistory: empty password");
885             return;
886         }
887         // Add the password to the password history. We assume all
888         // password hashes have the same length for simplicity of implementation.
889         String passwordHistory = getString(PASSWORD_HISTORY_KEY, userHandle);
890         if (passwordHistory == null) {
891             passwordHistory = "";
892         }
893         int passwordHistoryLength = getRequestedPasswordHistoryLength(userHandle);
894         if (passwordHistoryLength == 0) {
895             passwordHistory = "";
896         } else {
897             final byte[] hashFactor = getPasswordHistoryHashFactor(password, userHandle);
898             String hash = passwordToHistoryHash(password, hashFactor, userHandle);
899             if (hash == null) {
900                 Log.e(TAG, "Compute new style password hash failed, fallback to legacy style");
901                 hash = legacyPasswordToHash(password, userHandle);
902             }
903             if (TextUtils.isEmpty(passwordHistory)) {
904                 passwordHistory = hash;
905             } else {
906                 String[] history = passwordHistory.split(HISTORY_DELIMITER);
907                 StringJoiner joiner = new StringJoiner(HISTORY_DELIMITER);
908                 joiner.add(hash);
909                 for (int i = 0; i < passwordHistoryLength - 1 && i < history.length; i++) {
910                     joiner.add(history[i]);
911                 }
912                 passwordHistory = joiner.toString();
913             }
914         }
915         setString(PASSWORD_HISTORY_KEY, passwordHistory, userHandle);
916     }
917 
918     /**
919      * Determine if the device supports encryption, even if it's set to default. This
920      * differs from isDeviceEncrypted() in that it returns true even if the device is
921      * encrypted with the default password.
922      * @return true if device encryption is enabled
923      */
isDeviceEncryptionEnabled()924     public static boolean isDeviceEncryptionEnabled() {
925         return StorageManager.isEncrypted();
926     }
927 
928     /**
929      * Determine if the device is file encrypted
930      * @return true if device is file encrypted
931      */
isFileEncryptionEnabled()932     public static boolean isFileEncryptionEnabled() {
933         return StorageManager.isFileEncryptedNativeOrEmulated();
934     }
935 
936     /**
937      * Clears the encryption password.
938      */
clearEncryptionPassword()939     public void clearEncryptionPassword() {
940         updateEncryptionPassword(StorageManager.CRYPT_TYPE_DEFAULT, null);
941     }
942 
943     /**
944      * Retrieves the quality mode for {@param userHandle}.
945      * {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
946      *
947      * @return stored password quality
948      */
getKeyguardStoredPasswordQuality(int userHandle)949     public int getKeyguardStoredPasswordQuality(int userHandle) {
950         return (int) getLong(PASSWORD_TYPE_KEY, PASSWORD_QUALITY_UNSPECIFIED, userHandle);
951     }
952 
setKeyguardStoredPasswordQuality(int quality, int userHandle)953     private void setKeyguardStoredPasswordQuality(int quality, int userHandle) {
954         setLong(PASSWORD_TYPE_KEY, quality, userHandle);
955     }
956 
957     /**
958      * Returns the password quality of the given credential, promoting it to a higher level
959      * if DevicePolicyManager has a stronger quality requirement. This value will be written
960      * to PASSWORD_TYPE_KEY.
961      */
computePasswordQuality(int type, String credential, int requestedQuality)962     private int computePasswordQuality(int type, String credential, int requestedQuality) {
963         final int quality;
964         if (type == CREDENTIAL_TYPE_PASSWORD) {
965             int computedQuality = PasswordMetrics.computeForPassword(credential).quality;
966             quality = Math.max(requestedQuality, computedQuality);
967         } else if (type == CREDENTIAL_TYPE_PATTERN)  {
968             quality = PASSWORD_QUALITY_SOMETHING;
969         } else /* if (type == CREDENTIAL_TYPE_NONE) */ {
970             quality = PASSWORD_QUALITY_UNSPECIFIED;
971         }
972         return quality;
973     }
974 
975     /**
976      * Enables/disables the Separate Profile Challenge for this {@param userHandle}. This is a no-op
977      * for user handles that do not belong to a managed profile.
978      *
979      * @param userHandle Managed profile user id
980      * @param enabled True if separate challenge is enabled
981      * @param managedUserPassword Managed profile previous password. Null when {@param enabled} is
982      *            true
983      */
setSeparateProfileChallengeEnabled(int userHandle, boolean enabled, String managedUserPassword)984     public void setSeparateProfileChallengeEnabled(int userHandle, boolean enabled,
985             String managedUserPassword) {
986         if (!isManagedProfile(userHandle)) {
987             return;
988         }
989         try {
990             getLockSettings().setSeparateProfileChallengeEnabled(userHandle, enabled,
991                     managedUserPassword);
992             onAfterChangingPassword(userHandle);
993         } catch (RemoteException e) {
994             Log.e(TAG, "Couldn't update work profile challenge enabled");
995         }
996     }
997 
998     /**
999      * Returns true if {@param userHandle} is a managed profile with separate challenge.
1000      */
isSeparateProfileChallengeEnabled(int userHandle)1001     public boolean isSeparateProfileChallengeEnabled(int userHandle) {
1002         return isManagedProfile(userHandle) && hasSeparateChallenge(userHandle);
1003     }
1004 
1005     /**
1006      * Returns true if {@param userHandle} is a managed profile with unified challenge.
1007      */
isManagedProfileWithUnifiedChallenge(int userHandle)1008     public boolean isManagedProfileWithUnifiedChallenge(int userHandle) {
1009         return isManagedProfile(userHandle) && !hasSeparateChallenge(userHandle);
1010     }
1011 
1012     /**
1013      * Retrieves whether the current DPM allows use of the Profile Challenge.
1014      */
isSeparateProfileChallengeAllowed(int userHandle)1015     public boolean isSeparateProfileChallengeAllowed(int userHandle) {
1016         return isManagedProfile(userHandle)
1017                 && getDevicePolicyManager().isSeparateProfileChallengeAllowed(userHandle);
1018     }
1019 
1020     /**
1021      * Retrieves whether the current profile and device locks can be unified.
1022      * @param userHandle profile user handle.
1023      */
isSeparateProfileChallengeAllowedToUnify(int userHandle)1024     public boolean isSeparateProfileChallengeAllowedToUnify(int userHandle) {
1025         return getDevicePolicyManager().isProfileActivePasswordSufficientForParent(userHandle)
1026                 && !getUserManager().hasUserRestriction(
1027                         UserManager.DISALLOW_UNIFIED_PASSWORD, UserHandle.of(userHandle));
1028     }
1029 
hasSeparateChallenge(int userHandle)1030     private boolean hasSeparateChallenge(int userHandle) {
1031         try {
1032             return getLockSettings().getSeparateProfileChallengeEnabled(userHandle);
1033         } catch (RemoteException e) {
1034             Log.e(TAG, "Couldn't get separate profile challenge enabled");
1035             // Default value is false
1036             return false;
1037         }
1038     }
1039 
isManagedProfile(int userHandle)1040     private boolean isManagedProfile(int userHandle) {
1041         final UserInfo info = getUserManager().getUserInfo(userHandle);
1042         return info != null && info.isManagedProfile();
1043     }
1044 
1045     /**
1046      * Deserialize a pattern.
1047      * @param string The pattern serialized with {@link #patternToString}
1048      * @return The pattern.
1049      */
stringToPattern(String string)1050     public static List<LockPatternView.Cell> stringToPattern(String string) {
1051         if (string == null) {
1052             return null;
1053         }
1054 
1055         List<LockPatternView.Cell> result = Lists.newArrayList();
1056 
1057         final byte[] bytes = string.getBytes();
1058         for (int i = 0; i < bytes.length; i++) {
1059             byte b = (byte) (bytes[i] - '1');
1060             result.add(LockPatternView.Cell.of(b / 3, b % 3));
1061         }
1062         return result;
1063     }
1064 
1065     /**
1066      * Serialize a pattern.
1067      * @param pattern The pattern.
1068      * @return The pattern in string form.
1069      */
patternToString(List<LockPatternView.Cell> pattern)1070     public static String patternToString(List<LockPatternView.Cell> pattern) {
1071         if (pattern == null) {
1072             return "";
1073         }
1074         final int patternSize = pattern.size();
1075 
1076         byte[] res = new byte[patternSize];
1077         for (int i = 0; i < patternSize; i++) {
1078             LockPatternView.Cell cell = pattern.get(i);
1079             res[i] = (byte) (cell.getRow() * 3 + cell.getColumn() + '1');
1080         }
1081         return new String(res);
1082     }
1083 
patternStringToBaseZero(String pattern)1084     public static String patternStringToBaseZero(String pattern) {
1085         if (pattern == null) {
1086             return "";
1087         }
1088         final int patternSize = pattern.length();
1089 
1090         byte[] res = new byte[patternSize];
1091         final byte[] bytes = pattern.getBytes();
1092         for (int i = 0; i < patternSize; i++) {
1093             res[i] = (byte) (bytes[i] - '1');
1094         }
1095         return new String(res);
1096     }
1097 
1098     /*
1099      * Generate an SHA-1 hash for the pattern. Not the most secure, but it is
1100      * at least a second level of protection. First level is that the file
1101      * is in a location only readable by the system process.
1102      * @param pattern the gesture pattern.
1103      * @return the hash of the pattern in a byte array.
1104      */
patternToHash(List<LockPatternView.Cell> pattern)1105     public static byte[] patternToHash(List<LockPatternView.Cell> pattern) {
1106         if (pattern == null) {
1107             return null;
1108         }
1109 
1110         final int patternSize = pattern.size();
1111         byte[] res = new byte[patternSize];
1112         for (int i = 0; i < patternSize; i++) {
1113             LockPatternView.Cell cell = pattern.get(i);
1114             res[i] = (byte) (cell.getRow() * 3 + cell.getColumn());
1115         }
1116         try {
1117             MessageDigest md = MessageDigest.getInstance("SHA-1");
1118             byte[] hash = md.digest(res);
1119             return hash;
1120         } catch (NoSuchAlgorithmException nsa) {
1121             return res;
1122         }
1123     }
1124 
getSalt(int userId)1125     private String getSalt(int userId) {
1126         long salt = getLong(LOCK_PASSWORD_SALT_KEY, 0, userId);
1127         if (salt == 0) {
1128             try {
1129                 salt = SecureRandom.getInstance("SHA1PRNG").nextLong();
1130                 setLong(LOCK_PASSWORD_SALT_KEY, salt, userId);
1131                 Log.v(TAG, "Initialized lock password salt for user: " + userId);
1132             } catch (NoSuchAlgorithmException e) {
1133                 // Throw an exception rather than storing a password we'll never be able to recover
1134                 throw new IllegalStateException("Couldn't get SecureRandom number", e);
1135             }
1136         }
1137         return Long.toHexString(salt);
1138     }
1139 
1140     /**
1141      * Generate a hash for the given password. To avoid brute force attacks, we use a salted hash.
1142      * Not the most secure, but it is at least a second level of protection. First level is that
1143      * the file is in a location only readable by the system process.
1144      *
1145      * @param password the gesture pattern.
1146      *
1147      * @return the hash of the pattern in a byte array.
1148      */
legacyPasswordToHash(String password, int userId)1149     public String legacyPasswordToHash(String password, int userId) {
1150         if (password == null) {
1151             return null;
1152         }
1153 
1154         try {
1155             byte[] saltedPassword = (password + getSalt(userId)).getBytes();
1156             byte[] sha1 = MessageDigest.getInstance("SHA-1").digest(saltedPassword);
1157             byte[] md5 = MessageDigest.getInstance("MD5").digest(saltedPassword);
1158 
1159             byte[] combined = new byte[sha1.length + md5.length];
1160             System.arraycopy(sha1, 0, combined, 0, sha1.length);
1161             System.arraycopy(md5, 0, combined, sha1.length, md5.length);
1162 
1163             final char[] hexEncoded = HexEncoding.encode(combined);
1164             return new String(hexEncoded);
1165         } catch (NoSuchAlgorithmException e) {
1166             throw new AssertionError("Missing digest algorithm: ", e);
1167         }
1168     }
1169 
1170     /**
1171      * Hash the password for password history check purpose.
1172      */
passwordToHistoryHash(String passwordToHash, byte[] hashFactor, int userId)1173     private String passwordToHistoryHash(String passwordToHash, byte[] hashFactor, int userId) {
1174         if (TextUtils.isEmpty(passwordToHash) || hashFactor == null) {
1175             return null;
1176         }
1177         try {
1178             MessageDigest sha256 = MessageDigest.getInstance("SHA-256");
1179             sha256.update(hashFactor);
1180             sha256.update((passwordToHash + getSalt(userId)).getBytes());
1181             return new String(HexEncoding.encode(sha256.digest()));
1182         } catch (NoSuchAlgorithmException e) {
1183             throw new AssertionError("Missing digest algorithm: ", e);
1184         }
1185     }
1186 
1187     /**
1188      * @param userId the user for which to report the value
1189      * @return Whether the lock screen is secured.
1190      */
isSecure(int userId)1191     public boolean isSecure(int userId) {
1192         int mode = getKeyguardStoredPasswordQuality(userId);
1193         return isLockPatternEnabled(mode, userId) || isLockPasswordEnabled(mode, userId);
1194     }
1195 
isLockPasswordEnabled(int userId)1196     public boolean isLockPasswordEnabled(int userId) {
1197         return isLockPasswordEnabled(getKeyguardStoredPasswordQuality(userId), userId);
1198     }
1199 
isLockPasswordEnabled(int mode, int userId)1200     private boolean isLockPasswordEnabled(int mode, int userId) {
1201         final boolean passwordEnabled = mode == PASSWORD_QUALITY_ALPHABETIC
1202                 || mode == PASSWORD_QUALITY_NUMERIC
1203                 || mode == PASSWORD_QUALITY_NUMERIC_COMPLEX
1204                 || mode == PASSWORD_QUALITY_ALPHANUMERIC
1205                 || mode == PASSWORD_QUALITY_COMPLEX
1206                 || mode == PASSWORD_QUALITY_MANAGED;
1207         return passwordEnabled && savedPasswordExists(userId);
1208     }
1209 
1210     /**
1211      * @return Whether the lock pattern is enabled
1212      */
isLockPatternEnabled(int userId)1213     public boolean isLockPatternEnabled(int userId) {
1214         return isLockPatternEnabled(getKeyguardStoredPasswordQuality(userId), userId);
1215     }
1216 
1217     @Deprecated
isLegacyLockPatternEnabled(int userId)1218     public boolean isLegacyLockPatternEnabled(int userId) {
1219         // Note: this value should default to {@code true} to avoid any reset that might result.
1220         // We must use a special key to read this value, since it will by default return the value
1221         // based on the new logic.
1222         return getBoolean(LEGACY_LOCK_PATTERN_ENABLED, true, userId);
1223     }
1224 
1225     @Deprecated
setLegacyLockPatternEnabled(int userId)1226     public void setLegacyLockPatternEnabled(int userId) {
1227         setBoolean(Settings.Secure.LOCK_PATTERN_ENABLED, true, userId);
1228     }
1229 
isLockPatternEnabled(int mode, int userId)1230     private boolean isLockPatternEnabled(int mode, int userId) {
1231         return mode == PASSWORD_QUALITY_SOMETHING && savedPatternExists(userId);
1232     }
1233 
1234     /**
1235      * @return Whether the visible pattern is enabled.
1236      */
isVisiblePatternEnabled(int userId)1237     public boolean isVisiblePatternEnabled(int userId) {
1238         return getBoolean(Settings.Secure.LOCK_PATTERN_VISIBLE, false, userId);
1239     }
1240 
1241     /**
1242      * Set whether the visible pattern is enabled.
1243      */
setVisiblePatternEnabled(boolean enabled, int userId)1244     public void setVisiblePatternEnabled(boolean enabled, int userId) {
1245         setBoolean(Settings.Secure.LOCK_PATTERN_VISIBLE, enabled, userId);
1246 
1247         // Update for crypto if owner
1248         if (userId != UserHandle.USER_SYSTEM) {
1249             return;
1250         }
1251 
1252         IBinder service = ServiceManager.getService("mount");
1253         if (service == null) {
1254             Log.e(TAG, "Could not find the mount service to update the user info");
1255             return;
1256         }
1257 
1258         IStorageManager storageManager = IStorageManager.Stub.asInterface(service);
1259         try {
1260             storageManager.setField(StorageManager.PATTERN_VISIBLE_KEY, enabled ? "1" : "0");
1261         } catch (RemoteException e) {
1262             Log.e(TAG, "Error changing pattern visible state", e);
1263         }
1264     }
1265 
isVisiblePatternEverChosen(int userId)1266     public boolean isVisiblePatternEverChosen(int userId) {
1267         return getString(Settings.Secure.LOCK_PATTERN_VISIBLE, userId) != null;
1268     }
1269 
1270     /**
1271      * Set whether the visible password is enabled for cryptkeeper screen.
1272      */
setVisiblePasswordEnabled(boolean enabled, int userId)1273     public void setVisiblePasswordEnabled(boolean enabled, int userId) {
1274         // Update for crypto if owner
1275         if (userId != UserHandle.USER_SYSTEM) {
1276             return;
1277         }
1278 
1279         IBinder service = ServiceManager.getService("mount");
1280         if (service == null) {
1281             Log.e(TAG, "Could not find the mount service to update the user info");
1282             return;
1283         }
1284 
1285         IStorageManager storageManager = IStorageManager.Stub.asInterface(service);
1286         try {
1287             storageManager.setField(StorageManager.PASSWORD_VISIBLE_KEY, enabled ? "1" : "0");
1288         } catch (RemoteException e) {
1289             Log.e(TAG, "Error changing password visible state", e);
1290         }
1291     }
1292 
1293     /**
1294      * @return Whether tactile feedback for the pattern is enabled.
1295      */
isTactileFeedbackEnabled()1296     public boolean isTactileFeedbackEnabled() {
1297         return Settings.System.getIntForUser(mContentResolver,
1298                 Settings.System.HAPTIC_FEEDBACK_ENABLED, 1, UserHandle.USER_CURRENT) != 0;
1299     }
1300 
1301     /**
1302      * Set and store the lockout deadline, meaning the user can't attempt his/her unlock
1303      * pattern until the deadline has passed.
1304      * @return the chosen deadline.
1305      */
setLockoutAttemptDeadline(int userId, int timeoutMs)1306     public long setLockoutAttemptDeadline(int userId, int timeoutMs) {
1307         final long deadline = SystemClock.elapsedRealtime() + timeoutMs;
1308         if (userId == USER_FRP) {
1309             // For secure password storage (that is required for FRP), the underlying storage also
1310             // enforces the deadline. Since we cannot store settings for the FRP user, don't.
1311             return deadline;
1312         }
1313         mLockoutDeadlines.put(userId, deadline);
1314         return deadline;
1315     }
1316 
1317     /**
1318      * @return The elapsed time in millis in the future when the user is allowed to
1319      *   attempt to enter his/her lock pattern, or 0 if the user is welcome to
1320      *   enter a pattern.
1321      */
getLockoutAttemptDeadline(int userId)1322     public long getLockoutAttemptDeadline(int userId) {
1323         final long deadline = mLockoutDeadlines.get(userId, 0L);
1324         final long now = SystemClock.elapsedRealtime();
1325         if (deadline < now && deadline != 0) {
1326             // timeout expired
1327             mLockoutDeadlines.put(userId, 0);
1328             return 0L;
1329         }
1330         return deadline;
1331     }
1332 
getBoolean(String secureSettingKey, boolean defaultValue, int userId)1333     private boolean getBoolean(String secureSettingKey, boolean defaultValue, int userId) {
1334         try {
1335             return getLockSettings().getBoolean(secureSettingKey, defaultValue, userId);
1336         } catch (RemoteException re) {
1337             return defaultValue;
1338         }
1339     }
1340 
setBoolean(String secureSettingKey, boolean enabled, int userId)1341     private void setBoolean(String secureSettingKey, boolean enabled, int userId) {
1342         try {
1343             getLockSettings().setBoolean(secureSettingKey, enabled, userId);
1344         } catch (RemoteException re) {
1345             // What can we do?
1346             Log.e(TAG, "Couldn't write boolean " + secureSettingKey + re);
1347         }
1348     }
1349 
getLong(String secureSettingKey, long defaultValue, int userHandle)1350     private long getLong(String secureSettingKey, long defaultValue, int userHandle) {
1351         try {
1352             return getLockSettings().getLong(secureSettingKey, defaultValue, userHandle);
1353         } catch (RemoteException re) {
1354             return defaultValue;
1355         }
1356     }
1357 
setLong(String secureSettingKey, long value, int userHandle)1358     private void setLong(String secureSettingKey, long value, int userHandle) {
1359         try {
1360             getLockSettings().setLong(secureSettingKey, value, userHandle);
1361         } catch (RemoteException re) {
1362             // What can we do?
1363             Log.e(TAG, "Couldn't write long " + secureSettingKey + re);
1364         }
1365     }
1366 
getString(String secureSettingKey, int userHandle)1367     private String getString(String secureSettingKey, int userHandle) {
1368         try {
1369             return getLockSettings().getString(secureSettingKey, null, userHandle);
1370         } catch (RemoteException re) {
1371             return null;
1372         }
1373     }
1374 
setString(String secureSettingKey, String value, int userHandle)1375     private void setString(String secureSettingKey, String value, int userHandle) {
1376         try {
1377             getLockSettings().setString(secureSettingKey, value, userHandle);
1378         } catch (RemoteException re) {
1379             // What can we do?
1380             Log.e(TAG, "Couldn't write string " + secureSettingKey + re);
1381         }
1382     }
1383 
setPowerButtonInstantlyLocks(boolean enabled, int userId)1384     public void setPowerButtonInstantlyLocks(boolean enabled, int userId) {
1385         setBoolean(LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS, enabled, userId);
1386     }
1387 
getPowerButtonInstantlyLocks(int userId)1388     public boolean getPowerButtonInstantlyLocks(int userId) {
1389         return getBoolean(LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS, true, userId);
1390     }
1391 
isPowerButtonInstantlyLocksEverChosen(int userId)1392     public boolean isPowerButtonInstantlyLocksEverChosen(int userId) {
1393         return getString(LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS, userId) != null;
1394     }
1395 
setEnabledTrustAgents(Collection<ComponentName> activeTrustAgents, int userId)1396     public void setEnabledTrustAgents(Collection<ComponentName> activeTrustAgents, int userId) {
1397         StringBuilder sb = new StringBuilder();
1398         for (ComponentName cn : activeTrustAgents) {
1399             if (sb.length() > 0) {
1400                 sb.append(',');
1401             }
1402             sb.append(cn.flattenToShortString());
1403         }
1404         setString(ENABLED_TRUST_AGENTS, sb.toString(), userId);
1405         getTrustManager().reportEnabledTrustAgentsChanged(userId);
1406     }
1407 
getEnabledTrustAgents(int userId)1408     public List<ComponentName> getEnabledTrustAgents(int userId) {
1409         String serialized = getString(ENABLED_TRUST_AGENTS, userId);
1410         if (TextUtils.isEmpty(serialized)) {
1411             return null;
1412         }
1413         String[] split = serialized.split(",");
1414         ArrayList<ComponentName> activeTrustAgents = new ArrayList<ComponentName>(split.length);
1415         for (String s : split) {
1416             if (!TextUtils.isEmpty(s)) {
1417                 activeTrustAgents.add(ComponentName.unflattenFromString(s));
1418             }
1419         }
1420         return activeTrustAgents;
1421     }
1422 
1423     /**
1424      * Disable trust until credentials have been entered for user {@param userId}.
1425      *
1426      * Requires the {@link android.Manifest.permission#ACCESS_KEYGUARD_SECURE_STORAGE} permission.
1427      *
1428      * @param userId either an explicit user id or {@link android.os.UserHandle#USER_ALL}
1429      */
requireCredentialEntry(int userId)1430     public void requireCredentialEntry(int userId) {
1431         requireStrongAuth(StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST, userId);
1432     }
1433 
1434     /**
1435      * Requests strong authentication for user {@param userId}.
1436      *
1437      * Requires the {@link android.Manifest.permission#ACCESS_KEYGUARD_SECURE_STORAGE} permission.
1438      *
1439      * @param strongAuthReason a combination of {@link StrongAuthTracker.StrongAuthFlags} indicating
1440      *                         the reason for and the strength of the requested authentication.
1441      * @param userId either an explicit user id or {@link android.os.UserHandle#USER_ALL}
1442      */
requireStrongAuth(@trongAuthTracker.StrongAuthFlags int strongAuthReason, int userId)1443     public void requireStrongAuth(@StrongAuthTracker.StrongAuthFlags int strongAuthReason,
1444             int userId) {
1445         try {
1446             getLockSettings().requireStrongAuth(strongAuthReason, userId);
1447         } catch (RemoteException e) {
1448             Log.e(TAG, "Error while requesting strong auth: " + e);
1449         }
1450     }
1451 
onAfterChangingPassword(int userHandle)1452     private void onAfterChangingPassword(int userHandle) {
1453         getTrustManager().reportEnabledTrustAgentsChanged(userHandle);
1454     }
1455 
isCredentialRequiredToDecrypt(boolean defaultValue)1456     public boolean isCredentialRequiredToDecrypt(boolean defaultValue) {
1457         final int value = Settings.Global.getInt(mContentResolver,
1458                 Settings.Global.REQUIRE_PASSWORD_TO_DECRYPT, -1);
1459         return value == -1 ? defaultValue : (value != 0);
1460     }
1461 
setCredentialRequiredToDecrypt(boolean required)1462     public void setCredentialRequiredToDecrypt(boolean required) {
1463         if (!(getUserManager().isSystemUser() || getUserManager().isPrimaryUser())) {
1464             throw new IllegalStateException(
1465                     "Only the system or primary user may call setCredentialRequiredForDecrypt()");
1466         }
1467 
1468         if (isDeviceEncryptionEnabled()){
1469             Settings.Global.putInt(mContext.getContentResolver(),
1470                Settings.Global.REQUIRE_PASSWORD_TO_DECRYPT, required ? 1 : 0);
1471         }
1472     }
1473 
isDoNotAskCredentialsOnBootSet()1474     private boolean isDoNotAskCredentialsOnBootSet() {
1475         return getDevicePolicyManager().getDoNotAskCredentialsOnBoot();
1476     }
1477 
shouldEncryptWithCredentials(boolean defaultValue)1478     private boolean shouldEncryptWithCredentials(boolean defaultValue) {
1479         return isCredentialRequiredToDecrypt(defaultValue) && !isDoNotAskCredentialsOnBootSet();
1480     }
1481 
throwIfCalledOnMainThread()1482     private void throwIfCalledOnMainThread() {
1483         if (Looper.getMainLooper().isCurrentThread()) {
1484             throw new IllegalStateException("should not be called from the main thread.");
1485         }
1486     }
1487 
registerStrongAuthTracker(final StrongAuthTracker strongAuthTracker)1488     public void registerStrongAuthTracker(final StrongAuthTracker strongAuthTracker) {
1489         try {
1490             getLockSettings().registerStrongAuthTracker(strongAuthTracker.mStub);
1491         } catch (RemoteException e) {
1492             throw new RuntimeException("Could not register StrongAuthTracker");
1493         }
1494     }
1495 
unregisterStrongAuthTracker(final StrongAuthTracker strongAuthTracker)1496     public void unregisterStrongAuthTracker(final StrongAuthTracker strongAuthTracker) {
1497         try {
1498             getLockSettings().unregisterStrongAuthTracker(strongAuthTracker.mStub);
1499         } catch (RemoteException e) {
1500             Log.e(TAG, "Could not unregister StrongAuthTracker", e);
1501         }
1502     }
1503 
1504     /**
1505      * @see StrongAuthTracker#getStrongAuthForUser
1506      */
getStrongAuthForUser(int userId)1507     public int getStrongAuthForUser(int userId) {
1508         try {
1509             return getLockSettings().getStrongAuthForUser(userId);
1510         } catch (RemoteException e) {
1511             Log.e(TAG, "Could not get StrongAuth", e);
1512             return StrongAuthTracker.getDefaultFlags(mContext);
1513         }
1514     }
1515 
1516     /**
1517      * @see StrongAuthTracker#isTrustAllowedForUser
1518      */
isTrustAllowedForUser(int userId)1519     public boolean isTrustAllowedForUser(int userId) {
1520         return getStrongAuthForUser(userId) == StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED;
1521     }
1522 
1523     /**
1524      * @see StrongAuthTracker#isFingerprintAllowedForUser
1525      */
isFingerprintAllowedForUser(int userId)1526     public boolean isFingerprintAllowedForUser(int userId) {
1527         return (getStrongAuthForUser(userId) & ~StrongAuthTracker.ALLOWING_FINGERPRINT) == 0;
1528     }
1529 
isUserInLockdown(int userId)1530     public boolean isUserInLockdown(int userId) {
1531         return getStrongAuthForUser(userId)
1532                 == StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN;
1533     }
1534 
wrapCallback( final CheckCredentialProgressCallback callback)1535     private ICheckCredentialProgressCallback wrapCallback(
1536             final CheckCredentialProgressCallback callback) {
1537         if (callback == null) {
1538             return null;
1539         } else {
1540             if (mHandler == null) {
1541                 throw new IllegalStateException("Must construct LockPatternUtils on a looper thread"
1542                         + " to use progress callbacks.");
1543             }
1544             return new ICheckCredentialProgressCallback.Stub() {
1545 
1546                 @Override
1547                 public void onCredentialVerified() throws RemoteException {
1548                     mHandler.post(callback::onEarlyMatched);
1549                 }
1550             };
1551         }
1552     }
1553 
1554     private LockSettingsInternal getLockSettingsInternal() {
1555         LockSettingsInternal service = LocalServices.getService(LockSettingsInternal.class);
1556         if (service == null) {
1557             throw new SecurityException("Only available to system server itself");
1558         }
1559         return service;
1560     }
1561     /**
1562      * Create an escrow token for the current user, which can later be used to unlock FBE
1563      * or change user password.
1564      *
1565      * After adding, if the user currently has lockscreen password, he will need to perform a
1566      * confirm credential operation in order to activate the token for future use. If the user
1567      * has no secure lockscreen, then the token is activated immediately.
1568      *
1569      * <p>This method is only available to code running in the system server process itself.
1570      *
1571      * @return a unique 64-bit token handle which is needed to refer to this token later.
1572      */
1573     public long addEscrowToken(byte[] token, int userId) {
1574         return getLockSettingsInternal().addEscrowToken(token, userId);
1575     }
1576 
1577     /**
1578      * Remove an escrow token.
1579      *
1580      * <p>This method is only available to code running in the system server process itself.
1581      *
1582      * @return true if the given handle refers to a valid token previously returned from
1583      * {@link #addEscrowToken}, whether it's active or not. return false otherwise.
1584      */
1585     public boolean removeEscrowToken(long handle, int userId) {
1586         return getLockSettingsInternal().removeEscrowToken(handle, userId);
1587     }
1588 
1589     /**
1590      * Check if the given escrow token is active or not. Only active token can be used to call
1591      * {@link #setLockCredentialWithToken} and {@link #unlockUserWithToken}
1592      *
1593      * <p>This method is only available to code running in the system server process itself.
1594      */
1595     public boolean isEscrowTokenActive(long handle, int userId) {
1596         return getLockSettingsInternal().isEscrowTokenActive(handle, userId);
1597     }
1598 
1599     /**
1600      * Change a user's lock credential with a pre-configured escrow token.
1601      *
1602      * <p>This method is only available to code running in the system server process itself.
1603      *
1604      * @param credential The new credential to be set
1605      * @param type Credential type: password / pattern / none.
1606      * @param requestedQuality the requested password quality by DevicePolicyManager.
1607      *        See {@link DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
1608      * @param tokenHandle Handle of the escrow token
1609      * @param token Escrow token
1610      * @param userId The user who's lock credential to be changed
1611      * @return {@code true} if the operation is successful.
1612      */
1613     public boolean setLockCredentialWithToken(String credential, int type, int requestedQuality,
1614             long tokenHandle, byte[] token, int userId) {
1615         LockSettingsInternal localService = getLockSettingsInternal();
1616         if (type != CREDENTIAL_TYPE_NONE) {
1617             if (TextUtils.isEmpty(credential) || credential.length() < MIN_LOCK_PASSWORD_SIZE) {
1618                 throw new IllegalArgumentException("password must not be null and at least "
1619                         + "of length " + MIN_LOCK_PASSWORD_SIZE);
1620             }
1621             final int quality = computePasswordQuality(type, credential, requestedQuality);
1622             if (!localService.setLockCredentialWithToken(credential, type, tokenHandle,
1623                     token, quality, userId)) {
1624                 return false;
1625             }
1626             setKeyguardStoredPasswordQuality(quality, userId);
1627 
1628             updateEncryptionPasswordIfNeeded(credential, quality, userId);
1629             updatePasswordHistory(credential, userId);
1630             onAfterChangingPassword(userId);
1631         } else {
1632             if (!TextUtils.isEmpty(credential)) {
1633                 throw new IllegalArgumentException("password must be emtpy for NONE type");
1634             }
1635             if (!localService.setLockCredentialWithToken(null, CREDENTIAL_TYPE_NONE,
1636                     tokenHandle, token, PASSWORD_QUALITY_UNSPECIFIED, userId)) {
1637                 return false;
1638             }
1639             setKeyguardStoredPasswordQuality(PASSWORD_QUALITY_UNSPECIFIED, userId);
1640 
1641             if (userId == UserHandle.USER_SYSTEM) {
1642                 // Set the encryption password to default.
1643                 updateEncryptionPassword(StorageManager.CRYPT_TYPE_DEFAULT, null);
1644                 setCredentialRequiredToDecrypt(false);
1645             }
1646         }
1647         onAfterChangingPassword(userId);
1648         return true;
1649     }
1650 
1651     /**
1652      * Unlock the specified user by an pre-activated escrow token. This should have the same effect
1653      * on device encryption as the user entering his lockscreen credentials for the first time after
1654      * boot, this includes unlocking the user's credential-encrypted storage as well as the keystore
1655      *
1656      * <p>This method is only available to code running in the system server process itself.
1657      *
1658      * @return {@code true} if the supplied token is valid and unlock succeeds,
1659      *         {@code false} otherwise.
1660      */
1661     public boolean unlockUserWithToken(long tokenHandle, byte[] token, int userId) {
1662         return getLockSettingsInternal().unlockUserWithToken(tokenHandle, token, userId);
1663     }
1664 
1665 
1666     /**
1667      * Callback to be notified about progress when checking credentials.
1668      */
1669     public interface CheckCredentialProgressCallback {
1670 
1671         /**
1672          * Called as soon as possible when we know that the credentials match but the user hasn't
1673          * been fully unlocked.
1674          */
1675         void onEarlyMatched();
1676     }
1677 
1678     /**
1679      * Tracks the global strong authentication state.
1680      */
1681     public static class StrongAuthTracker {
1682 
1683         @IntDef(flag = true,
1684                 value = { STRONG_AUTH_NOT_REQUIRED,
1685                         STRONG_AUTH_REQUIRED_AFTER_BOOT,
1686                         STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW,
1687                         SOME_AUTH_REQUIRED_AFTER_USER_REQUEST,
1688                         STRONG_AUTH_REQUIRED_AFTER_LOCKOUT,
1689                         STRONG_AUTH_REQUIRED_AFTER_TIMEOUT,
1690                         STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN})
1691         @Retention(RetentionPolicy.SOURCE)
1692         public @interface StrongAuthFlags {}
1693 
1694         /**
1695          * Strong authentication is not required.
1696          */
1697         public static final int STRONG_AUTH_NOT_REQUIRED = 0x0;
1698 
1699         /**
1700          * Strong authentication is required because the user has not authenticated since boot.
1701          */
1702         public static final int STRONG_AUTH_REQUIRED_AFTER_BOOT = 0x1;
1703 
1704         /**
1705          * Strong authentication is required because a device admin has requested it.
1706          */
1707         public static final int STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW = 0x2;
1708 
1709         /**
1710          * Some authentication is required because the user has temporarily disabled trust.
1711          */
1712         public static final int SOME_AUTH_REQUIRED_AFTER_USER_REQUEST = 0x4;
1713 
1714         /**
1715          * Strong authentication is required because the user has been locked out after too many
1716          * attempts.
1717          */
1718         public static final int STRONG_AUTH_REQUIRED_AFTER_LOCKOUT = 0x8;
1719 
1720         /**
1721          * Strong authentication is required because it hasn't been used for a time required by
1722          * a device admin.
1723          */
1724         public static final int STRONG_AUTH_REQUIRED_AFTER_TIMEOUT = 0x10;
1725 
1726         /**
1727          * Strong authentication is required because the user has triggered lockdown.
1728          */
1729         public static final int STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN = 0x20;
1730 
1731         /**
1732          * Strong auth flags that do not prevent fingerprint from being accepted as auth.
1733          *
1734          * If any other flags are set, fingerprint is disabled.
1735          */
1736         private static final int ALLOWING_FINGERPRINT = STRONG_AUTH_NOT_REQUIRED
1737                 | SOME_AUTH_REQUIRED_AFTER_USER_REQUEST;
1738 
1739         private final SparseIntArray mStrongAuthRequiredForUser = new SparseIntArray();
1740         private final H mHandler;
1741         private final int mDefaultStrongAuthFlags;
1742 
1743         public StrongAuthTracker(Context context) {
1744             this(context, Looper.myLooper());
1745         }
1746 
1747         /**
1748          * @param looper the looper on whose thread calls to {@link #onStrongAuthRequiredChanged}
1749          *               will be scheduled.
1750          * @param context the current {@link Context}
1751          */
1752         public StrongAuthTracker(Context context, Looper looper) {
1753             mHandler = new H(looper);
1754             mDefaultStrongAuthFlags = getDefaultFlags(context);
1755         }
1756 
1757         public static @StrongAuthFlags int getDefaultFlags(Context context) {
1758             boolean strongAuthRequired = context.getResources().getBoolean(
1759                     com.android.internal.R.bool.config_strongAuthRequiredOnBoot);
1760             return strongAuthRequired ? STRONG_AUTH_REQUIRED_AFTER_BOOT : STRONG_AUTH_NOT_REQUIRED;
1761         }
1762 
1763         /**
1764          * Returns {@link #STRONG_AUTH_NOT_REQUIRED} if strong authentication is not required,
1765          * otherwise returns a combination of {@link StrongAuthFlags} indicating why strong
1766          * authentication is required.
1767          *
1768          * @param userId the user for whom the state is queried.
1769          */
1770         public @StrongAuthFlags int getStrongAuthForUser(int userId) {
1771             return mStrongAuthRequiredForUser.get(userId, mDefaultStrongAuthFlags);
1772         }
1773 
1774         /**
1775          * @return true if unlocking with trust alone is allowed for {@param userId} by the current
1776          * strong authentication requirements.
1777          */
1778         public boolean isTrustAllowedForUser(int userId) {
1779             return getStrongAuthForUser(userId) == STRONG_AUTH_NOT_REQUIRED;
1780         }
1781 
1782         /**
1783          * @return true if unlocking with fingerprint alone is allowed for {@param userId} by the
1784          * current strong authentication requirements.
1785          */
1786         public boolean isFingerprintAllowedForUser(int userId) {
1787             return (getStrongAuthForUser(userId) & ~ALLOWING_FINGERPRINT) == 0;
1788         }
1789 
1790         /**
1791          * Called when the strong authentication requirements for {@param userId} changed.
1792          */
1793         public void onStrongAuthRequiredChanged(int userId) {
1794         }
1795 
1796         protected void handleStrongAuthRequiredChanged(@StrongAuthFlags int strongAuthFlags,
1797                 int userId) {
1798             int oldValue = getStrongAuthForUser(userId);
1799             if (strongAuthFlags != oldValue) {
1800                 if (strongAuthFlags == mDefaultStrongAuthFlags) {
1801                     mStrongAuthRequiredForUser.delete(userId);
1802                 } else {
1803                     mStrongAuthRequiredForUser.put(userId, strongAuthFlags);
1804                 }
1805                 onStrongAuthRequiredChanged(userId);
1806             }
1807         }
1808 
1809 
1810         protected final IStrongAuthTracker.Stub mStub = new IStrongAuthTracker.Stub() {
1811             @Override
1812             public void onStrongAuthRequiredChanged(@StrongAuthFlags int strongAuthFlags,
1813                     int userId) {
1814                 mHandler.obtainMessage(H.MSG_ON_STRONG_AUTH_REQUIRED_CHANGED,
1815                         strongAuthFlags, userId).sendToTarget();
1816             }
1817         };
1818 
1819         private class H extends Handler {
1820             static final int MSG_ON_STRONG_AUTH_REQUIRED_CHANGED = 1;
1821 
1822             public H(Looper looper) {
1823                 super(looper);
1824             }
1825 
1826             @Override
1827             public void handleMessage(Message msg) {
1828                 switch (msg.what) {
1829                     case MSG_ON_STRONG_AUTH_REQUIRED_CHANGED:
1830                         handleStrongAuthRequiredChanged(msg.arg1, msg.arg2);
1831                         break;
1832                 }
1833             }
1834         }
1835     }
1836 
1837     public void enableSyntheticPassword() {
1838         setLong(SYNTHETIC_PASSWORD_ENABLED_KEY, 1L, UserHandle.USER_SYSTEM);
1839     }
1840 
1841     public void disableSyntheticPassword() {
1842         setLong(SYNTHETIC_PASSWORD_ENABLED_KEY, 0L, UserHandle.USER_SYSTEM);
1843     }
1844 
1845     public boolean isSyntheticPasswordEnabled() {
1846         return getLong(SYNTHETIC_PASSWORD_ENABLED_KEY, 0, UserHandle.USER_SYSTEM) != 0;
1847     }
1848 
1849     public static boolean userOwnsFrpCredential(Context context, UserInfo info) {
1850         return info != null && info.isPrimary() && info.isAdmin() && frpCredentialEnabled(context);
1851     }
1852 
1853     public static boolean frpCredentialEnabled(Context context) {
1854         return FRP_CREDENTIAL_ENABLED && context.getResources().getBoolean(
1855                 com.android.internal.R.bool.config_enableCredentialFactoryResetProtection);
1856     }
1857 }
1858