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