blob: e38d82fdca390a57306f276a6f610d22ee092166 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
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
17package com.android.internal.widget;
18
Adrian Roosb5e47222015-08-14 15:53:06 -070019import android.annotation.IntDef;
Adrian Roosd6aa6cb2015-04-16 19:31:29 -070020import android.app.ActivityManager;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -080021import android.app.admin.DevicePolicyManager;
Adrian Roosb5e47222015-08-14 15:53:06 -070022import android.app.trust.IStrongAuthTracker;
Adrian Roos82142c22014-03-27 14:56:59 +010023import android.app.trust.TrustManager;
Adrian Roos82142c22014-03-27 14:56:59 +010024import android.content.ComponentName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080025import android.content.ContentResolver;
Jim Miller31f90b62010-01-20 13:35:20 -080026import android.content.Context;
Paul Lawrence3a5a0be2014-09-25 09:26:34 -070027import android.os.AsyncTask;
Adrian Roosb5e47222015-08-14 15:53:06 -070028import android.os.Handler;
Jason parksf7b3cd42011-01-27 09:28:25 -060029import android.os.IBinder;
Xiyuan Xiaaa262942015-05-05 15:18:45 -070030import android.os.Looper;
Adrian Roosb5e47222015-08-14 15:53:06 -070031import android.os.Message;
Jim Miller69ac9882010-02-24 15:35:05 -080032import android.os.RemoteException;
33import android.os.ServiceManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034import android.os.SystemClock;
Jim Miller6848dc82014-10-13 18:51:53 -070035import android.os.SystemProperties;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -070036import android.os.UserHandle;
Jason parksf7b3cd42011-01-27 09:28:25 -060037import android.os.storage.IMountService;
Paul Lawrence8e397362014-01-27 15:22:30 -080038import android.os.storage.StorageManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039import android.provider.Settings;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080040import android.text.TextUtils;
41import android.util.Log;
Adrian Roosb5e47222015-08-14 15:53:06 -070042import android.util.SparseIntArray;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080043
Michael Jurka1254f2f2012-10-25 11:44:31 -070044import com.google.android.collect.Lists;
Adrian Roos9dd16eb2015-01-08 16:20:49 +010045
Adrian Roosb5e47222015-08-14 15:53:06 -070046import java.lang.annotation.Retention;
47import java.lang.annotation.RetentionPolicy;
Narayan Kamath78108a32014-12-16 12:56:23 +000048import java.nio.charset.StandardCharsets;
Brian Carlstrom929a1c22011-02-01 21:54:09 -080049import java.security.MessageDigest;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080050import java.security.NoSuchAlgorithmException;
Jim Miller11b019d2010-01-20 16:34:45 -080051import java.security.SecureRandom;
Adrian Roos82142c22014-03-27 14:56:59 +010052import java.util.ArrayList;
53import java.util.Collection;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080054import java.util.List;
55
Adrian Roosc2e01682015-01-15 23:20:20 +010056import libcore.util.HexEncoding;
57
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080058/**
Brian Carlstrom5cfee3f2011-05-31 01:00:15 -070059 * Utilities for the lock pattern and its settings.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080060 */
61public class LockPatternUtils {
62
63 private static final String TAG = "LockPatternUtils";
Brian Colonnaa0ee0042014-07-16 13:50:47 -040064 private static final boolean DEBUG = false;
Jim Miller69aa4a92009-12-22 19:03:28 -080065
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080066 /**
Bryce Lee46145962015-12-14 14:39:10 -080067 * The key to identify when the lock pattern enabled flag is being acccessed for legacy reasons.
68 */
69 public static final String LEGACY_LOCK_PATTERN_ENABLED = "legacy_lock_pattern_enabled";
70
71 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080072 * The number of incorrect attempts before which we fall back on an alternative
73 * method of verifying the user, and resetting their lock pattern.
74 */
75 public static final int FAILED_ATTEMPTS_BEFORE_RESET = 20;
76
77 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080078 * The interval of the countdown for showing progress of the lockout.
79 */
80 public static final long FAILED_ATTEMPT_COUNTDOWN_INTERVAL_MS = 1000L;
81
Jim Miller4f369952011-08-19 18:29:22 -070082
83 /**
84 * This dictates when we start telling the user that continued failed attempts will wipe
85 * their device.
86 */
87 public static final int FAILED_ATTEMPTS_BEFORE_WIPE_GRACE = 5;
88
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080089 /**
90 * The minimum number of dots in a valid pattern.
91 */
92 public static final int MIN_LOCK_PATTERN_SIZE = 4;
93
94 /**
Adrian Roosf80e66ce92015-01-15 23:27:24 +010095 * The minimum size of a valid password.
96 */
97 public static final int MIN_LOCK_PASSWORD_SIZE = 4;
98
99 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800100 * The minimum number of dots the user must include in a wrong pattern
101 * attempt for it to be counted against the counts that affect
102 * {@link #FAILED_ATTEMPTS_BEFORE_TIMEOUT} and {@link #FAILED_ATTEMPTS_BEFORE_RESET}
103 */
Jim Miller4f369952011-08-19 18:29:22 -0700104 public static final int MIN_PATTERN_REGISTER_FAIL = MIN_LOCK_PATTERN_SIZE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800105
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100106 @Deprecated
Jeff Sharkey7a96c392012-11-15 14:01:46 -0800107 public final static String LOCKOUT_PERMANENT_KEY = "lockscreen.lockedoutpermanently";
108 public final static String LOCKOUT_ATTEMPT_DEADLINE = "lockscreen.lockoutattemptdeadline";
Andres Morales23974272015-05-14 22:42:26 -0700109 public final static String LOCKOUT_ATTEMPT_TIMEOUT_MS = "lockscreen.lockoutattempttimeoutmss";
Jeff Sharkey7a96c392012-11-15 14:01:46 -0800110 public final static String PATTERN_EVER_CHOSEN_KEY = "lockscreen.patterneverchosen";
Jim Miller69aa4a92009-12-22 19:03:28 -0800111 public final static String PASSWORD_TYPE_KEY = "lockscreen.password_type";
Adrian Roos230635e2015-01-07 20:50:29 +0100112 @Deprecated
113 public final static String PASSWORD_TYPE_ALTERNATE_KEY = "lockscreen.password_type_alternate";
Jeff Sharkey7a96c392012-11-15 14:01:46 -0800114 public final static String LOCK_PASSWORD_SALT_KEY = "lockscreen.password_salt";
115 public final static String DISABLE_LOCKSCREEN_KEY = "lockscreen.disabled";
116 public final static String LOCKSCREEN_OPTIONS = "lockscreen.options";
Adrian Roos230635e2015-01-07 20:50:29 +0100117 @Deprecated
Jim Miller6edf2632011-09-05 16:03:14 -0700118 public final static String LOCKSCREEN_BIOMETRIC_WEAK_FALLBACK
119 = "lockscreen.biometric_weak_fallback";
Adrian Roos230635e2015-01-07 20:50:29 +0100120 @Deprecated
Danielle Millett7a072192011-10-03 17:36:01 -0400121 public final static String BIOMETRIC_WEAK_EVER_CHOSEN_KEY
122 = "lockscreen.biometricweakeverchosen";
Jim Millera4edd152012-01-06 18:24:04 -0800123 public final static String LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS
124 = "lockscreen.power_button_instantly_locks";
Adrian Roos230635e2015-01-07 20:50:29 +0100125 @Deprecated
Jim Millerf45bb402013-08-20 18:58:32 -0700126 public final static String LOCKSCREEN_WIDGETS_ENABLED = "lockscreen.widgets_enabled";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800127
Jeff Sharkey7a96c392012-11-15 14:01:46 -0800128 public final static String PASSWORD_HISTORY_KEY = "lockscreen.passwordhistory";
Konstantin Lopyrev863f22d2010-05-12 17:16:58 -0700129
Jim Miller187ec582013-04-15 18:27:54 -0700130 private static final String LOCK_SCREEN_OWNER_INFO = Settings.Secure.LOCK_SCREEN_OWNER_INFO;
131 private static final String LOCK_SCREEN_OWNER_INFO_ENABLED =
132 Settings.Secure.LOCK_SCREEN_OWNER_INFO_ENABLED;
133
Andrei Stingaceanu6644cd92015-11-10 13:03:31 +0000134 private static final String LOCK_SCREEN_DEVICE_OWNER_INFO = "lockscreen.device_owner_info";
135
Adrian Roos82142c22014-03-27 14:56:59 +0100136 private static final String ENABLED_TRUST_AGENTS = "lockscreen.enabledtrustagents";
137
Jim Miller85516d02014-01-31 17:08:37 -0800138 // Maximum allowed number of repeated or ordered characters in a sequence before we'll
139 // consider it a complex PIN/password.
140 public static final int MAX_ALLOWED_SEQUENCE = 3;
141
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800142 private final Context mContext;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800143 private final ContentResolver mContentResolver;
Jim Miller31f90b62010-01-20 13:35:20 -0800144 private DevicePolicyManager mDevicePolicyManager;
Amith Yamasani52c489c2012-03-28 11:42:42 -0700145 private ILockSettings mLockSettingsService;
Jim Milleree82f8f2012-10-01 16:26:18 -0700146
Andres Morales23974272015-05-14 22:42:26 -0700147
148 public static final class RequestThrottledException extends Exception {
149 private int mTimeoutMs;
150 public RequestThrottledException(int timeoutMs) {
151 mTimeoutMs = timeoutMs;
152 }
153
154 /**
155 * @return The amount of time in ms before another request may
156 * be executed
157 */
158 public int getTimeoutMs() {
159 return mTimeoutMs;
160 }
161
162 }
163
Jim Millercd709882010-03-25 18:24:02 -0700164 public DevicePolicyManager getDevicePolicyManager() {
Jim Miller5b0fb3a2010-02-23 13:46:35 -0800165 if (mDevicePolicyManager == null) {
166 mDevicePolicyManager =
167 (DevicePolicyManager)mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
168 if (mDevicePolicyManager == null) {
169 Log.e(TAG, "Can't get DevicePolicyManagerService: is it running?",
170 new IllegalStateException("Stack trace:"));
171 }
172 }
173 return mDevicePolicyManager;
174 }
Amith Yamasani52c489c2012-03-28 11:42:42 -0700175
Adrian Roos82142c22014-03-27 14:56:59 +0100176 private TrustManager getTrustManager() {
177 TrustManager trust = (TrustManager) mContext.getSystemService(Context.TRUST_SERVICE);
178 if (trust == null) {
179 Log.e(TAG, "Can't get TrustManagerService: is it running?",
180 new IllegalStateException("Stack trace:"));
181 }
182 return trust;
183 }
184
Jim Miller31f90b62010-01-20 13:35:20 -0800185 public LockPatternUtils(Context context) {
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800186 mContext = context;
Jim Miller31f90b62010-01-20 13:35:20 -0800187 mContentResolver = context.getContentResolver();
Amith Yamasani52c489c2012-03-28 11:42:42 -0700188 }
Jim Miller69aa4a92009-12-22 19:03:28 -0800189
Amith Yamasani52c489c2012-03-28 11:42:42 -0700190 private ILockSettings getLockSettings() {
191 if (mLockSettingsService == null) {
Adrian Roos450ce9f2014-10-29 14:30:37 +0100192 ILockSettings service = ILockSettings.Stub.asInterface(
193 ServiceManager.getService("lock_settings"));
Adrian Roos138b8332014-11-11 13:51:07 +0100194 mLockSettingsService = service;
Brad Fitzpatrick90881002010-08-23 18:30:08 -0700195 }
Amith Yamasani52c489c2012-03-28 11:42:42 -0700196 return mLockSettingsService;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800197 }
198
Adrian Roos8150d2a2015-04-16 17:11:20 -0700199 public int getRequestedMinimumPasswordLength(int userId) {
200 return getDevicePolicyManager().getPasswordMinimumLength(null, userId);
Jim Miller31f90b62010-01-20 13:35:20 -0800201 }
202
Jim Miller31f90b62010-01-20 13:35:20 -0800203 /**
204 * Gets the device policy password mode. If the mode is non-specific, returns
205 * MODE_PATTERN which allows the user to choose anything.
Jim Miller31f90b62010-01-20 13:35:20 -0800206 */
Adrian Roos8150d2a2015-04-16 17:11:20 -0700207 public int getRequestedPasswordQuality(int userId) {
208 return getDevicePolicyManager().getPasswordQuality(null, userId);
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100209 }
210
211 private int getRequestedPasswordHistoryLength(int userId) {
212 return getDevicePolicyManager().getPasswordHistoryLength(null, userId);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700213 }
214
Adrian Roos8150d2a2015-04-16 17:11:20 -0700215 public int getRequestedPasswordMinimumLetters(int userId) {
216 return getDevicePolicyManager().getPasswordMinimumLetters(null, userId);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700217 }
218
Adrian Roos8150d2a2015-04-16 17:11:20 -0700219 public int getRequestedPasswordMinimumUpperCase(int userId) {
220 return getDevicePolicyManager().getPasswordMinimumUpperCase(null, userId);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700221 }
222
Adrian Roos8150d2a2015-04-16 17:11:20 -0700223 public int getRequestedPasswordMinimumLowerCase(int userId) {
224 return getDevicePolicyManager().getPasswordMinimumLowerCase(null, userId);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700225 }
226
Adrian Roos8150d2a2015-04-16 17:11:20 -0700227 public int getRequestedPasswordMinimumNumeric(int userId) {
228 return getDevicePolicyManager().getPasswordMinimumNumeric(null, userId);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700229 }
230
Adrian Roos8150d2a2015-04-16 17:11:20 -0700231 public int getRequestedPasswordMinimumSymbols(int userId) {
232 return getDevicePolicyManager().getPasswordMinimumSymbols(null, userId);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700233 }
234
Adrian Roos8150d2a2015-04-16 17:11:20 -0700235 public int getRequestedPasswordMinimumNonLetter(int userId) {
236 return getDevicePolicyManager().getPasswordMinimumNonLetter(null, userId);
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700237 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700238
Adrian Roos8150d2a2015-04-16 17:11:20 -0700239 public void reportFailedPasswordAttempt(int userId) {
Adrian Roos4f994eb2014-07-23 15:45:05 +0200240 getDevicePolicyManager().reportFailedPasswordAttempt(userId);
241 getTrustManager().reportUnlockAttempt(false /* authenticated */, userId);
Adrian Roosaf4ab3e2015-09-02 13:23:30 -0700242 requireStrongAuth(StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_WRONG_CREDENTIAL, userId);
Jim Miller31f90b62010-01-20 13:35:20 -0800243 }
244
Adrian Roos8150d2a2015-04-16 17:11:20 -0700245 public void reportSuccessfulPasswordAttempt(int userId) {
246 getDevicePolicyManager().reportSuccessfulPasswordAttempt(userId);
247 getTrustManager().reportUnlockAttempt(true /* authenticated */, userId);
Jim Miller31f90b62010-01-20 13:35:20 -0800248 }
249
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800250 /**
Andres Moralesd9fc85a2015-04-09 19:14:42 -0700251 * Check to see if a pattern matches the saved pattern.
252 * If pattern matches, return an opaque attestation that the challenge
253 * was verified.
254 *
255 * @param pattern The pattern to check.
256 * @param challenge The challenge to verify against the pattern
257 * @return the attestation that the challenge was verified, or null.
258 */
Andres Morales23974272015-05-14 22:42:26 -0700259 public byte[] verifyPattern(List<LockPatternView.Cell> pattern, long challenge, int userId)
260 throws RequestThrottledException {
Xiyuan Xiaaa262942015-05-05 15:18:45 -0700261 throwIfCalledOnMainThread();
Andres Moralesd9fc85a2015-04-09 19:14:42 -0700262 try {
Andres Morales23974272015-05-14 22:42:26 -0700263 VerifyCredentialResponse response =
264 getLockSettings().verifyPattern(patternToString(pattern), challenge, userId);
265 if (response == null) {
266 // Shouldn't happen
267 return null;
268 }
269
270 if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
271 return response.getPayload();
272 } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {
273 throw new RequestThrottledException(response.getTimeout());
274 } else {
275 return null;
276 }
Andres Moralesd9fc85a2015-04-09 19:14:42 -0700277 } catch (RemoteException re) {
278 return null;
279 }
280 }
281
282 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800283 * Check to see if a pattern matches the saved pattern. If no pattern exists,
284 * always returns true.
285 * @param pattern The pattern to check.
Jim Miller69aa4a92009-12-22 19:03:28 -0800286 * @return Whether the pattern matches the stored one.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800287 */
Andres Morales23974272015-05-14 22:42:26 -0700288 public boolean checkPattern(List<LockPatternView.Cell> pattern, int userId)
289 throws RequestThrottledException {
Xiyuan Xiaaa262942015-05-05 15:18:45 -0700290 throwIfCalledOnMainThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800291 try {
Andres Morales23974272015-05-14 22:42:26 -0700292 VerifyCredentialResponse response =
293 getLockSettings().checkPattern(patternToString(pattern), userId);
294
295 if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
296 return true;
297 } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {
298 throw new RequestThrottledException(response.getTimeout());
299 } else {
300 return false;
301 }
Amith Yamasani52c489c2012-03-28 11:42:42 -0700302 } catch (RemoteException re) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800303 return true;
304 }
305 }
306
307 /**
Andres Moralesd9fc85a2015-04-09 19:14:42 -0700308 * Check to see if a password matches the saved password.
309 * If password matches, return an opaque attestation that the challenge
310 * was verified.
311 *
312 * @param password The password to check.
313 * @param challenge The challenge to verify against the password
314 * @return the attestation that the challenge was verified, or null.
315 */
Andres Morales23974272015-05-14 22:42:26 -0700316 public byte[] verifyPassword(String password, long challenge, int userId)
317 throws RequestThrottledException {
Xiyuan Xiaaa262942015-05-05 15:18:45 -0700318 throwIfCalledOnMainThread();
Andres Moralesd9fc85a2015-04-09 19:14:42 -0700319 try {
Andres Morales23974272015-05-14 22:42:26 -0700320 VerifyCredentialResponse response =
321 getLockSettings().verifyPassword(password, challenge, userId);
322
323 if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
324 return response.getPayload();
325 } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {
326 throw new RequestThrottledException(response.getTimeout());
327 } else {
328 return null;
329 }
Andres Moralesd9fc85a2015-04-09 19:14:42 -0700330 } catch (RemoteException re) {
331 return null;
332 }
333 }
334
335 /**
Jim Miller69aa4a92009-12-22 19:03:28 -0800336 * Check to see if a password matches the saved password. If no password exists,
337 * always returns true.
338 * @param password The password to check.
339 * @return Whether the password matches the stored one.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800340 */
Andres Morales23974272015-05-14 22:42:26 -0700341 public boolean checkPassword(String password, int userId) throws RequestThrottledException {
Xiyuan Xiaaa262942015-05-05 15:18:45 -0700342 throwIfCalledOnMainThread();
Jim Miller69aa4a92009-12-22 19:03:28 -0800343 try {
Andres Morales23974272015-05-14 22:42:26 -0700344 VerifyCredentialResponse response =
345 getLockSettings().checkPassword(password, userId);
346 if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
347 return true;
348 } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {
349 throw new RequestThrottledException(response.getTimeout());
350 } else {
351 return false;
352 }
Amith Yamasani52c489c2012-03-28 11:42:42 -0700353 } catch (RemoteException re) {
Jim Miller69aa4a92009-12-22 19:03:28 -0800354 return true;
355 }
356 }
357
358 /**
Paul Lawrence945490c2014-03-27 16:37:28 +0000359 * Check to see if vold already has the password.
360 * Note that this also clears vold's copy of the password.
361 * @return Whether the vold password matches or not.
362 */
Adrian Roos8150d2a2015-04-16 17:11:20 -0700363 public boolean checkVoldPassword(int userId) {
Paul Lawrence945490c2014-03-27 16:37:28 +0000364 try {
365 return getLockSettings().checkVoldPassword(userId);
366 } catch (RemoteException re) {
367 return false;
368 }
369 }
370
371 /**
Konstantin Lopyrev863f22d2010-05-12 17:16:58 -0700372 * Check to see if a password matches any of the passwords stored in the
373 * password history.
374 *
375 * @param password The password to check.
376 * @return Whether the password matches any in the history.
377 */
Adrian Roos8150d2a2015-04-16 17:11:20 -0700378 public boolean checkPasswordHistory(String password, int userId) {
Geoffrey Borggaard987672d22014-07-18 16:47:18 -0400379 String passwordHashString = new String(
Adrian Roosdce01222015-01-07 22:39:01 +0100380 passwordToHash(password, userId), StandardCharsets.UTF_8);
381 String passwordHistory = getString(PASSWORD_HISTORY_KEY, userId);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700382 if (passwordHistory == null) {
383 return false;
384 }
385 // Password History may be too long...
386 int passwordHashLength = passwordHashString.length();
Adrian Roos8150d2a2015-04-16 17:11:20 -0700387 int passwordHistoryLength = getRequestedPasswordHistoryLength(userId);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700388 if(passwordHistoryLength == 0) {
389 return false;
390 }
391 int neededPasswordHistoryLength = passwordHashLength * passwordHistoryLength
392 + passwordHistoryLength - 1;
393 if (passwordHistory.length() > neededPasswordHistoryLength) {
394 passwordHistory = passwordHistory.substring(0, neededPasswordHistoryLength);
395 }
396 return passwordHistory.contains(passwordHashString);
Konstantin Lopyrev863f22d2010-05-12 17:16:58 -0700397 }
398
399 /**
Jim Miller69aa4a92009-12-22 19:03:28 -0800400 * Check to see if the user has stored a lock pattern.
401 * @return Whether a saved pattern exists.
402 */
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100403 private boolean savedPatternExists(int userId) {
Amith Yamasani52c489c2012-03-28 11:42:42 -0700404 try {
Adrian Roos50bfeec2014-11-20 16:21:11 +0100405 return getLockSettings().havePattern(userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -0700406 } catch (RemoteException re) {
407 return false;
408 }
Jim Miller69aa4a92009-12-22 19:03:28 -0800409 }
410
411 /**
412 * Check to see if the user has stored a lock pattern.
413 * @return Whether a saved pattern exists.
414 */
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100415 private boolean savedPasswordExists(int userId) {
Amith Yamasani52c489c2012-03-28 11:42:42 -0700416 try {
Adrian Roos50bfeec2014-11-20 16:21:11 +0100417 return getLockSettings().havePassword(userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -0700418 } catch (RemoteException re) {
419 return false;
420 }
Jim Miller69aa4a92009-12-22 19:03:28 -0800421 }
422
423 /**
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -0700424 * Return true if the user has ever chosen a pattern. This is true even if the pattern is
425 * currently cleared.
426 *
427 * @return True if the user has ever chosen a pattern.
428 */
Adrian Roos8150d2a2015-04-16 17:11:20 -0700429 public boolean isPatternEverChosen(int userId) {
430 return getBoolean(PATTERN_EVER_CHOSEN_KEY, false, userId);
Adrian Roosdce01222015-01-07 22:39:01 +0100431 }
432
433 /**
434 * Used by device policy manager to validate the current password
435 * information it has.
436 */
437 public int getActivePasswordQuality(int userId) {
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100438 int quality = getKeyguardStoredPasswordQuality(userId);
Adrian Roosdce01222015-01-07 22:39:01 +0100439
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100440 if (isLockPasswordEnabled(quality, userId)) {
441 // Quality is a password and a password exists. Return the quality.
442 return quality;
443 }
444
445 if (isLockPatternEnabled(quality, userId)) {
446 // Quality is a pattern and a pattern exists. Return the quality.
447 return quality;
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700448 }
Danielle Millettc8fb5322011-10-04 12:18:51 -0400449
Adrian Roosdce01222015-01-07 22:39:01 +0100450 return DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700451 }
Jim Millercd709882010-03-25 18:24:02 -0700452
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700453 /**
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800454 * Clear any lock pattern or password.
455 */
Adrian Roos230635e2015-01-07 20:50:29 +0100456 public void clearLock(int userHandle) {
Adrian Roosf8f56bc2014-11-20 23:55:34 +0100457 setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, userHandle);
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100458
459 try {
Andres Morales8fa56652015-03-31 09:19:50 -0700460 getLockSettings().setLockPassword(null, null, userHandle);
461 getLockSettings().setLockPattern(null, null, userHandle);
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100462 } catch (RemoteException e) {
463 // well, we tried...
464 }
465
Xiaohui Chen86c69dd2015-08-27 15:44:02 -0700466 if (userHandle == UserHandle.USER_SYSTEM) {
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100467 // Set the encryption password to default.
468 updateEncryptionPassword(StorageManager.CRYPT_TYPE_DEFAULT, null);
469 }
470
Wen ZHANG95bbbdd2015-04-15 19:32:06 +0100471 setCredentialRequiredToDecrypt(false);
472
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100473 getDevicePolicyManager().setActivePasswordState(
474 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 0, 0, 0, 0, 0, 0, 0, userHandle);
475
Adrian Roosf8f56bc2014-11-20 23:55:34 +0100476 onAfterChangingPassword(userHandle);
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800477 }
Jim Miller5b0fb3a2010-02-23 13:46:35 -0800478
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800479 /**
Benjamin Franz51ed7942015-04-07 16:34:56 +0100480 * Disable showing lock screen at all for a given user.
481 * This is only meaningful if pattern, pin or password are not set.
Jim Miller2a98a4c2010-11-19 18:49:26 -0800482 *
Benjamin Franz51ed7942015-04-07 16:34:56 +0100483 * @param disable Disables lock screen when true
484 * @param userId User ID of the user this has effect on
485 */
486 public void setLockScreenDisabled(boolean disable, int userId) {
487 setBoolean(DISABLE_LOCKSCREEN_KEY, disable, userId);
488 }
489
490 /**
491 * Determine if LockScreen is disabled for the current user. This is used to decide whether
492 * LockScreen is shown after reboot or after screen timeout / short press on power.
493 *
494 * @return true if lock screen is disabled
Jim Miller2a98a4c2010-11-19 18:49:26 -0800495 */
Adrian Roos8150d2a2015-04-16 17:11:20 -0700496 public boolean isLockScreenDisabled(int userId) {
497 return !isSecure(userId) &&
498 getBoolean(DISABLE_LOCKSCREEN_KEY, false, userId);
Jim Miller2a98a4c2010-11-19 18:49:26 -0800499 }
500
501 /**
Jim Miller6edf2632011-09-05 16:03:14 -0700502 * Save a lock pattern.
503 * @param pattern The new pattern to save.
Adrian Roos8150d2a2015-04-16 17:11:20 -0700504 * @param userId the user whose pattern is to be saved.
Danielle Millett2364a222011-12-21 17:02:32 -0500505 */
Andres Morales8fa56652015-03-31 09:19:50 -0700506 public void saveLockPattern(List<LockPatternView.Cell> pattern, int userId) {
507 this.saveLockPattern(pattern, null, userId);
508 }
Danielle Millett2364a222011-12-21 17:02:32 -0500509 /**
510 * Save a lock pattern.
511 * @param pattern The new pattern to save.
Andres Morales8fa56652015-03-31 09:19:50 -0700512 * @param savedPattern The previously saved pattern, converted to String format
Adrian Roosf8f56bc2014-11-20 23:55:34 +0100513 * @param userId the user whose pattern is to be saved.
514 */
Andres Morales8fa56652015-03-31 09:19:50 -0700515 public void saveLockPattern(List<LockPatternView.Cell> pattern, String savedPattern, int userId) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800516 try {
Adrian Roosf80e66ce92015-01-15 23:27:24 +0100517 if (pattern == null || pattern.size() < MIN_LOCK_PATTERN_SIZE) {
518 throw new IllegalArgumentException("pattern must not be null and at least "
519 + MIN_LOCK_PATTERN_SIZE + " dots long.");
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100520 }
521
Andres Morales8fa56652015-03-31 09:19:50 -0700522 getLockSettings().setLockPattern(patternToString(pattern), savedPattern, userId);
Dianne Hackborn2509d3c2010-03-08 12:54:25 -0800523 DevicePolicyManager dpm = getDevicePolicyManager();
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100524
525 // Update the device encryption password.
Xiaohui Chen86c69dd2015-08-27 15:44:02 -0700526 if (userId == UserHandle.USER_SYSTEM
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100527 && LockPatternUtils.isDeviceEncryptionEnabled()) {
Andrei Kapishnikov4eb6a362015-04-02 15:21:20 -0400528 if (!shouldEncryptWithCredentials(true)) {
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100529 clearEncryptionPassword();
530 } else {
531 String stringPattern = patternToString(pattern);
532 updateEncryptionPassword(StorageManager.CRYPT_TYPE_PATTERN, stringPattern);
Paul Lawrence8e397362014-01-27 15:22:30 -0800533 }
Jim Miller31f90b62010-01-20 13:35:20 -0800534 }
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100535
536 setBoolean(PATTERN_EVER_CHOSEN_KEY, true, userId);
537
538 setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, userId);
539 dpm.setActivePasswordState(DevicePolicyManager.PASSWORD_QUALITY_SOMETHING,
540 pattern.size(), 0, 0, 0, 0, 0, 0, userId);
Adrian Roosf8f56bc2014-11-20 23:55:34 +0100541 onAfterChangingPassword(userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -0700542 } catch (RemoteException re) {
543 Log.e(TAG, "Couldn't save lock pattern " + re);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800544 }
545 }
546
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100547 private void updateCryptoUserInfo(int userId) {
Xiaohui Chen86c69dd2015-08-27 15:44:02 -0700548 if (userId != UserHandle.USER_SYSTEM) {
Paul Lawrencee51dcf92014-03-18 10:56:00 -0700549 return;
550 }
551
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100552 final String ownerInfo = isOwnerInfoEnabled(userId) ? getOwnerInfo(userId) : "";
Paul Lawrencee51dcf92014-03-18 10:56:00 -0700553
554 IBinder service = ServiceManager.getService("mount");
555 if (service == null) {
556 Log.e(TAG, "Could not find the mount service to update the user info");
557 return;
558 }
559
560 IMountService mountService = IMountService.Stub.asInterface(service);
561 try {
562 Log.d(TAG, "Setting owner info");
Elliott Hughesf839b4f2014-09-26 12:30:47 -0700563 mountService.setField(StorageManager.OWNER_INFO_KEY, ownerInfo);
Paul Lawrencee51dcf92014-03-18 10:56:00 -0700564 } catch (RemoteException e) {
565 Log.e(TAG, "Error changing user info", e);
566 }
567 }
568
Jim Miller187ec582013-04-15 18:27:54 -0700569 public void setOwnerInfo(String info, int userId) {
570 setString(LOCK_SCREEN_OWNER_INFO, info, userId);
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100571 updateCryptoUserInfo(userId);
Jim Miller187ec582013-04-15 18:27:54 -0700572 }
573
Adrian Roos8150d2a2015-04-16 17:11:20 -0700574 public void setOwnerInfoEnabled(boolean enabled, int userId) {
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100575 setBoolean(LOCK_SCREEN_OWNER_INFO_ENABLED, enabled, userId);
576 updateCryptoUserInfo(userId);
Jim Miller187ec582013-04-15 18:27:54 -0700577 }
578
579 public String getOwnerInfo(int userId) {
Adrian Roosdce01222015-01-07 22:39:01 +0100580 return getString(LOCK_SCREEN_OWNER_INFO, userId);
Jim Miller187ec582013-04-15 18:27:54 -0700581 }
582
Adrian Roos8150d2a2015-04-16 17:11:20 -0700583 public boolean isOwnerInfoEnabled(int userId) {
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100584 return getBoolean(LOCK_SCREEN_OWNER_INFO_ENABLED, false, userId);
Jim Miller187ec582013-04-15 18:27:54 -0700585 }
586
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800587 /**
Andrei Stingaceanu6644cd92015-11-10 13:03:31 +0000588 * Sets the device owner information. If the information is {@code null} or empty then the
589 * device owner info is cleared.
590 *
591 * @param info Device owner information which will be displayed instead of the user
592 * owner info.
593 */
594 public void setDeviceOwnerInfo(String info) {
595 if (info != null && info.isEmpty()) {
596 info = null;
597 }
598
599 setString(LOCK_SCREEN_DEVICE_OWNER_INFO, info, UserHandle.USER_SYSTEM);
600 }
601
602 public String getDeviceOwnerInfo() {
603 return getString(LOCK_SCREEN_DEVICE_OWNER_INFO, UserHandle.USER_SYSTEM);
604 }
605
606 public boolean isDeviceOwnerInfoEnabled() {
607 return getDeviceOwnerInfo() != null;
608 }
609
610 /**
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700611 * Compute the password quality from the given password string.
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800612 */
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700613 static public int computePasswordQuality(String password) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800614 boolean hasDigit = false;
615 boolean hasNonDigit = false;
616 final int len = password.length();
617 for (int i = 0; i < len; i++) {
618 if (Character.isDigit(password.charAt(i))) {
619 hasDigit = true;
620 } else {
621 hasNonDigit = true;
622 }
623 }
Jim Miller5b0fb3a2010-02-23 13:46:35 -0800624
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700625 if (hasNonDigit && hasDigit) {
626 return DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC;
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800627 }
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800628 if (hasNonDigit) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700629 return DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC;
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800630 }
631 if (hasDigit) {
Jim Miller85516d02014-01-31 17:08:37 -0800632 return maxLengthSequence(password) > MAX_ALLOWED_SEQUENCE
633 ? DevicePolicyManager.PASSWORD_QUALITY_NUMERIC
634 : DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX;
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800635 }
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700636 return DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800637 }
Jim Miller5b0fb3a2010-02-23 13:46:35 -0800638
Jim Miller85516d02014-01-31 17:08:37 -0800639 private static int categoryChar(char c) {
640 if ('a' <= c && c <= 'z') return 0;
641 if ('A' <= c && c <= 'Z') return 1;
642 if ('0' <= c && c <= '9') return 2;
643 return 3;
644 }
645
646 private static int maxDiffCategory(int category) {
647 if (category == 0 || category == 1) return 1;
648 else if (category == 2) return 10;
649 return 0;
650 }
651
652 /*
653 * Returns the maximum length of a sequential characters. A sequence is defined as
654 * monotonically increasing characters with a constant interval or the same character repeated.
655 *
656 * For example:
657 * maxLengthSequence("1234") == 4
658 * maxLengthSequence("1234abc") == 4
659 * maxLengthSequence("aabc") == 3
660 * maxLengthSequence("qwertyuio") == 1
661 * maxLengthSequence("@ABC") == 3
662 * maxLengthSequence(";;;;") == 4 (anything that repeats)
663 * maxLengthSequence(":;<=>") == 1 (ordered, but not composed of alphas or digits)
664 *
665 * @param string the pass
666 * @return the number of sequential letters or digits
667 */
668 public static int maxLengthSequence(String string) {
669 if (string.length() == 0) return 0;
670 char previousChar = string.charAt(0);
671 int category = categoryChar(previousChar); //current category of the sequence
672 int diff = 0; //difference between two consecutive characters
673 boolean hasDiff = false; //if we are currently targeting a sequence
674 int maxLength = 0; //maximum length of a sequence already found
675 int startSequence = 0; //where the current sequence started
676 for (int current = 1; current < string.length(); current++) {
677 char currentChar = string.charAt(current);
678 int categoryCurrent = categoryChar(currentChar);
679 int currentDiff = (int) currentChar - (int) previousChar;
680 if (categoryCurrent != category || Math.abs(currentDiff) > maxDiffCategory(category)) {
681 maxLength = Math.max(maxLength, current - startSequence);
682 startSequence = current;
683 hasDiff = false;
684 category = categoryCurrent;
685 }
686 else {
687 if(hasDiff && currentDiff != diff) {
688 maxLength = Math.max(maxLength, current - startSequence);
689 startSequence = current - 1;
690 }
691 diff = currentDiff;
692 hasDiff = true;
693 }
694 previousChar = currentChar;
695 }
696 maxLength = Math.max(maxLength, string.length() - startSequence);
697 return maxLength;
698 }
699
Jason parksf7b3cd42011-01-27 09:28:25 -0600700 /** Update the encryption password if it is enabled **/
Paul Lawrence3a5a0be2014-09-25 09:26:34 -0700701 private void updateEncryptionPassword(final int type, final String password) {
Amith Yamasanicd410ba2014-10-17 11:16:58 -0700702 if (!isDeviceEncryptionEnabled()) {
Jason parksf7b3cd42011-01-27 09:28:25 -0600703 return;
704 }
Paul Lawrence3a5a0be2014-09-25 09:26:34 -0700705 final IBinder service = ServiceManager.getService("mount");
Jason parksf7b3cd42011-01-27 09:28:25 -0600706 if (service == null) {
707 Log.e(TAG, "Could not find the mount service to update the encryption password");
708 return;
709 }
710
Paul Lawrence3a5a0be2014-09-25 09:26:34 -0700711 new AsyncTask<Void, Void, Void>() {
712 @Override
713 protected Void doInBackground(Void... dummy) {
714 IMountService mountService = IMountService.Stub.asInterface(service);
715 try {
716 mountService.changeEncryptionPassword(type, password);
717 } catch (RemoteException e) {
718 Log.e(TAG, "Error changing encryption password", e);
719 }
720 return null;
721 }
722 }.execute();
Jason parksf7b3cd42011-01-27 09:28:25 -0600723 }
724
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800725 /**
Jim Millercd709882010-03-25 18:24:02 -0700726 * Save a lock password. Does not ensure that the password is as good
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800727 * as the requested mode, but will adjust the mode to be as good as the
Adrian Roos8150d2a2015-04-16 17:11:20 -0700728 * password.
Jim Miller69aa4a92009-12-22 19:03:28 -0800729 * @param password The password to save
Andres Morales8fa56652015-03-31 09:19:50 -0700730 * @param savedPassword The previously saved lock password, or null if none
Jim Millercd709882010-03-25 18:24:02 -0700731 * @param quality {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700732 * @param userHandle The userId of the user to change the password for
733 */
Andres Morales8fa56652015-03-31 09:19:50 -0700734 public void saveLockPassword(String password, String savedPassword, int quality,
735 int userHandle) {
Jim Miller69aa4a92009-12-22 19:03:28 -0800736 try {
Dianne Hackborn2509d3c2010-03-08 12:54:25 -0800737 DevicePolicyManager dpm = getDevicePolicyManager();
Adrian Roosf80e66ce92015-01-15 23:27:24 +0100738 if (password == null || password.length() < MIN_LOCK_PASSWORD_SIZE) {
739 throw new IllegalArgumentException("password must not be null and at least "
740 + "of length " + MIN_LOCK_PASSWORD_SIZE);
Jim Miller31f90b62010-01-20 13:35:20 -0800741 }
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100742
Andres Morales8fa56652015-03-31 09:19:50 -0700743 getLockSettings().setLockPassword(password, savedPassword, userHandle);
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100744 int computedQuality = computePasswordQuality(password);
745
746 // Update the device encryption password.
Xiaohui Chen86c69dd2015-08-27 15:44:02 -0700747 if (userHandle == UserHandle.USER_SYSTEM
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100748 && LockPatternUtils.isDeviceEncryptionEnabled()) {
Andrei Kapishnikov4eb6a362015-04-02 15:21:20 -0400749 if (!shouldEncryptWithCredentials(true)) {
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100750 clearEncryptionPassword();
751 } else {
752 boolean numeric = computedQuality
753 == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
754 boolean numericComplex = computedQuality
755 == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX;
756 int type = numeric || numericComplex ? StorageManager.CRYPT_TYPE_PIN
757 : StorageManager.CRYPT_TYPE_PASSWORD;
758 updateEncryptionPassword(type, password);
759 }
760 }
761
762 setLong(PASSWORD_TYPE_KEY, Math.max(quality, computedQuality), userHandle);
763 if (computedQuality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
764 int letters = 0;
765 int uppercase = 0;
766 int lowercase = 0;
767 int numbers = 0;
768 int symbols = 0;
769 int nonletter = 0;
770 for (int i = 0; i < password.length(); i++) {
771 char c = password.charAt(i);
772 if (c >= 'A' && c <= 'Z') {
773 letters++;
774 uppercase++;
775 } else if (c >= 'a' && c <= 'z') {
776 letters++;
777 lowercase++;
778 } else if (c >= '0' && c <= '9') {
779 numbers++;
780 nonletter++;
781 } else {
782 symbols++;
783 nonletter++;
784 }
785 }
786 dpm.setActivePasswordState(Math.max(quality, computedQuality),
787 password.length(), letters, uppercase, lowercase,
788 numbers, symbols, nonletter, userHandle);
789 } else {
790 // The password is not anything.
791 dpm.setActivePasswordState(
792 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
793 0, 0, 0, 0, 0, 0, 0, userHandle);
794 }
795
796 // Add the password to the password history. We assume all
797 // password hashes have the same length for simplicity of implementation.
798 String passwordHistory = getString(PASSWORD_HISTORY_KEY, userHandle);
799 if (passwordHistory == null) {
800 passwordHistory = "";
801 }
802 int passwordHistoryLength = getRequestedPasswordHistoryLength(userHandle);
803 if (passwordHistoryLength == 0) {
804 passwordHistory = "";
805 } else {
806 byte[] hash = passwordToHash(password, userHandle);
807 passwordHistory = new String(hash, StandardCharsets.UTF_8) + "," + passwordHistory;
808 // Cut it to contain passwordHistoryLength hashes
809 // and passwordHistoryLength -1 commas.
810 passwordHistory = passwordHistory.substring(0, Math.min(hash.length
811 * passwordHistoryLength + passwordHistoryLength - 1, passwordHistory
812 .length()));
813 }
814 setString(PASSWORD_HISTORY_KEY, passwordHistory, userHandle);
Adrian Roosf8f56bc2014-11-20 23:55:34 +0100815 onAfterChangingPassword(userHandle);
Amith Yamasani52c489c2012-03-28 11:42:42 -0700816 } catch (RemoteException re) {
Jim Miller69aa4a92009-12-22 19:03:28 -0800817 // Cant do much
Amith Yamasani52c489c2012-03-28 11:42:42 -0700818 Log.e(TAG, "Unable to save lock password " + re);
Jim Miller69aa4a92009-12-22 19:03:28 -0800819 }
820 }
821
Jim Millercd709882010-03-25 18:24:02 -0700822 /**
Svetoslav16e4a1a2014-09-29 18:16:20 -0700823 * Gets whether the device is encrypted.
824 *
825 * @return Whether the device is encrypted.
826 */
827 public static boolean isDeviceEncrypted() {
828 IMountService mountService = IMountService.Stub.asInterface(
829 ServiceManager.getService("mount"));
830 try {
831 return mountService.getEncryptionState() != IMountService.ENCRYPTION_STATE_NONE
832 && mountService.getPasswordType() != StorageManager.CRYPT_TYPE_DEFAULT;
833 } catch (RemoteException re) {
834 Log.e(TAG, "Error getting encryption state", re);
835 }
836 return true;
837 }
838
839 /**
Jim Miller6848dc82014-10-13 18:51:53 -0700840 * Determine if the device supports encryption, even if it's set to default. This
841 * differs from isDeviceEncrypted() in that it returns true even if the device is
842 * encrypted with the default password.
843 * @return true if device encryption is enabled
844 */
845 public static boolean isDeviceEncryptionEnabled() {
846 final String status = SystemProperties.get("ro.crypto.state", "unsupported");
847 return "encrypted".equalsIgnoreCase(status);
848 }
849
850 /**
Svetoslav16e4a1a2014-09-29 18:16:20 -0700851 * Clears the encryption password.
852 */
853 public void clearEncryptionPassword() {
854 updateEncryptionPassword(StorageManager.CRYPT_TYPE_DEFAULT, null);
855 }
856
857 /**
Adrian Roos1572ee32014-09-01 16:24:32 +0200858 * Retrieves the quality mode for {@param userHandle}.
859 * {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
860 *
861 * @return stored password quality
862 */
863 public int getKeyguardStoredPasswordQuality(int userHandle) {
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100864 return (int) getLong(PASSWORD_TYPE_KEY,
Adrian Roos1572ee32014-09-01 16:24:32 +0200865 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, userHandle);
Jim Miller6edf2632011-09-05 16:03:14 -0700866 }
867
Danielle Millett58396982011-09-30 13:55:07 -0400868 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800869 * Deserialize a pattern.
870 * @param string The pattern serialized with {@link #patternToString}
871 * @return The pattern.
872 */
873 public static List<LockPatternView.Cell> stringToPattern(String string) {
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100874 if (string == null) {
875 return null;
876 }
877
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800878 List<LockPatternView.Cell> result = Lists.newArrayList();
879
880 final byte[] bytes = string.getBytes();
881 for (int i = 0; i < bytes.length; i++) {
Andres Moralese40bad82015-05-28 14:21:36 -0700882 byte b = (byte) (bytes[i] - '1');
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800883 result.add(LockPatternView.Cell.of(b / 3, b % 3));
884 }
885 return result;
886 }
887
888 /**
889 * Serialize a pattern.
890 * @param pattern The pattern.
891 * @return The pattern in string form.
892 */
893 public static String patternToString(List<LockPatternView.Cell> pattern) {
894 if (pattern == null) {
895 return "";
896 }
897 final int patternSize = pattern.size();
898
899 byte[] res = new byte[patternSize];
900 for (int i = 0; i < patternSize; i++) {
901 LockPatternView.Cell cell = pattern.get(i);
Andres Moralese40bad82015-05-28 14:21:36 -0700902 res[i] = (byte) (cell.getRow() * 3 + cell.getColumn() + '1');
903 }
904 return new String(res);
905 }
906
907 public static String patternStringToBaseZero(String pattern) {
908 if (pattern == null) {
909 return "";
910 }
911 final int patternSize = pattern.length();
912
913 byte[] res = new byte[patternSize];
914 final byte[] bytes = pattern.getBytes();
915 for (int i = 0; i < patternSize; i++) {
916 res[i] = (byte) (bytes[i] - '1');
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800917 }
918 return new String(res);
919 }
Jim Miller69aa4a92009-12-22 19:03:28 -0800920
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800921 /*
922 * Generate an SHA-1 hash for the pattern. Not the most secure, but it is
923 * at least a second level of protection. First level is that the file
924 * is in a location only readable by the system process.
925 * @param pattern the gesture pattern.
926 * @return the hash of the pattern in a byte array.
927 */
Jim Millerde1af082013-09-11 14:58:26 -0700928 public static byte[] patternToHash(List<LockPatternView.Cell> pattern) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800929 if (pattern == null) {
930 return null;
931 }
Jim Miller69aa4a92009-12-22 19:03:28 -0800932
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800933 final int patternSize = pattern.size();
934 byte[] res = new byte[patternSize];
935 for (int i = 0; i < patternSize; i++) {
936 LockPatternView.Cell cell = pattern.get(i);
937 res[i] = (byte) (cell.getRow() * 3 + cell.getColumn());
938 }
939 try {
940 MessageDigest md = MessageDigest.getInstance("SHA-1");
941 byte[] hash = md.digest(res);
942 return hash;
943 } catch (NoSuchAlgorithmException nsa) {
944 return res;
945 }
946 }
947
Geoffrey Borggaard987672d22014-07-18 16:47:18 -0400948 private String getSalt(int userId) {
949 long salt = getLong(LOCK_PASSWORD_SALT_KEY, 0, userId);
Jim Miller11b019d2010-01-20 16:34:45 -0800950 if (salt == 0) {
951 try {
952 salt = SecureRandom.getInstance("SHA1PRNG").nextLong();
Geoffrey Borggaard987672d22014-07-18 16:47:18 -0400953 setLong(LOCK_PASSWORD_SALT_KEY, salt, userId);
954 Log.v(TAG, "Initialized lock password salt for user: " + userId);
Jim Miller11b019d2010-01-20 16:34:45 -0800955 } catch (NoSuchAlgorithmException e) {
956 // Throw an exception rather than storing a password we'll never be able to recover
957 throw new IllegalStateException("Couldn't get SecureRandom number", e);
958 }
959 }
960 return Long.toHexString(salt);
961 }
962
Jim Miller69aa4a92009-12-22 19:03:28 -0800963 /*
964 * Generate a hash for the given password. To avoid brute force attacks, we use a salted hash.
965 * Not the most secure, but it is at least a second level of protection. First level is that
966 * the file is in a location only readable by the system process.
Narayan Kamath78108a32014-12-16 12:56:23 +0000967 *
Jim Miller69aa4a92009-12-22 19:03:28 -0800968 * @param password the gesture pattern.
Narayan Kamath78108a32014-12-16 12:56:23 +0000969 *
Jim Miller69aa4a92009-12-22 19:03:28 -0800970 * @return the hash of the pattern in a byte array.
971 */
Geoffrey Borggaard987672d22014-07-18 16:47:18 -0400972 public byte[] passwordToHash(String password, int userId) {
Jim Miller69aa4a92009-12-22 19:03:28 -0800973 if (password == null) {
974 return null;
975 }
Narayan Kamath78108a32014-12-16 12:56:23 +0000976
Jim Miller69aa4a92009-12-22 19:03:28 -0800977 try {
Geoffrey Borggaard987672d22014-07-18 16:47:18 -0400978 byte[] saltedPassword = (password + getSalt(userId)).getBytes();
Narayan Kamath78108a32014-12-16 12:56:23 +0000979 byte[] sha1 = MessageDigest.getInstance("SHA-1").digest(saltedPassword);
980 byte[] md5 = MessageDigest.getInstance("MD5").digest(saltedPassword);
Jim Miller69aa4a92009-12-22 19:03:28 -0800981
Narayan Kamath78108a32014-12-16 12:56:23 +0000982 byte[] combined = new byte[sha1.length + md5.length];
983 System.arraycopy(sha1, 0, combined, 0, sha1.length);
984 System.arraycopy(md5, 0, combined, sha1.length, md5.length);
985
986 final char[] hexEncoded = HexEncoding.encode(combined);
987 return new String(hexEncoded).getBytes(StandardCharsets.UTF_8);
988 } catch (NoSuchAlgorithmException e) {
989 throw new AssertionError("Missing digest algorithm: ", e);
Jim Miller69aa4a92009-12-22 19:03:28 -0800990 }
Jim Miller69aa4a92009-12-22 19:03:28 -0800991 }
992
993 /**
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100994 * @param userId the user for which to report the value
995 * @return Whether the lock screen is secured.
996 */
997 public boolean isSecure(int userId) {
998 int mode = getKeyguardStoredPasswordQuality(userId);
999 return isLockPatternEnabled(mode, userId) || isLockPasswordEnabled(mode, userId);
1000 }
1001
Adrian Roosdce01222015-01-07 22:39:01 +01001002 public boolean isLockPasswordEnabled(int userId) {
Adrian Roos9dd16eb2015-01-08 16:20:49 +01001003 return isLockPasswordEnabled(getKeyguardStoredPasswordQuality(userId), userId);
1004 }
1005
1006 private boolean isLockPasswordEnabled(int mode, int userId) {
Danielle Millett73da5fe2011-09-13 16:20:05 -04001007 final boolean passwordEnabled = mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC
1008 || mode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC
Jim Miller85516d02014-01-31 17:08:37 -08001009 || mode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX
Danielle Millett73da5fe2011-09-13 16:20:05 -04001010 || mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC
1011 || mode == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
Adrian Roos9dd16eb2015-01-08 16:20:49 +01001012 return passwordEnabled && savedPasswordExists(userId);
Jim Miller69aa4a92009-12-22 19:03:28 -08001013 }
1014
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001015 /**
Adrian Roos230635e2015-01-07 20:50:29 +01001016 * @return Whether the lock pattern is enabled
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001017 */
Adrian Roos50bfeec2014-11-20 16:21:11 +01001018 public boolean isLockPatternEnabled(int userId) {
Adrian Roos9dd16eb2015-01-08 16:20:49 +01001019 return isLockPatternEnabled(getKeyguardStoredPasswordQuality(userId), userId);
Danielle Millett925a7d82012-03-19 18:02:20 -04001020 }
1021
Bryce Lee46145962015-12-14 14:39:10 -08001022 @Deprecated
1023 public boolean isLegacyLockPatternEnabled(int userId) {
1024 // Note: this value should default to {@code true} to avoid any reset that might result.
1025 // We must use a special key to read this value, since it will by default return the value
1026 // based on the new logic.
1027 return getBoolean(LEGACY_LOCK_PATTERN_ENABLED, true, userId);
1028 }
1029
1030 @Deprecated
1031 public void setLegacyLockPatternEnabled(int userId) {
1032 setBoolean(Settings.Secure.LOCK_PATTERN_ENABLED, true, userId);
1033 }
1034
Adrian Roos9dd16eb2015-01-08 16:20:49 +01001035 private boolean isLockPatternEnabled(int mode, int userId) {
1036 return mode == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING
1037 && savedPatternExists(userId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001038 }
1039
1040 /**
1041 * @return Whether the visible pattern is enabled.
1042 */
Adrian Roos8150d2a2015-04-16 17:11:20 -07001043 public boolean isVisiblePatternEnabled(int userId) {
1044 return getBoolean(Settings.Secure.LOCK_PATTERN_VISIBLE, false, userId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001045 }
1046
1047 /**
1048 * Set whether the visible pattern is enabled.
1049 */
Adrian Roos8150d2a2015-04-16 17:11:20 -07001050 public void setVisiblePatternEnabled(boolean enabled, int userId) {
Adrian Roosdce01222015-01-07 22:39:01 +01001051 setBoolean(Settings.Secure.LOCK_PATTERN_VISIBLE, enabled, userId);
Paul Lawrence878ba0a2014-08-20 13:08:01 -07001052
1053 // Update for crypto if owner
Xiaohui Chen86c69dd2015-08-27 15:44:02 -07001054 if (userId != UserHandle.USER_SYSTEM) {
Paul Lawrence878ba0a2014-08-20 13:08:01 -07001055 return;
1056 }
1057
1058 IBinder service = ServiceManager.getService("mount");
1059 if (service == null) {
1060 Log.e(TAG, "Could not find the mount service to update the user info");
1061 return;
1062 }
1063
1064 IMountService mountService = IMountService.Stub.asInterface(service);
1065 try {
Elliott Hughesf839b4f2014-09-26 12:30:47 -07001066 mountService.setField(StorageManager.PATTERN_VISIBLE_KEY, enabled ? "1" : "0");
Paul Lawrence878ba0a2014-08-20 13:08:01 -07001067 } catch (RemoteException e) {
1068 Log.e(TAG, "Error changing pattern visible state", e);
1069 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001070 }
1071
1072 /**
Paul Lawrenced8fdb332015-05-18 13:26:11 -07001073 * Set whether the visible password is enabled for cryptkeeper screen.
1074 */
1075 public void setVisiblePasswordEnabled(boolean enabled, int userId) {
1076 // Update for crypto if owner
Xiaohui Chen86c69dd2015-08-27 15:44:02 -07001077 if (userId != UserHandle.USER_SYSTEM) {
Paul Lawrenced8fdb332015-05-18 13:26:11 -07001078 return;
1079 }
1080
1081 IBinder service = ServiceManager.getService("mount");
1082 if (service == null) {
1083 Log.e(TAG, "Could not find the mount service to update the user info");
1084 return;
1085 }
1086
1087 IMountService mountService = IMountService.Stub.asInterface(service);
1088 try {
1089 mountService.setField(StorageManager.PASSWORD_VISIBLE_KEY, enabled ? "1" : "0");
1090 } catch (RemoteException e) {
1091 Log.e(TAG, "Error changing password visible state", e);
1092 }
1093 }
1094
1095 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001096 * @return Whether tactile feedback for the pattern is enabled.
1097 */
1098 public boolean isTactileFeedbackEnabled() {
Jeff Sharkey5ed9d682012-10-10 14:28:27 -07001099 return Settings.System.getIntForUser(mContentResolver,
1100 Settings.System.HAPTIC_FEEDBACK_ENABLED, 1, UserHandle.USER_CURRENT) != 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001101 }
1102
1103 /**
1104 * Set and store the lockout deadline, meaning the user can't attempt his/her unlock
1105 * pattern until the deadline has passed.
1106 * @return the chosen deadline.
1107 */
Andres Morales23974272015-05-14 22:42:26 -07001108 public long setLockoutAttemptDeadline(int userId, int timeoutMs) {
1109 final long deadline = SystemClock.elapsedRealtime() + timeoutMs;
Adrian Roos8150d2a2015-04-16 17:11:20 -07001110 setLong(LOCKOUT_ATTEMPT_DEADLINE, deadline, userId);
Andres Morales23974272015-05-14 22:42:26 -07001111 setLong(LOCKOUT_ATTEMPT_TIMEOUT_MS, timeoutMs, userId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001112 return deadline;
1113 }
1114
1115 /**
1116 * @return The elapsed time in millis in the future when the user is allowed to
1117 * attempt to enter his/her lock pattern, or 0 if the user is welcome to
1118 * enter a pattern.
1119 */
Adrian Roos8150d2a2015-04-16 17:11:20 -07001120 public long getLockoutAttemptDeadline(int userId) {
Andres Moralesa4e23372015-09-08 13:17:37 -07001121 long deadline = getLong(LOCKOUT_ATTEMPT_DEADLINE, 0L, userId);
Andres Morales23974272015-05-14 22:42:26 -07001122 final long timeoutMs = getLong(LOCKOUT_ATTEMPT_TIMEOUT_MS, 0L, userId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001123 final long now = SystemClock.elapsedRealtime();
Jorim Jaggie3e6d562015-09-28 13:57:37 -07001124 if (deadline < now && deadline != 0) {
Andres Moralesa4e23372015-09-08 13:17:37 -07001125 // timeout expired
1126 setLong(LOCKOUT_ATTEMPT_DEADLINE, 0, userId);
1127 setLong(LOCKOUT_ATTEMPT_TIMEOUT_MS, 0, userId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001128 return 0L;
1129 }
Andres Moralesa4e23372015-09-08 13:17:37 -07001130
1131 if (deadline > (now + timeoutMs)) {
1132 // device was rebooted, set new deadline
1133 deadline = now + timeoutMs;
1134 setLong(LOCKOUT_ATTEMPT_DEADLINE, deadline, userId);
1135 }
1136
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001137 return deadline;
1138 }
1139
Jim Millerf45bb402013-08-20 18:58:32 -07001140 private boolean getBoolean(String secureSettingKey, boolean defaultValue, int userId) {
Amith Yamasani52c489c2012-03-28 11:42:42 -07001141 try {
Jim Millerf45bb402013-08-20 18:58:32 -07001142 return getLockSettings().getBoolean(secureSettingKey, defaultValue, userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -07001143 } catch (RemoteException re) {
1144 return defaultValue;
1145 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001146 }
1147
Jim Millerf45bb402013-08-20 18:58:32 -07001148 private void setBoolean(String secureSettingKey, boolean enabled, int userId) {
Amith Yamasani52c489c2012-03-28 11:42:42 -07001149 try {
Jim Millerf45bb402013-08-20 18:58:32 -07001150 getLockSettings().setBoolean(secureSettingKey, enabled, userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -07001151 } catch (RemoteException re) {
1152 // What can we do?
1153 Log.e(TAG, "Couldn't write boolean " + secureSettingKey + re);
1154 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001155 }
1156
Geoffrey Borggaard987672d22014-07-18 16:47:18 -04001157 private long getLong(String secureSettingKey, long defaultValue, int userHandle) {
1158 try {
1159 return getLockSettings().getLong(secureSettingKey, defaultValue, userHandle);
1160 } catch (RemoteException re) {
1161 return defaultValue;
1162 }
1163 }
1164
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001165 private void setLong(String secureSettingKey, long value, int userHandle) {
Amith Yamasani52c489c2012-03-28 11:42:42 -07001166 try {
Kenny Guy0cf13702013-11-29 16:33:05 +00001167 getLockSettings().setLong(secureSettingKey, value, userHandle);
Amith Yamasani52c489c2012-03-28 11:42:42 -07001168 } catch (RemoteException re) {
1169 // What can we do?
1170 Log.e(TAG, "Couldn't write long " + secureSettingKey + re);
1171 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001172 }
1173
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001174 private String getString(String secureSettingKey, int userHandle) {
Amith Yamasani52c489c2012-03-28 11:42:42 -07001175 try {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001176 return getLockSettings().getString(secureSettingKey, null, userHandle);
Amith Yamasani52c489c2012-03-28 11:42:42 -07001177 } catch (RemoteException re) {
1178 return null;
1179 }
Konstantin Lopyrev863f22d2010-05-12 17:16:58 -07001180 }
1181
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001182 private void setString(String secureSettingKey, String value, int userHandle) {
Amith Yamasani52c489c2012-03-28 11:42:42 -07001183 try {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001184 getLockSettings().setString(secureSettingKey, value, userHandle);
Amith Yamasani52c489c2012-03-28 11:42:42 -07001185 } catch (RemoteException re) {
1186 // What can we do?
1187 Log.e(TAG, "Couldn't write string " + secureSettingKey + re);
1188 }
Konstantin Lopyrev863f22d2010-05-12 17:16:58 -07001189 }
1190
Adrian Roos8150d2a2015-04-16 17:11:20 -07001191 public void setPowerButtonInstantlyLocks(boolean enabled, int userId) {
1192 setBoolean(LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS, enabled, userId);
Jim Millera4edd152012-01-06 18:24:04 -08001193 }
1194
Adrian Roos8150d2a2015-04-16 17:11:20 -07001195 public boolean getPowerButtonInstantlyLocks(int userId) {
1196 return getBoolean(LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS, true, userId);
Adrian Roos82142c22014-03-27 14:56:59 +01001197 }
1198
1199 public void setEnabledTrustAgents(Collection<ComponentName> activeTrustAgents, int userId) {
1200 StringBuilder sb = new StringBuilder();
1201 for (ComponentName cn : activeTrustAgents) {
1202 if (sb.length() > 0) {
1203 sb.append(',');
1204 }
1205 sb.append(cn.flattenToShortString());
1206 }
1207 setString(ENABLED_TRUST_AGENTS, sb.toString(), userId);
Adrian Roos8150d2a2015-04-16 17:11:20 -07001208 getTrustManager().reportEnabledTrustAgentsChanged(userId);
Adrian Roos82142c22014-03-27 14:56:59 +01001209 }
1210
1211 public List<ComponentName> getEnabledTrustAgents(int userId) {
1212 String serialized = getString(ENABLED_TRUST_AGENTS, userId);
1213 if (TextUtils.isEmpty(serialized)) {
1214 return null;
1215 }
1216 String[] split = serialized.split(",");
1217 ArrayList<ComponentName> activeTrustAgents = new ArrayList<ComponentName>(split.length);
1218 for (String s : split) {
1219 if (!TextUtils.isEmpty(s)) {
1220 activeTrustAgents.add(ComponentName.unflattenFromString(s));
1221 }
1222 }
1223 return activeTrustAgents;
1224 }
Adrian Roos2c12cfa2014-06-25 23:28:53 +02001225
1226 /**
Adrian Roosb5e47222015-08-14 15:53:06 -07001227 * Disable trust until credentials have been entered for user {@param userId}.
1228 *
1229 * Requires the {@link android.Manifest.permission#ACCESS_KEYGUARD_SECURE_STORAGE} permission.
1230 *
1231 * @param userId either an explicit user id or {@link android.os.UserHandle#USER_ALL}
Adrian Roos2c12cfa2014-06-25 23:28:53 +02001232 */
1233 public void requireCredentialEntry(int userId) {
Jorim Jaggi16093fe32015-09-09 23:29:17 +00001234 requireStrongAuth(StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST, userId);
Adrian Roosb5e47222015-08-14 15:53:06 -07001235 }
1236
1237 /**
1238 * Requests strong authentication for user {@param userId}.
1239 *
1240 * Requires the {@link android.Manifest.permission#ACCESS_KEYGUARD_SECURE_STORAGE} permission.
1241 *
1242 * @param strongAuthReason a combination of {@link StrongAuthTracker.StrongAuthFlags} indicating
1243 * the reason for and the strength of the requested authentication.
1244 * @param userId either an explicit user id or {@link android.os.UserHandle#USER_ALL}
1245 */
1246 public void requireStrongAuth(@StrongAuthTracker.StrongAuthFlags int strongAuthReason,
1247 int userId) {
1248 try {
1249 getLockSettings().requireStrongAuth(strongAuthReason, userId);
1250 } catch (RemoteException e) {
1251 Log.e(TAG, "Error while requesting strong auth: " + e);
1252 }
Adrian Roos2c12cfa2014-06-25 23:28:53 +02001253 }
Adrian Roos4b9e3242014-08-20 23:36:25 +02001254
Adrian Roosf8f56bc2014-11-20 23:55:34 +01001255 private void onAfterChangingPassword(int userHandle) {
1256 getTrustManager().reportEnabledTrustAgentsChanged(userHandle);
Adrian Roos4b9e3242014-08-20 23:36:25 +02001257 }
Jim Millerdd5de712014-10-16 19:50:18 -07001258
1259 public boolean isCredentialRequiredToDecrypt(boolean defaultValue) {
1260 final int value = Settings.Global.getInt(mContentResolver,
1261 Settings.Global.REQUIRE_PASSWORD_TO_DECRYPT, -1);
1262 return value == -1 ? defaultValue : (value != 0);
1263 }
1264
1265 public void setCredentialRequiredToDecrypt(boolean required) {
Xiaohui Chen86c69dd2015-08-27 15:44:02 -07001266 if (ActivityManager.getCurrentUser() != UserHandle.USER_SYSTEM) {
Jim Millerdd5de712014-10-16 19:50:18 -07001267 Log.w(TAG, "Only device owner may call setCredentialRequiredForDecrypt()");
1268 return;
1269 }
Paul Lawrence688af6c2015-05-15 11:26:17 -07001270
1271 if (isDeviceEncryptionEnabled()){
1272 Settings.Global.putInt(mContext.getContentResolver(),
1273 Settings.Global.REQUIRE_PASSWORD_TO_DECRYPT, required ? 1 : 0);
1274 }
Jim Millerdd5de712014-10-16 19:50:18 -07001275 }
Andrei Kapishnikov4eb6a362015-04-02 15:21:20 -04001276
1277 private boolean isDoNotAskCredentialsOnBootSet() {
1278 return mDevicePolicyManager.getDoNotAskCredentialsOnBoot();
1279 }
1280
1281 private boolean shouldEncryptWithCredentials(boolean defaultValue) {
1282 return isCredentialRequiredToDecrypt(defaultValue) && !isDoNotAskCredentialsOnBootSet();
1283 }
Xiyuan Xiaaa262942015-05-05 15:18:45 -07001284
1285 private void throwIfCalledOnMainThread() {
1286 if (Looper.getMainLooper().isCurrentThread()) {
1287 throw new IllegalStateException("should not be called from the main thread.");
1288 }
1289 }
Adrian Roosb5e47222015-08-14 15:53:06 -07001290
Clara Bayarri10ad84a2015-12-01 17:38:05 +00001291 public static boolean isSeparateWorkChallengeEnabled() {
1292 return StorageManager.isFileBasedEncryptionEnabled();
1293 }
1294
Adrian Roosb5e47222015-08-14 15:53:06 -07001295 public void registerStrongAuthTracker(final StrongAuthTracker strongAuthTracker) {
1296 try {
1297 getLockSettings().registerStrongAuthTracker(strongAuthTracker.mStub);
1298 } catch (RemoteException e) {
1299 throw new RuntimeException("Could not register StrongAuthTracker");
1300 }
1301 }
1302
1303 public void unregisterStrongAuthTracker(final StrongAuthTracker strongAuthTracker) {
1304 try {
1305 getLockSettings().unregisterStrongAuthTracker(strongAuthTracker.mStub);
1306 } catch (RemoteException e) {
1307 Log.e(TAG, "Could not unregister StrongAuthTracker", e);
1308 }
1309 }
1310
1311 /**
1312 * Tracks the global strong authentication state.
1313 */
1314 public static class StrongAuthTracker {
1315
1316 @IntDef(flag = true,
1317 value = { STRONG_AUTH_NOT_REQUIRED,
1318 STRONG_AUTH_REQUIRED_AFTER_BOOT,
1319 STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW,
Jorim Jaggi16093fe32015-09-09 23:29:17 +00001320 SOME_AUTH_REQUIRED_AFTER_USER_REQUEST})
Adrian Roosb5e47222015-08-14 15:53:06 -07001321 @Retention(RetentionPolicy.SOURCE)
1322 public @interface StrongAuthFlags {}
1323
1324 /**
1325 * Strong authentication is not required.
1326 */
1327 public static final int STRONG_AUTH_NOT_REQUIRED = 0x0;
1328
1329 /**
1330 * Strong authentication is required because the user has not authenticated since boot.
1331 */
1332 public static final int STRONG_AUTH_REQUIRED_AFTER_BOOT = 0x1;
1333
1334 /**
Jorim Jaggi16093fe32015-09-09 23:29:17 +00001335 * Strong authentication is required because a device admin has requested it.
Adrian Roosb5e47222015-08-14 15:53:06 -07001336 */
1337 public static final int STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW = 0x2;
1338
1339 /**
Jorim Jaggi16093fe32015-09-09 23:29:17 +00001340 * Some authentication is required because the user has temporarily disabled trust.
Adrian Roosb5e47222015-08-14 15:53:06 -07001341 */
Jorim Jaggi16093fe32015-09-09 23:29:17 +00001342 public static final int SOME_AUTH_REQUIRED_AFTER_USER_REQUEST = 0x4;
Adrian Roosb5e47222015-08-14 15:53:06 -07001343
Adrian Roos873010d2015-08-25 15:59:00 -07001344 /**
1345 * Strong authentication is required because the user has been locked out after too many
1346 * attempts.
1347 */
1348 public static final int STRONG_AUTH_REQUIRED_AFTER_LOCKOUT = 0x8;
1349
Adrian Roosaf4ab3e2015-09-02 13:23:30 -07001350 /**
1351 * Some authentication is required because the user has entered a wrong credential.
1352 */
1353 public static final int SOME_AUTH_REQUIRED_AFTER_WRONG_CREDENTIAL = 0x10;
1354
Adrian Roosb5e47222015-08-14 15:53:06 -07001355 public static final int DEFAULT = STRONG_AUTH_REQUIRED_AFTER_BOOT;
Adrian Roosb5e47222015-08-14 15:53:06 -07001356
Adrian Roosaf4ab3e2015-09-02 13:23:30 -07001357 private static final int ALLOWING_FINGERPRINT = STRONG_AUTH_NOT_REQUIRED
Jorim Jaggi16093fe32015-09-09 23:29:17 +00001358 | SOME_AUTH_REQUIRED_AFTER_USER_REQUEST
Adrian Roosaf4ab3e2015-09-02 13:23:30 -07001359 | SOME_AUTH_REQUIRED_AFTER_WRONG_CREDENTIAL;
Adrian Roosb5e47222015-08-14 15:53:06 -07001360
Adrian Roosaf4ab3e2015-09-02 13:23:30 -07001361 private final SparseIntArray mStrongAuthRequiredForUser = new SparseIntArray();
Adrian Roosb5e47222015-08-14 15:53:06 -07001362 private final H mHandler;
1363
1364 public StrongAuthTracker() {
1365 this(Looper.myLooper());
1366 }
1367
1368 /**
1369 * @param looper the looper on whose thread calls to {@link #onStrongAuthRequiredChanged}
1370 * will be scheduled.
1371 */
1372 public StrongAuthTracker(Looper looper) {
1373 mHandler = new H(looper);
1374 }
1375
1376 /**
1377 * Returns {@link #STRONG_AUTH_NOT_REQUIRED} if strong authentication is not required,
1378 * otherwise returns a combination of {@link StrongAuthFlags} indicating why strong
1379 * authentication is required.
1380 *
1381 * @param userId the user for whom the state is queried.
1382 */
1383 public @StrongAuthFlags int getStrongAuthForUser(int userId) {
1384 return mStrongAuthRequiredForUser.get(userId, DEFAULT);
1385 }
1386
1387 /**
1388 * @return true if unlocking with trust alone is allowed for {@param userId} by the current
1389 * strong authentication requirements.
1390 */
1391 public boolean isTrustAllowedForUser(int userId) {
1392 return getStrongAuthForUser(userId) == STRONG_AUTH_NOT_REQUIRED;
1393 }
1394
1395 /**
1396 * @return true if unlocking with fingerprint alone is allowed for {@param userId} by the
1397 * current strong authentication requirements.
1398 */
1399 public boolean isFingerprintAllowedForUser(int userId) {
Adrian Roosaf4ab3e2015-09-02 13:23:30 -07001400 return (getStrongAuthForUser(userId) & ~ALLOWING_FINGERPRINT) == 0;
Adrian Roosb5e47222015-08-14 15:53:06 -07001401 }
1402
1403 /**
1404 * Called when the strong authentication requirements for {@param userId} changed.
1405 */
1406 public void onStrongAuthRequiredChanged(int userId) {
1407 }
1408
1409 void handleStrongAuthRequiredChanged(@StrongAuthFlags int strongAuthFlags,
1410 int userId) {
1411
1412 int oldValue = getStrongAuthForUser(userId);
1413 if (strongAuthFlags != oldValue) {
1414 if (strongAuthFlags == DEFAULT) {
1415 mStrongAuthRequiredForUser.delete(userId);
1416 } else {
1417 mStrongAuthRequiredForUser.put(userId, strongAuthFlags);
1418 }
1419 onStrongAuthRequiredChanged(userId);
1420 }
1421 }
1422
1423
1424 final IStrongAuthTracker.Stub mStub = new IStrongAuthTracker.Stub() {
1425 @Override
1426 public void onStrongAuthRequiredChanged(@StrongAuthFlags int strongAuthFlags,
1427 int userId) {
1428 mHandler.obtainMessage(H.MSG_ON_STRONG_AUTH_REQUIRED_CHANGED,
1429 strongAuthFlags, userId).sendToTarget();
1430 }
1431 };
1432
1433 private class H extends Handler {
1434 static final int MSG_ON_STRONG_AUTH_REQUIRED_CHANGED = 1;
1435
1436 public H(Looper looper) {
1437 super(looper);
1438 }
1439
1440 @Override
1441 public void handleMessage(Message msg) {
1442 switch (msg.what) {
1443 case MSG_ON_STRONG_AUTH_REQUIRED_CHANGED:
1444 handleStrongAuthRequiredChanged(msg.arg1, msg.arg2);
1445 break;
1446 }
1447 }
1448 };
1449 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001450}