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