blob: 9d1447836b93d95160b3a3c42d41e3171e922316 [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;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -080020import android.app.admin.DevicePolicyManager;
Adrian Roosb5e47222015-08-14 15:53:06 -070021import android.app.trust.IStrongAuthTracker;
Adrian Roos82142c22014-03-27 14:56:59 +010022import android.app.trust.TrustManager;
Adrian Roos82142c22014-03-27 14:56:59 +010023import android.content.ComponentName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080024import android.content.ContentResolver;
Jim Miller31f90b62010-01-20 13:35:20 -080025import android.content.Context;
Clara Bayarria1771112015-12-18 16:29:18 +000026import android.content.pm.UserInfo;
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;
Clara Bayarria1771112015-12-18 16:29:18 +000037import android.os.UserManager;
Jason parksf7b3cd42011-01-27 09:28:25 -060038import android.os.storage.IMountService;
Paul Lawrence8e397362014-01-27 15:22:30 -080039import android.os.storage.StorageManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080040import android.provider.Settings;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080041import android.text.TextUtils;
42import android.util.Log;
Adrian Roosb5e47222015-08-14 15:53:06 -070043import android.util.SparseIntArray;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080044
Michael Jurka1254f2f2012-10-25 11:44:31 -070045import com.google.android.collect.Lists;
Adrian Roos9dd16eb2015-01-08 16:20:49 +010046
Adrian Roosb5e47222015-08-14 15:53:06 -070047import java.lang.annotation.Retention;
48import java.lang.annotation.RetentionPolicy;
Narayan Kamath78108a32014-12-16 12:56:23 +000049import java.nio.charset.StandardCharsets;
Brian Carlstrom929a1c22011-02-01 21:54:09 -080050import java.security.MessageDigest;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080051import java.security.NoSuchAlgorithmException;
Jim Miller11b019d2010-01-20 16:34:45 -080052import java.security.SecureRandom;
Adrian Roos82142c22014-03-27 14:56:59 +010053import java.util.ArrayList;
54import java.util.Collection;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080055import java.util.List;
56
Adrian Roosc2e01682015-01-15 23:20:20 +010057import libcore.util.HexEncoding;
58
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080059/**
Brian Carlstrom5cfee3f2011-05-31 01:00:15 -070060 * Utilities for the lock pattern and its settings.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080061 */
62public class LockPatternUtils {
63
64 private static final String TAG = "LockPatternUtils";
Brian Colonnaa0ee0042014-07-16 13:50:47 -040065 private static final boolean DEBUG = false;
Jim Miller69aa4a92009-12-22 19:03:28 -080066
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080067 /**
Bryce Lee46145962015-12-14 14:39:10 -080068 * 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 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080073 * 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 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080079 * The interval of the countdown for showing progress of the lockout.
80 */
81 public static final long FAILED_ATTEMPT_COUNTDOWN_INTERVAL_MS = 1000L;
82
Jim Miller4f369952011-08-19 18:29:22 -070083
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
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080090 /**
91 * The minimum number of dots in a valid pattern.
92 */
93 public static final int MIN_LOCK_PATTERN_SIZE = 4;
94
95 /**
Adrian Roosf80e66ce92015-01-15 23:27:24 +010096 * The minimum size of a valid password.
97 */
98 public static final int MIN_LOCK_PASSWORD_SIZE = 4;
99
100 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800101 * 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 */
Jim Miller4f369952011-08-19 18:29:22 -0700105 public static final int MIN_PATTERN_REGISTER_FAIL = MIN_LOCK_PATTERN_SIZE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800106
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100107 @Deprecated
Jeff Sharkey7a96c392012-11-15 14:01:46 -0800108 public final static String LOCKOUT_PERMANENT_KEY = "lockscreen.lockedoutpermanently";
109 public final static String LOCKOUT_ATTEMPT_DEADLINE = "lockscreen.lockoutattemptdeadline";
Andres Morales23974272015-05-14 22:42:26 -0700110 public final static String LOCKOUT_ATTEMPT_TIMEOUT_MS = "lockscreen.lockoutattempttimeoutmss";
Jeff Sharkey7a96c392012-11-15 14:01:46 -0800111 public final static String PATTERN_EVER_CHOSEN_KEY = "lockscreen.patterneverchosen";
Jim Miller69aa4a92009-12-22 19:03:28 -0800112 public final static String PASSWORD_TYPE_KEY = "lockscreen.password_type";
Adrian Roos230635e2015-01-07 20:50:29 +0100113 @Deprecated
114 public final static String PASSWORD_TYPE_ALTERNATE_KEY = "lockscreen.password_type_alternate";
Jeff Sharkey7a96c392012-11-15 14:01:46 -0800115 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";
Adrian Roos230635e2015-01-07 20:50:29 +0100118 @Deprecated
Jim Miller6edf2632011-09-05 16:03:14 -0700119 public final static String LOCKSCREEN_BIOMETRIC_WEAK_FALLBACK
120 = "lockscreen.biometric_weak_fallback";
Adrian Roos230635e2015-01-07 20:50:29 +0100121 @Deprecated
Danielle Millett7a072192011-10-03 17:36:01 -0400122 public final static String BIOMETRIC_WEAK_EVER_CHOSEN_KEY
123 = "lockscreen.biometricweakeverchosen";
Jim Millera4edd152012-01-06 18:24:04 -0800124 public final static String LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS
125 = "lockscreen.power_button_instantly_locks";
Adrian Roos230635e2015-01-07 20:50:29 +0100126 @Deprecated
Jim Millerf45bb402013-08-20 18:58:32 -0700127 public final static String LOCKSCREEN_WIDGETS_ENABLED = "lockscreen.widgets_enabled";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800128
Jeff Sharkey7a96c392012-11-15 14:01:46 -0800129 public final static String PASSWORD_HISTORY_KEY = "lockscreen.passwordhistory";
Konstantin Lopyrev863f22d2010-05-12 17:16:58 -0700130
Jim Miller187ec582013-04-15 18:27:54 -0700131 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
Andrei Stingaceanu6644cd92015-11-10 13:03:31 +0000135 private static final String LOCK_SCREEN_DEVICE_OWNER_INFO = "lockscreen.device_owner_info";
136
Adrian Roos82142c22014-03-27 14:56:59 +0100137 private static final String ENABLED_TRUST_AGENTS = "lockscreen.enabledtrustagents";
Adrian Roosc13723f2016-01-12 20:29:03 +0100138 private static final String IS_TRUST_USUALLY_MANAGED = "lockscreen.istrustusuallymanaged";
Adrian Roos82142c22014-03-27 14:56:59 +0100139
Clara Bayarria1771112015-12-18 16:29:18 +0000140 private static final String SEPARATE_PROFILE_CHALLENGE_KEY = "lockscreen.profilechallenge";
141
Jim Miller85516d02014-01-31 17:08:37 -0800142 // Maximum allowed number of repeated or ordered characters in a sequence before we'll
143 // consider it a complex PIN/password.
144 public static final int MAX_ALLOWED_SEQUENCE = 3;
145
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800146 private final Context mContext;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800147 private final ContentResolver mContentResolver;
Jim Miller31f90b62010-01-20 13:35:20 -0800148 private DevicePolicyManager mDevicePolicyManager;
Amith Yamasani52c489c2012-03-28 11:42:42 -0700149 private ILockSettings mLockSettingsService;
Clara Bayarria1771112015-12-18 16:29:18 +0000150 private UserManager mUserManager;
Jim Milleree82f8f2012-10-01 16:26:18 -0700151
Adrian Roosc13723f2016-01-12 20:29:03 +0100152 /**
153 * Use {@link TrustManager#isTrustUsuallyManaged(int)}.
154 *
155 * This returns the lazily-peristed value and should only be used by TrustManagerService.
156 */
157 public boolean isTrustUsuallyManaged(int userId) {
158 if (!(mLockSettingsService instanceof ILockSettings.Stub)) {
159 throw new IllegalStateException("May only be called by TrustManagerService. "
160 + "Use TrustManager.isTrustUsuallyManaged()");
161 }
162 try {
163 return getLockSettings().getBoolean(IS_TRUST_USUALLY_MANAGED, false, userId);
164 } catch (RemoteException e) {
165 return false;
166 }
167 }
168
169 public void setTrustUsuallyManaged(boolean managed, int userId) {
170 try {
171 getLockSettings().setBoolean(IS_TRUST_USUALLY_MANAGED, managed, userId);
172 } catch (RemoteException e) {
173 // System dead.
174 }
175 }
Andres Morales23974272015-05-14 22:42:26 -0700176
177 public static final class RequestThrottledException extends Exception {
178 private int mTimeoutMs;
179 public RequestThrottledException(int timeoutMs) {
180 mTimeoutMs = timeoutMs;
181 }
182
183 /**
184 * @return The amount of time in ms before another request may
185 * be executed
186 */
187 public int getTimeoutMs() {
188 return mTimeoutMs;
189 }
190
191 }
192
Jim Millercd709882010-03-25 18:24:02 -0700193 public DevicePolicyManager getDevicePolicyManager() {
Jim Miller5b0fb3a2010-02-23 13:46:35 -0800194 if (mDevicePolicyManager == null) {
195 mDevicePolicyManager =
196 (DevicePolicyManager)mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
197 if (mDevicePolicyManager == null) {
198 Log.e(TAG, "Can't get DevicePolicyManagerService: is it running?",
199 new IllegalStateException("Stack trace:"));
200 }
201 }
202 return mDevicePolicyManager;
203 }
Amith Yamasani52c489c2012-03-28 11:42:42 -0700204
Clara Bayarria1771112015-12-18 16:29:18 +0000205 private UserManager getUserManager() {
206 if (mUserManager == null) {
207 mUserManager = UserManager.get(mContext);
208 }
209 return mUserManager;
210 }
211
Adrian Roos82142c22014-03-27 14:56:59 +0100212 private TrustManager getTrustManager() {
213 TrustManager trust = (TrustManager) mContext.getSystemService(Context.TRUST_SERVICE);
214 if (trust == null) {
215 Log.e(TAG, "Can't get TrustManagerService: is it running?",
216 new IllegalStateException("Stack trace:"));
217 }
218 return trust;
219 }
220
Jim Miller31f90b62010-01-20 13:35:20 -0800221 public LockPatternUtils(Context context) {
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800222 mContext = context;
Jim Miller31f90b62010-01-20 13:35:20 -0800223 mContentResolver = context.getContentResolver();
Amith Yamasani52c489c2012-03-28 11:42:42 -0700224 }
Jim Miller69aa4a92009-12-22 19:03:28 -0800225
Amith Yamasani52c489c2012-03-28 11:42:42 -0700226 private ILockSettings getLockSettings() {
227 if (mLockSettingsService == null) {
Adrian Roos450ce9f2014-10-29 14:30:37 +0100228 ILockSettings service = ILockSettings.Stub.asInterface(
229 ServiceManager.getService("lock_settings"));
Adrian Roos138b8332014-11-11 13:51:07 +0100230 mLockSettingsService = service;
Brad Fitzpatrick90881002010-08-23 18:30:08 -0700231 }
Amith Yamasani52c489c2012-03-28 11:42:42 -0700232 return mLockSettingsService;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800233 }
234
Adrian Roos8150d2a2015-04-16 17:11:20 -0700235 public int getRequestedMinimumPasswordLength(int userId) {
236 return getDevicePolicyManager().getPasswordMinimumLength(null, userId);
Jim Miller31f90b62010-01-20 13:35:20 -0800237 }
238
Jim Miller31f90b62010-01-20 13:35:20 -0800239 /**
240 * Gets the device policy password mode. If the mode is non-specific, returns
241 * MODE_PATTERN which allows the user to choose anything.
Jim Miller31f90b62010-01-20 13:35:20 -0800242 */
Adrian Roos8150d2a2015-04-16 17:11:20 -0700243 public int getRequestedPasswordQuality(int userId) {
244 return getDevicePolicyManager().getPasswordQuality(null, userId);
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100245 }
246
247 private int getRequestedPasswordHistoryLength(int userId) {
248 return getDevicePolicyManager().getPasswordHistoryLength(null, userId);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700249 }
250
Adrian Roos8150d2a2015-04-16 17:11:20 -0700251 public int getRequestedPasswordMinimumLetters(int userId) {
252 return getDevicePolicyManager().getPasswordMinimumLetters(null, userId);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700253 }
254
Adrian Roos8150d2a2015-04-16 17:11:20 -0700255 public int getRequestedPasswordMinimumUpperCase(int userId) {
256 return getDevicePolicyManager().getPasswordMinimumUpperCase(null, userId);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700257 }
258
Adrian Roos8150d2a2015-04-16 17:11:20 -0700259 public int getRequestedPasswordMinimumLowerCase(int userId) {
260 return getDevicePolicyManager().getPasswordMinimumLowerCase(null, userId);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700261 }
262
Adrian Roos8150d2a2015-04-16 17:11:20 -0700263 public int getRequestedPasswordMinimumNumeric(int userId) {
264 return getDevicePolicyManager().getPasswordMinimumNumeric(null, userId);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700265 }
266
Adrian Roos8150d2a2015-04-16 17:11:20 -0700267 public int getRequestedPasswordMinimumSymbols(int userId) {
268 return getDevicePolicyManager().getPasswordMinimumSymbols(null, userId);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700269 }
270
Adrian Roos8150d2a2015-04-16 17:11:20 -0700271 public int getRequestedPasswordMinimumNonLetter(int userId) {
272 return getDevicePolicyManager().getPasswordMinimumNonLetter(null, userId);
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700273 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700274
Adrian Roos8150d2a2015-04-16 17:11:20 -0700275 public void reportFailedPasswordAttempt(int userId) {
Adrian Roos4f994eb2014-07-23 15:45:05 +0200276 getDevicePolicyManager().reportFailedPasswordAttempt(userId);
277 getTrustManager().reportUnlockAttempt(false /* authenticated */, userId);
Adrian Roosaf4ab3e2015-09-02 13:23:30 -0700278 requireStrongAuth(StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_WRONG_CREDENTIAL, userId);
Jim Miller31f90b62010-01-20 13:35:20 -0800279 }
280
Adrian Roos8150d2a2015-04-16 17:11:20 -0700281 public void reportSuccessfulPasswordAttempt(int userId) {
282 getDevicePolicyManager().reportSuccessfulPasswordAttempt(userId);
283 getTrustManager().reportUnlockAttempt(true /* authenticated */, userId);
Jim Miller31f90b62010-01-20 13:35:20 -0800284 }
285
Clara Bayarri51e41ad2016-02-11 17:48:53 +0000286 public int getCurrentFailedPasswordAttempts(int userId) {
287 return getDevicePolicyManager().getCurrentFailedPasswordAttempts(userId);
288 }
289
290 public int getMaximumFailedPasswordsForWipe(int userId) {
291 return getDevicePolicyManager().getMaximumFailedPasswordsForWipe(
292 null /* componentName */, userId);
293 }
294
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800295 /**
Andres Moralesd9fc85a2015-04-09 19:14:42 -0700296 * Check to see if a pattern matches the saved pattern.
297 * If pattern matches, return an opaque attestation that the challenge
298 * was verified.
299 *
300 * @param pattern The pattern to check.
301 * @param challenge The challenge to verify against the pattern
302 * @return the attestation that the challenge was verified, or null.
303 */
Andres Morales23974272015-05-14 22:42:26 -0700304 public byte[] verifyPattern(List<LockPatternView.Cell> pattern, long challenge, int userId)
305 throws RequestThrottledException {
Xiyuan Xiaaa262942015-05-05 15:18:45 -0700306 throwIfCalledOnMainThread();
Andres Moralesd9fc85a2015-04-09 19:14:42 -0700307 try {
Andres Morales23974272015-05-14 22:42:26 -0700308 VerifyCredentialResponse response =
309 getLockSettings().verifyPattern(patternToString(pattern), challenge, userId);
310 if (response == null) {
311 // Shouldn't happen
312 return null;
313 }
314
315 if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
316 return response.getPayload();
317 } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {
318 throw new RequestThrottledException(response.getTimeout());
319 } else {
320 return null;
321 }
Andres Moralesd9fc85a2015-04-09 19:14:42 -0700322 } catch (RemoteException re) {
323 return null;
324 }
325 }
326
327 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800328 * Check to see if a pattern matches the saved pattern. If no pattern exists,
329 * always returns true.
330 * @param pattern The pattern to check.
Jim Miller69aa4a92009-12-22 19:03:28 -0800331 * @return Whether the pattern matches the stored one.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800332 */
Andres Morales23974272015-05-14 22:42:26 -0700333 public boolean checkPattern(List<LockPatternView.Cell> pattern, int userId)
334 throws RequestThrottledException {
Xiyuan Xiaaa262942015-05-05 15:18:45 -0700335 throwIfCalledOnMainThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800336 try {
Andres Morales23974272015-05-14 22:42:26 -0700337 VerifyCredentialResponse response =
338 getLockSettings().checkPattern(patternToString(pattern), userId);
339
340 if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
341 return true;
342 } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {
343 throw new RequestThrottledException(response.getTimeout());
344 } else {
345 return false;
346 }
Amith Yamasani52c489c2012-03-28 11:42:42 -0700347 } catch (RemoteException re) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800348 return true;
349 }
350 }
351
352 /**
Andres Moralesd9fc85a2015-04-09 19:14:42 -0700353 * Check to see if a password matches the saved password.
354 * If password matches, return an opaque attestation that the challenge
355 * was verified.
356 *
357 * @param password The password to check.
358 * @param challenge The challenge to verify against the password
359 * @return the attestation that the challenge was verified, or null.
360 */
Andres Morales23974272015-05-14 22:42:26 -0700361 public byte[] verifyPassword(String password, long challenge, int userId)
362 throws RequestThrottledException {
Xiyuan Xiaaa262942015-05-05 15:18:45 -0700363 throwIfCalledOnMainThread();
Andres Moralesd9fc85a2015-04-09 19:14:42 -0700364 try {
Andres Morales23974272015-05-14 22:42:26 -0700365 VerifyCredentialResponse response =
366 getLockSettings().verifyPassword(password, challenge, userId);
367
368 if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
369 return response.getPayload();
370 } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {
371 throw new RequestThrottledException(response.getTimeout());
372 } else {
373 return null;
374 }
Andres Moralesd9fc85a2015-04-09 19:14:42 -0700375 } catch (RemoteException re) {
376 return null;
377 }
378 }
379
380 /**
Jim Miller69aa4a92009-12-22 19:03:28 -0800381 * Check to see if a password matches the saved password. If no password exists,
382 * always returns true.
383 * @param password The password to check.
384 * @return Whether the password matches the stored one.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800385 */
Andres Morales23974272015-05-14 22:42:26 -0700386 public boolean checkPassword(String password, int userId) throws RequestThrottledException {
Xiyuan Xiaaa262942015-05-05 15:18:45 -0700387 throwIfCalledOnMainThread();
Jim Miller69aa4a92009-12-22 19:03:28 -0800388 try {
Andres Morales23974272015-05-14 22:42:26 -0700389 VerifyCredentialResponse response =
390 getLockSettings().checkPassword(password, userId);
391 if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
392 return true;
393 } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {
394 throw new RequestThrottledException(response.getTimeout());
395 } else {
396 return false;
397 }
Amith Yamasani52c489c2012-03-28 11:42:42 -0700398 } catch (RemoteException re) {
Jim Miller69aa4a92009-12-22 19:03:28 -0800399 return true;
400 }
401 }
402
403 /**
Paul Lawrence945490c2014-03-27 16:37:28 +0000404 * Check to see if vold already has the password.
405 * Note that this also clears vold's copy of the password.
406 * @return Whether the vold password matches or not.
407 */
Adrian Roos8150d2a2015-04-16 17:11:20 -0700408 public boolean checkVoldPassword(int userId) {
Paul Lawrence945490c2014-03-27 16:37:28 +0000409 try {
410 return getLockSettings().checkVoldPassword(userId);
411 } catch (RemoteException re) {
412 return false;
413 }
414 }
415
416 /**
Konstantin Lopyrev863f22d2010-05-12 17:16:58 -0700417 * Check to see if a password matches any of the passwords stored in the
418 * password history.
419 *
420 * @param password The password to check.
421 * @return Whether the password matches any in the history.
422 */
Adrian Roos8150d2a2015-04-16 17:11:20 -0700423 public boolean checkPasswordHistory(String password, int userId) {
Geoffrey Borggaard987672d22014-07-18 16:47:18 -0400424 String passwordHashString = new String(
Adrian Roosdce01222015-01-07 22:39:01 +0100425 passwordToHash(password, userId), StandardCharsets.UTF_8);
426 String passwordHistory = getString(PASSWORD_HISTORY_KEY, userId);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700427 if (passwordHistory == null) {
428 return false;
429 }
430 // Password History may be too long...
431 int passwordHashLength = passwordHashString.length();
Adrian Roos8150d2a2015-04-16 17:11:20 -0700432 int passwordHistoryLength = getRequestedPasswordHistoryLength(userId);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700433 if(passwordHistoryLength == 0) {
434 return false;
435 }
436 int neededPasswordHistoryLength = passwordHashLength * passwordHistoryLength
437 + passwordHistoryLength - 1;
438 if (passwordHistory.length() > neededPasswordHistoryLength) {
439 passwordHistory = passwordHistory.substring(0, neededPasswordHistoryLength);
440 }
441 return passwordHistory.contains(passwordHashString);
Konstantin Lopyrev863f22d2010-05-12 17:16:58 -0700442 }
443
444 /**
Jim Miller69aa4a92009-12-22 19:03:28 -0800445 * Check to see if the user has stored a lock pattern.
446 * @return Whether a saved pattern exists.
447 */
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100448 private boolean savedPatternExists(int userId) {
Amith Yamasani52c489c2012-03-28 11:42:42 -0700449 try {
Adrian Roos50bfeec2014-11-20 16:21:11 +0100450 return getLockSettings().havePattern(userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -0700451 } catch (RemoteException re) {
452 return false;
453 }
Jim Miller69aa4a92009-12-22 19:03:28 -0800454 }
455
456 /**
457 * Check to see if the user has stored a lock pattern.
458 * @return Whether a saved pattern exists.
459 */
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100460 private boolean savedPasswordExists(int userId) {
Amith Yamasani52c489c2012-03-28 11:42:42 -0700461 try {
Adrian Roos50bfeec2014-11-20 16:21:11 +0100462 return getLockSettings().havePassword(userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -0700463 } catch (RemoteException re) {
464 return false;
465 }
Jim Miller69aa4a92009-12-22 19:03:28 -0800466 }
467
468 /**
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -0700469 * Return true if the user has ever chosen a pattern. This is true even if the pattern is
470 * currently cleared.
471 *
472 * @return True if the user has ever chosen a pattern.
473 */
Adrian Roos8150d2a2015-04-16 17:11:20 -0700474 public boolean isPatternEverChosen(int userId) {
475 return getBoolean(PATTERN_EVER_CHOSEN_KEY, false, userId);
Adrian Roosdce01222015-01-07 22:39:01 +0100476 }
477
478 /**
479 * Used by device policy manager to validate the current password
480 * information it has.
481 */
482 public int getActivePasswordQuality(int userId) {
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100483 int quality = getKeyguardStoredPasswordQuality(userId);
Adrian Roosdce01222015-01-07 22:39:01 +0100484
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100485 if (isLockPasswordEnabled(quality, userId)) {
486 // Quality is a password and a password exists. Return the quality.
487 return quality;
488 }
489
490 if (isLockPatternEnabled(quality, userId)) {
491 // Quality is a pattern and a pattern exists. Return the quality.
492 return quality;
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700493 }
Danielle Millettc8fb5322011-10-04 12:18:51 -0400494
Adrian Roosdce01222015-01-07 22:39:01 +0100495 return DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700496 }
Jim Millercd709882010-03-25 18:24:02 -0700497
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700498 /**
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800499 * Clear any lock pattern or password.
500 */
Adrian Roos230635e2015-01-07 20:50:29 +0100501 public void clearLock(int userHandle) {
Adrian Roosf8f56bc2014-11-20 23:55:34 +0100502 setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, userHandle);
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100503
504 try {
Andres Morales8fa56652015-03-31 09:19:50 -0700505 getLockSettings().setLockPassword(null, null, userHandle);
506 getLockSettings().setLockPattern(null, null, userHandle);
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100507 } catch (RemoteException e) {
508 // well, we tried...
509 }
510
Xiaohui Chen86c69dd2015-08-27 15:44:02 -0700511 if (userHandle == UserHandle.USER_SYSTEM) {
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100512 // Set the encryption password to default.
513 updateEncryptionPassword(StorageManager.CRYPT_TYPE_DEFAULT, null);
Robin Leed39113e2016-01-22 15:44:49 +0000514 setCredentialRequiredToDecrypt(false);
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100515 }
516
517 getDevicePolicyManager().setActivePasswordState(
518 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 0, 0, 0, 0, 0, 0, 0, userHandle);
519
Adrian Roosf8f56bc2014-11-20 23:55:34 +0100520 onAfterChangingPassword(userHandle);
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800521 }
Jim Miller5b0fb3a2010-02-23 13:46:35 -0800522
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800523 /**
Benjamin Franz51ed7942015-04-07 16:34:56 +0100524 * Disable showing lock screen at all for a given user.
525 * This is only meaningful if pattern, pin or password are not set.
Jim Miller2a98a4c2010-11-19 18:49:26 -0800526 *
Benjamin Franz51ed7942015-04-07 16:34:56 +0100527 * @param disable Disables lock screen when true
528 * @param userId User ID of the user this has effect on
529 */
530 public void setLockScreenDisabled(boolean disable, int userId) {
531 setBoolean(DISABLE_LOCKSCREEN_KEY, disable, userId);
532 }
533
534 /**
535 * Determine if LockScreen is disabled for the current user. This is used to decide whether
536 * LockScreen is shown after reboot or after screen timeout / short press on power.
537 *
538 * @return true if lock screen is disabled
Jim Miller2a98a4c2010-11-19 18:49:26 -0800539 */
Adrian Roos8150d2a2015-04-16 17:11:20 -0700540 public boolean isLockScreenDisabled(int userId) {
541 return !isSecure(userId) &&
542 getBoolean(DISABLE_LOCKSCREEN_KEY, false, userId);
Jim Miller2a98a4c2010-11-19 18:49:26 -0800543 }
544
545 /**
Jim Miller6edf2632011-09-05 16:03:14 -0700546 * Save a lock pattern.
547 * @param pattern The new pattern to save.
Adrian Roos8150d2a2015-04-16 17:11:20 -0700548 * @param userId the user whose pattern is to be saved.
Danielle Millett2364a222011-12-21 17:02:32 -0500549 */
Andres Morales8fa56652015-03-31 09:19:50 -0700550 public void saveLockPattern(List<LockPatternView.Cell> pattern, int userId) {
551 this.saveLockPattern(pattern, null, userId);
552 }
Danielle Millett2364a222011-12-21 17:02:32 -0500553 /**
554 * Save a lock pattern.
555 * @param pattern The new pattern to save.
Andres Morales8fa56652015-03-31 09:19:50 -0700556 * @param savedPattern The previously saved pattern, converted to String format
Adrian Roosf8f56bc2014-11-20 23:55:34 +0100557 * @param userId the user whose pattern is to be saved.
558 */
Andres Morales8fa56652015-03-31 09:19:50 -0700559 public void saveLockPattern(List<LockPatternView.Cell> pattern, String savedPattern, int userId) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800560 try {
Adrian Roosf80e66ce92015-01-15 23:27:24 +0100561 if (pattern == null || pattern.size() < MIN_LOCK_PATTERN_SIZE) {
562 throw new IllegalArgumentException("pattern must not be null and at least "
563 + MIN_LOCK_PATTERN_SIZE + " dots long.");
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100564 }
565
Andres Morales8fa56652015-03-31 09:19:50 -0700566 getLockSettings().setLockPattern(patternToString(pattern), savedPattern, userId);
Dianne Hackborn2509d3c2010-03-08 12:54:25 -0800567 DevicePolicyManager dpm = getDevicePolicyManager();
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100568
569 // Update the device encryption password.
Xiaohui Chen86c69dd2015-08-27 15:44:02 -0700570 if (userId == UserHandle.USER_SYSTEM
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100571 && LockPatternUtils.isDeviceEncryptionEnabled()) {
Andrei Kapishnikov4eb6a362015-04-02 15:21:20 -0400572 if (!shouldEncryptWithCredentials(true)) {
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100573 clearEncryptionPassword();
574 } else {
575 String stringPattern = patternToString(pattern);
576 updateEncryptionPassword(StorageManager.CRYPT_TYPE_PATTERN, stringPattern);
Paul Lawrence8e397362014-01-27 15:22:30 -0800577 }
Jim Miller31f90b62010-01-20 13:35:20 -0800578 }
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100579
580 setBoolean(PATTERN_EVER_CHOSEN_KEY, true, userId);
581
582 setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, userId);
583 dpm.setActivePasswordState(DevicePolicyManager.PASSWORD_QUALITY_SOMETHING,
584 pattern.size(), 0, 0, 0, 0, 0, 0, userId);
Adrian Roosf8f56bc2014-11-20 23:55:34 +0100585 onAfterChangingPassword(userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -0700586 } catch (RemoteException re) {
587 Log.e(TAG, "Couldn't save lock pattern " + re);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800588 }
589 }
590
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100591 private void updateCryptoUserInfo(int userId) {
Xiaohui Chen86c69dd2015-08-27 15:44:02 -0700592 if (userId != UserHandle.USER_SYSTEM) {
Paul Lawrencee51dcf92014-03-18 10:56:00 -0700593 return;
594 }
595
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100596 final String ownerInfo = isOwnerInfoEnabled(userId) ? getOwnerInfo(userId) : "";
Paul Lawrencee51dcf92014-03-18 10:56:00 -0700597
598 IBinder service = ServiceManager.getService("mount");
599 if (service == null) {
600 Log.e(TAG, "Could not find the mount service to update the user info");
601 return;
602 }
603
604 IMountService mountService = IMountService.Stub.asInterface(service);
605 try {
606 Log.d(TAG, "Setting owner info");
Elliott Hughesf839b4f2014-09-26 12:30:47 -0700607 mountService.setField(StorageManager.OWNER_INFO_KEY, ownerInfo);
Paul Lawrencee51dcf92014-03-18 10:56:00 -0700608 } catch (RemoteException e) {
609 Log.e(TAG, "Error changing user info", e);
610 }
611 }
612
Jim Miller187ec582013-04-15 18:27:54 -0700613 public void setOwnerInfo(String info, int userId) {
614 setString(LOCK_SCREEN_OWNER_INFO, info, userId);
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100615 updateCryptoUserInfo(userId);
Jim Miller187ec582013-04-15 18:27:54 -0700616 }
617
Adrian Roos8150d2a2015-04-16 17:11:20 -0700618 public void setOwnerInfoEnabled(boolean enabled, int userId) {
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100619 setBoolean(LOCK_SCREEN_OWNER_INFO_ENABLED, enabled, userId);
620 updateCryptoUserInfo(userId);
Jim Miller187ec582013-04-15 18:27:54 -0700621 }
622
623 public String getOwnerInfo(int userId) {
Adrian Roosdce01222015-01-07 22:39:01 +0100624 return getString(LOCK_SCREEN_OWNER_INFO, userId);
Jim Miller187ec582013-04-15 18:27:54 -0700625 }
626
Adrian Roos8150d2a2015-04-16 17:11:20 -0700627 public boolean isOwnerInfoEnabled(int userId) {
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100628 return getBoolean(LOCK_SCREEN_OWNER_INFO_ENABLED, false, userId);
Jim Miller187ec582013-04-15 18:27:54 -0700629 }
630
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800631 /**
Andrei Stingaceanu6644cd92015-11-10 13:03:31 +0000632 * Sets the device owner information. If the information is {@code null} or empty then the
633 * device owner info is cleared.
634 *
635 * @param info Device owner information which will be displayed instead of the user
636 * owner info.
637 */
638 public void setDeviceOwnerInfo(String info) {
639 if (info != null && info.isEmpty()) {
640 info = null;
641 }
642
643 setString(LOCK_SCREEN_DEVICE_OWNER_INFO, info, UserHandle.USER_SYSTEM);
644 }
645
646 public String getDeviceOwnerInfo() {
647 return getString(LOCK_SCREEN_DEVICE_OWNER_INFO, UserHandle.USER_SYSTEM);
648 }
649
650 public boolean isDeviceOwnerInfoEnabled() {
651 return getDeviceOwnerInfo() != null;
652 }
653
654 /**
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700655 * Compute the password quality from the given password string.
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800656 */
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700657 static public int computePasswordQuality(String password) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800658 boolean hasDigit = false;
659 boolean hasNonDigit = false;
660 final int len = password.length();
661 for (int i = 0; i < len; i++) {
662 if (Character.isDigit(password.charAt(i))) {
663 hasDigit = true;
664 } else {
665 hasNonDigit = true;
666 }
667 }
Jim Miller5b0fb3a2010-02-23 13:46:35 -0800668
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700669 if (hasNonDigit && hasDigit) {
670 return DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC;
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800671 }
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800672 if (hasNonDigit) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700673 return DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC;
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800674 }
675 if (hasDigit) {
Jim Miller85516d02014-01-31 17:08:37 -0800676 return maxLengthSequence(password) > MAX_ALLOWED_SEQUENCE
677 ? DevicePolicyManager.PASSWORD_QUALITY_NUMERIC
678 : DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX;
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800679 }
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700680 return DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800681 }
Jim Miller5b0fb3a2010-02-23 13:46:35 -0800682
Jim Miller85516d02014-01-31 17:08:37 -0800683 private static int categoryChar(char c) {
684 if ('a' <= c && c <= 'z') return 0;
685 if ('A' <= c && c <= 'Z') return 1;
686 if ('0' <= c && c <= '9') return 2;
687 return 3;
688 }
689
690 private static int maxDiffCategory(int category) {
691 if (category == 0 || category == 1) return 1;
692 else if (category == 2) return 10;
693 return 0;
694 }
695
696 /*
697 * Returns the maximum length of a sequential characters. A sequence is defined as
698 * monotonically increasing characters with a constant interval or the same character repeated.
699 *
700 * For example:
701 * maxLengthSequence("1234") == 4
702 * maxLengthSequence("1234abc") == 4
703 * maxLengthSequence("aabc") == 3
704 * maxLengthSequence("qwertyuio") == 1
705 * maxLengthSequence("@ABC") == 3
706 * maxLengthSequence(";;;;") == 4 (anything that repeats)
707 * maxLengthSequence(":;<=>") == 1 (ordered, but not composed of alphas or digits)
708 *
709 * @param string the pass
710 * @return the number of sequential letters or digits
711 */
712 public static int maxLengthSequence(String string) {
713 if (string.length() == 0) return 0;
714 char previousChar = string.charAt(0);
715 int category = categoryChar(previousChar); //current category of the sequence
716 int diff = 0; //difference between two consecutive characters
717 boolean hasDiff = false; //if we are currently targeting a sequence
718 int maxLength = 0; //maximum length of a sequence already found
719 int startSequence = 0; //where the current sequence started
720 for (int current = 1; current < string.length(); current++) {
721 char currentChar = string.charAt(current);
722 int categoryCurrent = categoryChar(currentChar);
723 int currentDiff = (int) currentChar - (int) previousChar;
724 if (categoryCurrent != category || Math.abs(currentDiff) > maxDiffCategory(category)) {
725 maxLength = Math.max(maxLength, current - startSequence);
726 startSequence = current;
727 hasDiff = false;
728 category = categoryCurrent;
729 }
730 else {
731 if(hasDiff && currentDiff != diff) {
732 maxLength = Math.max(maxLength, current - startSequence);
733 startSequence = current - 1;
734 }
735 diff = currentDiff;
736 hasDiff = true;
737 }
738 previousChar = currentChar;
739 }
740 maxLength = Math.max(maxLength, string.length() - startSequence);
741 return maxLength;
742 }
743
Jason parksf7b3cd42011-01-27 09:28:25 -0600744 /** Update the encryption password if it is enabled **/
Paul Lawrence3a5a0be2014-09-25 09:26:34 -0700745 private void updateEncryptionPassword(final int type, final String password) {
Amith Yamasanicd410ba2014-10-17 11:16:58 -0700746 if (!isDeviceEncryptionEnabled()) {
Jason parksf7b3cd42011-01-27 09:28:25 -0600747 return;
748 }
Paul Lawrence3a5a0be2014-09-25 09:26:34 -0700749 final IBinder service = ServiceManager.getService("mount");
Jason parksf7b3cd42011-01-27 09:28:25 -0600750 if (service == null) {
751 Log.e(TAG, "Could not find the mount service to update the encryption password");
752 return;
753 }
754
Paul Lawrence3a5a0be2014-09-25 09:26:34 -0700755 new AsyncTask<Void, Void, Void>() {
756 @Override
757 protected Void doInBackground(Void... dummy) {
758 IMountService mountService = IMountService.Stub.asInterface(service);
759 try {
760 mountService.changeEncryptionPassword(type, password);
761 } catch (RemoteException e) {
762 Log.e(TAG, "Error changing encryption password", e);
763 }
764 return null;
765 }
766 }.execute();
Jason parksf7b3cd42011-01-27 09:28:25 -0600767 }
768
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800769 /**
Jim Millercd709882010-03-25 18:24:02 -0700770 * Save a lock password. Does not ensure that the password is as good
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800771 * as the requested mode, but will adjust the mode to be as good as the
Adrian Roos8150d2a2015-04-16 17:11:20 -0700772 * password.
Jim Miller69aa4a92009-12-22 19:03:28 -0800773 * @param password The password to save
Andres Morales8fa56652015-03-31 09:19:50 -0700774 * @param savedPassword The previously saved lock password, or null if none
Jim Millercd709882010-03-25 18:24:02 -0700775 * @param quality {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700776 * @param userHandle The userId of the user to change the password for
777 */
Andres Morales8fa56652015-03-31 09:19:50 -0700778 public void saveLockPassword(String password, String savedPassword, int quality,
779 int userHandle) {
Jim Miller69aa4a92009-12-22 19:03:28 -0800780 try {
Dianne Hackborn2509d3c2010-03-08 12:54:25 -0800781 DevicePolicyManager dpm = getDevicePolicyManager();
Adrian Roosf80e66ce92015-01-15 23:27:24 +0100782 if (password == null || password.length() < MIN_LOCK_PASSWORD_SIZE) {
783 throw new IllegalArgumentException("password must not be null and at least "
784 + "of length " + MIN_LOCK_PASSWORD_SIZE);
Jim Miller31f90b62010-01-20 13:35:20 -0800785 }
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100786
Andres Morales8fa56652015-03-31 09:19:50 -0700787 getLockSettings().setLockPassword(password, savedPassword, userHandle);
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100788 int computedQuality = computePasswordQuality(password);
789
790 // Update the device encryption password.
Xiaohui Chen86c69dd2015-08-27 15:44:02 -0700791 if (userHandle == UserHandle.USER_SYSTEM
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100792 && LockPatternUtils.isDeviceEncryptionEnabled()) {
Andrei Kapishnikov4eb6a362015-04-02 15:21:20 -0400793 if (!shouldEncryptWithCredentials(true)) {
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100794 clearEncryptionPassword();
795 } else {
796 boolean numeric = computedQuality
797 == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
798 boolean numericComplex = computedQuality
799 == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX;
800 int type = numeric || numericComplex ? StorageManager.CRYPT_TYPE_PIN
801 : StorageManager.CRYPT_TYPE_PASSWORD;
802 updateEncryptionPassword(type, password);
803 }
804 }
805
806 setLong(PASSWORD_TYPE_KEY, Math.max(quality, computedQuality), userHandle);
807 if (computedQuality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
808 int letters = 0;
809 int uppercase = 0;
810 int lowercase = 0;
811 int numbers = 0;
812 int symbols = 0;
813 int nonletter = 0;
814 for (int i = 0; i < password.length(); i++) {
815 char c = password.charAt(i);
816 if (c >= 'A' && c <= 'Z') {
817 letters++;
818 uppercase++;
819 } else if (c >= 'a' && c <= 'z') {
820 letters++;
821 lowercase++;
822 } else if (c >= '0' && c <= '9') {
823 numbers++;
824 nonletter++;
825 } else {
826 symbols++;
827 nonletter++;
828 }
829 }
830 dpm.setActivePasswordState(Math.max(quality, computedQuality),
831 password.length(), letters, uppercase, lowercase,
832 numbers, symbols, nonletter, userHandle);
833 } else {
834 // The password is not anything.
835 dpm.setActivePasswordState(
836 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
837 0, 0, 0, 0, 0, 0, 0, userHandle);
838 }
839
840 // Add the password to the password history. We assume all
841 // password hashes have the same length for simplicity of implementation.
842 String passwordHistory = getString(PASSWORD_HISTORY_KEY, userHandle);
843 if (passwordHistory == null) {
844 passwordHistory = "";
845 }
846 int passwordHistoryLength = getRequestedPasswordHistoryLength(userHandle);
847 if (passwordHistoryLength == 0) {
848 passwordHistory = "";
849 } else {
850 byte[] hash = passwordToHash(password, userHandle);
851 passwordHistory = new String(hash, StandardCharsets.UTF_8) + "," + passwordHistory;
852 // Cut it to contain passwordHistoryLength hashes
853 // and passwordHistoryLength -1 commas.
854 passwordHistory = passwordHistory.substring(0, Math.min(hash.length
855 * passwordHistoryLength + passwordHistoryLength - 1, passwordHistory
856 .length()));
857 }
858 setString(PASSWORD_HISTORY_KEY, passwordHistory, userHandle);
Adrian Roosf8f56bc2014-11-20 23:55:34 +0100859 onAfterChangingPassword(userHandle);
Amith Yamasani52c489c2012-03-28 11:42:42 -0700860 } catch (RemoteException re) {
Jim Miller69aa4a92009-12-22 19:03:28 -0800861 // Cant do much
Amith Yamasani52c489c2012-03-28 11:42:42 -0700862 Log.e(TAG, "Unable to save lock password " + re);
Jim Miller69aa4a92009-12-22 19:03:28 -0800863 }
864 }
865
Jim Millercd709882010-03-25 18:24:02 -0700866 /**
Svetoslav16e4a1a2014-09-29 18:16:20 -0700867 * Gets whether the device is encrypted.
868 *
869 * @return Whether the device is encrypted.
870 */
871 public static boolean isDeviceEncrypted() {
872 IMountService mountService = IMountService.Stub.asInterface(
873 ServiceManager.getService("mount"));
874 try {
875 return mountService.getEncryptionState() != IMountService.ENCRYPTION_STATE_NONE
876 && mountService.getPasswordType() != StorageManager.CRYPT_TYPE_DEFAULT;
877 } catch (RemoteException re) {
878 Log.e(TAG, "Error getting encryption state", re);
879 }
880 return true;
881 }
882
883 /**
Jim Miller6848dc82014-10-13 18:51:53 -0700884 * Determine if the device supports encryption, even if it's set to default. This
885 * differs from isDeviceEncrypted() in that it returns true even if the device is
886 * encrypted with the default password.
887 * @return true if device encryption is enabled
888 */
889 public static boolean isDeviceEncryptionEnabled() {
Paul Lawrence20be5d62016-02-26 13:51:17 -0800890 return StorageManager.isEncrypted();
Jim Miller6848dc82014-10-13 18:51:53 -0700891 }
892
893 /**
Paul Lawrence5c21c702016-01-29 13:26:19 -0800894 * Determine if the device is file encrypted
895 * @return true if device is file encrypted
896 */
897 public static boolean isFileEncryptionEnabled() {
Paul Lawrence20be5d62016-02-26 13:51:17 -0800898 return StorageManager.isFileEncryptedNativeOrEmulated();
Paul Lawrence5c21c702016-01-29 13:26:19 -0800899 }
900
901 /**
Svetoslav16e4a1a2014-09-29 18:16:20 -0700902 * Clears the encryption password.
903 */
904 public void clearEncryptionPassword() {
905 updateEncryptionPassword(StorageManager.CRYPT_TYPE_DEFAULT, null);
906 }
907
908 /**
Adrian Roos1572ee32014-09-01 16:24:32 +0200909 * Retrieves the quality mode for {@param userHandle}.
910 * {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
911 *
912 * @return stored password quality
913 */
914 public int getKeyguardStoredPasswordQuality(int userHandle) {
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100915 return (int) getLong(PASSWORD_TYPE_KEY,
Adrian Roos1572ee32014-09-01 16:24:32 +0200916 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, userHandle);
Jim Miller6edf2632011-09-05 16:03:14 -0700917 }
918
Danielle Millett58396982011-09-30 13:55:07 -0400919 /**
Clara Bayarria1771112015-12-18 16:29:18 +0000920 * Enables/disables the Separate Profile Challenge for this {@param userHandle}. This is a no-op
921 * for user handles that do not belong to a managed profile.
922 */
923 public void setSeparateProfileChallengeEnabled(int userHandle, boolean enabled) {
924 UserInfo info = getUserManager().getUserInfo(userHandle);
925 if (info.isManagedProfile()) {
926 setBoolean(SEPARATE_PROFILE_CHALLENGE_KEY, enabled, userHandle);
927 }
928 }
929
930 /**
931 * Retrieves whether the Separate Profile Challenge is enabled for this {@param userHandle}.
932 */
933 public boolean isSeparateProfileChallengeEnabled(int userHandle) {
934 UserInfo info = getUserManager().getUserInfo(userHandle);
Clara Bayarri8d35de82016-01-12 17:29:29 +0000935 if (info == null || !info.isManagedProfile()) {
Clara Bayarria1771112015-12-18 16:29:18 +0000936 return false;
937 }
938 return getBoolean(SEPARATE_PROFILE_CHALLENGE_KEY, false, userHandle);
939 }
940
941 /**
942 * Retrieves whether the current DPM allows use of the Profile Challenge.
943 */
944 public boolean isSeparateProfileChallengeAllowed(int userHandle) {
945 UserInfo info = getUserManager().getUserInfo(userHandle);
Clara Bayarri8d35de82016-01-12 17:29:29 +0000946 if (info == null || !info.isManagedProfile()) {
Clara Bayarria1771112015-12-18 16:29:18 +0000947 return false;
948 }
949 return getDevicePolicyManager().isSeparateProfileChallengeAllowed(userHandle);
950 }
951
952 /**
Clara Bayarrid7693912016-01-22 17:26:31 +0000953 * Retrieves whether the current profile and device locks can be unified.
954 */
955 public boolean isSeparateProfileChallengeAllowedToUnify(int userHandle) {
956 return getDevicePolicyManager().isProfileActivePasswordSufficientForParent(userHandle);
957 }
958
959 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800960 * Deserialize a pattern.
961 * @param string The pattern serialized with {@link #patternToString}
962 * @return The pattern.
963 */
964 public static List<LockPatternView.Cell> stringToPattern(String string) {
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100965 if (string == null) {
966 return null;
967 }
968
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800969 List<LockPatternView.Cell> result = Lists.newArrayList();
970
971 final byte[] bytes = string.getBytes();
972 for (int i = 0; i < bytes.length; i++) {
Andres Moralese40bad82015-05-28 14:21:36 -0700973 byte b = (byte) (bytes[i] - '1');
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800974 result.add(LockPatternView.Cell.of(b / 3, b % 3));
975 }
976 return result;
977 }
978
979 /**
980 * Serialize a pattern.
981 * @param pattern The pattern.
982 * @return The pattern in string form.
983 */
984 public static String patternToString(List<LockPatternView.Cell> pattern) {
985 if (pattern == null) {
986 return "";
987 }
988 final int patternSize = pattern.size();
989
990 byte[] res = new byte[patternSize];
991 for (int i = 0; i < patternSize; i++) {
992 LockPatternView.Cell cell = pattern.get(i);
Andres Moralese40bad82015-05-28 14:21:36 -0700993 res[i] = (byte) (cell.getRow() * 3 + cell.getColumn() + '1');
994 }
995 return new String(res);
996 }
997
998 public static String patternStringToBaseZero(String pattern) {
999 if (pattern == null) {
1000 return "";
1001 }
1002 final int patternSize = pattern.length();
1003
1004 byte[] res = new byte[patternSize];
1005 final byte[] bytes = pattern.getBytes();
1006 for (int i = 0; i < patternSize; i++) {
1007 res[i] = (byte) (bytes[i] - '1');
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001008 }
1009 return new String(res);
1010 }
Jim Miller69aa4a92009-12-22 19:03:28 -08001011
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001012 /*
1013 * Generate an SHA-1 hash for the pattern. Not the most secure, but it is
1014 * at least a second level of protection. First level is that the file
1015 * is in a location only readable by the system process.
1016 * @param pattern the gesture pattern.
1017 * @return the hash of the pattern in a byte array.
1018 */
Jim Millerde1af082013-09-11 14:58:26 -07001019 public static byte[] patternToHash(List<LockPatternView.Cell> pattern) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001020 if (pattern == null) {
1021 return null;
1022 }
Jim Miller69aa4a92009-12-22 19:03:28 -08001023
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001024 final int patternSize = pattern.size();
1025 byte[] res = new byte[patternSize];
1026 for (int i = 0; i < patternSize; i++) {
1027 LockPatternView.Cell cell = pattern.get(i);
1028 res[i] = (byte) (cell.getRow() * 3 + cell.getColumn());
1029 }
1030 try {
1031 MessageDigest md = MessageDigest.getInstance("SHA-1");
1032 byte[] hash = md.digest(res);
1033 return hash;
1034 } catch (NoSuchAlgorithmException nsa) {
1035 return res;
1036 }
1037 }
1038
Geoffrey Borggaard987672d22014-07-18 16:47:18 -04001039 private String getSalt(int userId) {
1040 long salt = getLong(LOCK_PASSWORD_SALT_KEY, 0, userId);
Jim Miller11b019d2010-01-20 16:34:45 -08001041 if (salt == 0) {
1042 try {
1043 salt = SecureRandom.getInstance("SHA1PRNG").nextLong();
Geoffrey Borggaard987672d22014-07-18 16:47:18 -04001044 setLong(LOCK_PASSWORD_SALT_KEY, salt, userId);
1045 Log.v(TAG, "Initialized lock password salt for user: " + userId);
Jim Miller11b019d2010-01-20 16:34:45 -08001046 } catch (NoSuchAlgorithmException e) {
1047 // Throw an exception rather than storing a password we'll never be able to recover
1048 throw new IllegalStateException("Couldn't get SecureRandom number", e);
1049 }
1050 }
1051 return Long.toHexString(salt);
1052 }
1053
Jim Miller69aa4a92009-12-22 19:03:28 -08001054 /*
1055 * Generate a hash for the given password. To avoid brute force attacks, we use a salted hash.
1056 * Not the most secure, but it is at least a second level of protection. First level is that
1057 * the file is in a location only readable by the system process.
Narayan Kamath78108a32014-12-16 12:56:23 +00001058 *
Jim Miller69aa4a92009-12-22 19:03:28 -08001059 * @param password the gesture pattern.
Narayan Kamath78108a32014-12-16 12:56:23 +00001060 *
Jim Miller69aa4a92009-12-22 19:03:28 -08001061 * @return the hash of the pattern in a byte array.
1062 */
Geoffrey Borggaard987672d22014-07-18 16:47:18 -04001063 public byte[] passwordToHash(String password, int userId) {
Jim Miller69aa4a92009-12-22 19:03:28 -08001064 if (password == null) {
1065 return null;
1066 }
Narayan Kamath78108a32014-12-16 12:56:23 +00001067
Jim Miller69aa4a92009-12-22 19:03:28 -08001068 try {
Geoffrey Borggaard987672d22014-07-18 16:47:18 -04001069 byte[] saltedPassword = (password + getSalt(userId)).getBytes();
Narayan Kamath78108a32014-12-16 12:56:23 +00001070 byte[] sha1 = MessageDigest.getInstance("SHA-1").digest(saltedPassword);
1071 byte[] md5 = MessageDigest.getInstance("MD5").digest(saltedPassword);
Jim Miller69aa4a92009-12-22 19:03:28 -08001072
Narayan Kamath78108a32014-12-16 12:56:23 +00001073 byte[] combined = new byte[sha1.length + md5.length];
1074 System.arraycopy(sha1, 0, combined, 0, sha1.length);
1075 System.arraycopy(md5, 0, combined, sha1.length, md5.length);
1076
1077 final char[] hexEncoded = HexEncoding.encode(combined);
1078 return new String(hexEncoded).getBytes(StandardCharsets.UTF_8);
1079 } catch (NoSuchAlgorithmException e) {
1080 throw new AssertionError("Missing digest algorithm: ", e);
Jim Miller69aa4a92009-12-22 19:03:28 -08001081 }
Jim Miller69aa4a92009-12-22 19:03:28 -08001082 }
1083
1084 /**
Adrian Roos9dd16eb2015-01-08 16:20:49 +01001085 * @param userId the user for which to report the value
1086 * @return Whether the lock screen is secured.
1087 */
1088 public boolean isSecure(int userId) {
1089 int mode = getKeyguardStoredPasswordQuality(userId);
1090 return isLockPatternEnabled(mode, userId) || isLockPasswordEnabled(mode, userId);
1091 }
1092
Adrian Roosdce01222015-01-07 22:39:01 +01001093 public boolean isLockPasswordEnabled(int userId) {
Adrian Roos9dd16eb2015-01-08 16:20:49 +01001094 return isLockPasswordEnabled(getKeyguardStoredPasswordQuality(userId), userId);
1095 }
1096
1097 private boolean isLockPasswordEnabled(int mode, int userId) {
Danielle Millett73da5fe2011-09-13 16:20:05 -04001098 final boolean passwordEnabled = mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC
1099 || mode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC
Jim Miller85516d02014-01-31 17:08:37 -08001100 || mode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX
Danielle Millett73da5fe2011-09-13 16:20:05 -04001101 || mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC
1102 || mode == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
Adrian Roos9dd16eb2015-01-08 16:20:49 +01001103 return passwordEnabled && savedPasswordExists(userId);
Jim Miller69aa4a92009-12-22 19:03:28 -08001104 }
1105
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001106 /**
Adrian Roos230635e2015-01-07 20:50:29 +01001107 * @return Whether the lock pattern is enabled
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001108 */
Adrian Roos50bfeec2014-11-20 16:21:11 +01001109 public boolean isLockPatternEnabled(int userId) {
Adrian Roos9dd16eb2015-01-08 16:20:49 +01001110 return isLockPatternEnabled(getKeyguardStoredPasswordQuality(userId), userId);
Danielle Millett925a7d82012-03-19 18:02:20 -04001111 }
1112
Bryce Lee46145962015-12-14 14:39:10 -08001113 @Deprecated
1114 public boolean isLegacyLockPatternEnabled(int userId) {
1115 // Note: this value should default to {@code true} to avoid any reset that might result.
1116 // We must use a special key to read this value, since it will by default return the value
1117 // based on the new logic.
1118 return getBoolean(LEGACY_LOCK_PATTERN_ENABLED, true, userId);
1119 }
1120
1121 @Deprecated
1122 public void setLegacyLockPatternEnabled(int userId) {
1123 setBoolean(Settings.Secure.LOCK_PATTERN_ENABLED, true, userId);
1124 }
1125
Adrian Roos9dd16eb2015-01-08 16:20:49 +01001126 private boolean isLockPatternEnabled(int mode, int userId) {
1127 return mode == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING
1128 && savedPatternExists(userId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001129 }
1130
1131 /**
1132 * @return Whether the visible pattern is enabled.
1133 */
Adrian Roos8150d2a2015-04-16 17:11:20 -07001134 public boolean isVisiblePatternEnabled(int userId) {
1135 return getBoolean(Settings.Secure.LOCK_PATTERN_VISIBLE, false, userId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001136 }
1137
1138 /**
1139 * Set whether the visible pattern is enabled.
1140 */
Adrian Roos8150d2a2015-04-16 17:11:20 -07001141 public void setVisiblePatternEnabled(boolean enabled, int userId) {
Adrian Roosdce01222015-01-07 22:39:01 +01001142 setBoolean(Settings.Secure.LOCK_PATTERN_VISIBLE, enabled, userId);
Paul Lawrence878ba0a2014-08-20 13:08:01 -07001143
1144 // Update for crypto if owner
Xiaohui Chen86c69dd2015-08-27 15:44:02 -07001145 if (userId != UserHandle.USER_SYSTEM) {
Paul Lawrence878ba0a2014-08-20 13:08:01 -07001146 return;
1147 }
1148
1149 IBinder service = ServiceManager.getService("mount");
1150 if (service == null) {
1151 Log.e(TAG, "Could not find the mount service to update the user info");
1152 return;
1153 }
1154
1155 IMountService mountService = IMountService.Stub.asInterface(service);
1156 try {
Elliott Hughesf839b4f2014-09-26 12:30:47 -07001157 mountService.setField(StorageManager.PATTERN_VISIBLE_KEY, enabled ? "1" : "0");
Paul Lawrence878ba0a2014-08-20 13:08:01 -07001158 } catch (RemoteException e) {
1159 Log.e(TAG, "Error changing pattern visible state", e);
1160 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001161 }
1162
1163 /**
Paul Lawrenced8fdb332015-05-18 13:26:11 -07001164 * Set whether the visible password is enabled for cryptkeeper screen.
1165 */
1166 public void setVisiblePasswordEnabled(boolean enabled, int userId) {
1167 // Update for crypto if owner
Xiaohui Chen86c69dd2015-08-27 15:44:02 -07001168 if (userId != UserHandle.USER_SYSTEM) {
Paul Lawrenced8fdb332015-05-18 13:26:11 -07001169 return;
1170 }
1171
1172 IBinder service = ServiceManager.getService("mount");
1173 if (service == null) {
1174 Log.e(TAG, "Could not find the mount service to update the user info");
1175 return;
1176 }
1177
1178 IMountService mountService = IMountService.Stub.asInterface(service);
1179 try {
1180 mountService.setField(StorageManager.PASSWORD_VISIBLE_KEY, enabled ? "1" : "0");
1181 } catch (RemoteException e) {
1182 Log.e(TAG, "Error changing password visible state", e);
1183 }
1184 }
1185
1186 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001187 * @return Whether tactile feedback for the pattern is enabled.
1188 */
1189 public boolean isTactileFeedbackEnabled() {
Jeff Sharkey5ed9d682012-10-10 14:28:27 -07001190 return Settings.System.getIntForUser(mContentResolver,
1191 Settings.System.HAPTIC_FEEDBACK_ENABLED, 1, UserHandle.USER_CURRENT) != 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001192 }
1193
1194 /**
1195 * Set and store the lockout deadline, meaning the user can't attempt his/her unlock
1196 * pattern until the deadline has passed.
1197 * @return the chosen deadline.
1198 */
Andres Morales23974272015-05-14 22:42:26 -07001199 public long setLockoutAttemptDeadline(int userId, int timeoutMs) {
1200 final long deadline = SystemClock.elapsedRealtime() + timeoutMs;
Adrian Roos8150d2a2015-04-16 17:11:20 -07001201 setLong(LOCKOUT_ATTEMPT_DEADLINE, deadline, userId);
Andres Morales23974272015-05-14 22:42:26 -07001202 setLong(LOCKOUT_ATTEMPT_TIMEOUT_MS, timeoutMs, userId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001203 return deadline;
1204 }
1205
1206 /**
1207 * @return The elapsed time in millis in the future when the user is allowed to
1208 * attempt to enter his/her lock pattern, or 0 if the user is welcome to
1209 * enter a pattern.
1210 */
Adrian Roos8150d2a2015-04-16 17:11:20 -07001211 public long getLockoutAttemptDeadline(int userId) {
Andres Moralesa4e23372015-09-08 13:17:37 -07001212 long deadline = getLong(LOCKOUT_ATTEMPT_DEADLINE, 0L, userId);
Andres Morales23974272015-05-14 22:42:26 -07001213 final long timeoutMs = getLong(LOCKOUT_ATTEMPT_TIMEOUT_MS, 0L, userId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001214 final long now = SystemClock.elapsedRealtime();
Jorim Jaggie3e6d562015-09-28 13:57:37 -07001215 if (deadline < now && deadline != 0) {
Andres Moralesa4e23372015-09-08 13:17:37 -07001216 // timeout expired
1217 setLong(LOCKOUT_ATTEMPT_DEADLINE, 0, userId);
1218 setLong(LOCKOUT_ATTEMPT_TIMEOUT_MS, 0, userId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001219 return 0L;
1220 }
Andres Moralesa4e23372015-09-08 13:17:37 -07001221
1222 if (deadline > (now + timeoutMs)) {
1223 // device was rebooted, set new deadline
1224 deadline = now + timeoutMs;
1225 setLong(LOCKOUT_ATTEMPT_DEADLINE, deadline, userId);
1226 }
1227
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001228 return deadline;
1229 }
1230
Jim Millerf45bb402013-08-20 18:58:32 -07001231 private boolean getBoolean(String secureSettingKey, boolean defaultValue, int userId) {
Amith Yamasani52c489c2012-03-28 11:42:42 -07001232 try {
Jim Millerf45bb402013-08-20 18:58:32 -07001233 return getLockSettings().getBoolean(secureSettingKey, defaultValue, userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -07001234 } catch (RemoteException re) {
1235 return defaultValue;
1236 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001237 }
1238
Jim Millerf45bb402013-08-20 18:58:32 -07001239 private void setBoolean(String secureSettingKey, boolean enabled, int userId) {
Amith Yamasani52c489c2012-03-28 11:42:42 -07001240 try {
Jim Millerf45bb402013-08-20 18:58:32 -07001241 getLockSettings().setBoolean(secureSettingKey, enabled, userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -07001242 } catch (RemoteException re) {
1243 // What can we do?
1244 Log.e(TAG, "Couldn't write boolean " + secureSettingKey + re);
1245 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001246 }
1247
Geoffrey Borggaard987672d22014-07-18 16:47:18 -04001248 private long getLong(String secureSettingKey, long defaultValue, int userHandle) {
1249 try {
1250 return getLockSettings().getLong(secureSettingKey, defaultValue, userHandle);
1251 } catch (RemoteException re) {
1252 return defaultValue;
1253 }
1254 }
1255
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001256 private void setLong(String secureSettingKey, long value, int userHandle) {
Amith Yamasani52c489c2012-03-28 11:42:42 -07001257 try {
Kenny Guy0cf13702013-11-29 16:33:05 +00001258 getLockSettings().setLong(secureSettingKey, value, userHandle);
Amith Yamasani52c489c2012-03-28 11:42:42 -07001259 } catch (RemoteException re) {
1260 // What can we do?
1261 Log.e(TAG, "Couldn't write long " + secureSettingKey + re);
1262 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001263 }
1264
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001265 private String getString(String secureSettingKey, int userHandle) {
Amith Yamasani52c489c2012-03-28 11:42:42 -07001266 try {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001267 return getLockSettings().getString(secureSettingKey, null, userHandle);
Amith Yamasani52c489c2012-03-28 11:42:42 -07001268 } catch (RemoteException re) {
1269 return null;
1270 }
Konstantin Lopyrev863f22d2010-05-12 17:16:58 -07001271 }
1272
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001273 private void setString(String secureSettingKey, String value, int userHandle) {
Amith Yamasani52c489c2012-03-28 11:42:42 -07001274 try {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001275 getLockSettings().setString(secureSettingKey, value, userHandle);
Amith Yamasani52c489c2012-03-28 11:42:42 -07001276 } catch (RemoteException re) {
1277 // What can we do?
1278 Log.e(TAG, "Couldn't write string " + secureSettingKey + re);
1279 }
Konstantin Lopyrev863f22d2010-05-12 17:16:58 -07001280 }
1281
Adrian Roos8150d2a2015-04-16 17:11:20 -07001282 public void setPowerButtonInstantlyLocks(boolean enabled, int userId) {
1283 setBoolean(LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS, enabled, userId);
Jim Millera4edd152012-01-06 18:24:04 -08001284 }
1285
Adrian Roos8150d2a2015-04-16 17:11:20 -07001286 public boolean getPowerButtonInstantlyLocks(int userId) {
1287 return getBoolean(LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS, true, userId);
Adrian Roos82142c22014-03-27 14:56:59 +01001288 }
1289
1290 public void setEnabledTrustAgents(Collection<ComponentName> activeTrustAgents, int userId) {
1291 StringBuilder sb = new StringBuilder();
1292 for (ComponentName cn : activeTrustAgents) {
1293 if (sb.length() > 0) {
1294 sb.append(',');
1295 }
1296 sb.append(cn.flattenToShortString());
1297 }
1298 setString(ENABLED_TRUST_AGENTS, sb.toString(), userId);
Adrian Roos8150d2a2015-04-16 17:11:20 -07001299 getTrustManager().reportEnabledTrustAgentsChanged(userId);
Adrian Roos82142c22014-03-27 14:56:59 +01001300 }
1301
1302 public List<ComponentName> getEnabledTrustAgents(int userId) {
1303 String serialized = getString(ENABLED_TRUST_AGENTS, userId);
1304 if (TextUtils.isEmpty(serialized)) {
1305 return null;
1306 }
1307 String[] split = serialized.split(",");
1308 ArrayList<ComponentName> activeTrustAgents = new ArrayList<ComponentName>(split.length);
1309 for (String s : split) {
1310 if (!TextUtils.isEmpty(s)) {
1311 activeTrustAgents.add(ComponentName.unflattenFromString(s));
1312 }
1313 }
1314 return activeTrustAgents;
1315 }
Adrian Roos2c12cfa2014-06-25 23:28:53 +02001316
1317 /**
Adrian Roosb5e47222015-08-14 15:53:06 -07001318 * Disable trust until credentials have been entered for user {@param userId}.
1319 *
1320 * Requires the {@link android.Manifest.permission#ACCESS_KEYGUARD_SECURE_STORAGE} permission.
1321 *
1322 * @param userId either an explicit user id or {@link android.os.UserHandle#USER_ALL}
Adrian Roos2c12cfa2014-06-25 23:28:53 +02001323 */
1324 public void requireCredentialEntry(int userId) {
Jorim Jaggi16093fe32015-09-09 23:29:17 +00001325 requireStrongAuth(StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST, userId);
Adrian Roosb5e47222015-08-14 15:53:06 -07001326 }
1327
1328 /**
1329 * Requests strong authentication for user {@param userId}.
1330 *
1331 * Requires the {@link android.Manifest.permission#ACCESS_KEYGUARD_SECURE_STORAGE} permission.
1332 *
1333 * @param strongAuthReason a combination of {@link StrongAuthTracker.StrongAuthFlags} indicating
1334 * the reason for and the strength of the requested authentication.
1335 * @param userId either an explicit user id or {@link android.os.UserHandle#USER_ALL}
1336 */
1337 public void requireStrongAuth(@StrongAuthTracker.StrongAuthFlags int strongAuthReason,
1338 int userId) {
1339 try {
1340 getLockSettings().requireStrongAuth(strongAuthReason, userId);
1341 } catch (RemoteException e) {
1342 Log.e(TAG, "Error while requesting strong auth: " + e);
1343 }
Adrian Roos2c12cfa2014-06-25 23:28:53 +02001344 }
Adrian Roos4b9e3242014-08-20 23:36:25 +02001345
Adrian Roosf8f56bc2014-11-20 23:55:34 +01001346 private void onAfterChangingPassword(int userHandle) {
1347 getTrustManager().reportEnabledTrustAgentsChanged(userHandle);
Adrian Roos4b9e3242014-08-20 23:36:25 +02001348 }
Jim Millerdd5de712014-10-16 19:50:18 -07001349
1350 public boolean isCredentialRequiredToDecrypt(boolean defaultValue) {
1351 final int value = Settings.Global.getInt(mContentResolver,
1352 Settings.Global.REQUIRE_PASSWORD_TO_DECRYPT, -1);
1353 return value == -1 ? defaultValue : (value != 0);
1354 }
1355
1356 public void setCredentialRequiredToDecrypt(boolean required) {
Robin Leed39113e2016-01-22 15:44:49 +00001357 if (!(getUserManager().isSystemUser() || getUserManager().isPrimaryUser())) {
1358 throw new IllegalStateException(
1359 "Only the system or primary user may call setCredentialRequiredForDecrypt()");
Jim Millerdd5de712014-10-16 19:50:18 -07001360 }
Paul Lawrence688af6c2015-05-15 11:26:17 -07001361
1362 if (isDeviceEncryptionEnabled()){
1363 Settings.Global.putInt(mContext.getContentResolver(),
1364 Settings.Global.REQUIRE_PASSWORD_TO_DECRYPT, required ? 1 : 0);
1365 }
Jim Millerdd5de712014-10-16 19:50:18 -07001366 }
Andrei Kapishnikov4eb6a362015-04-02 15:21:20 -04001367
1368 private boolean isDoNotAskCredentialsOnBootSet() {
1369 return mDevicePolicyManager.getDoNotAskCredentialsOnBoot();
1370 }
1371
1372 private boolean shouldEncryptWithCredentials(boolean defaultValue) {
1373 return isCredentialRequiredToDecrypt(defaultValue) && !isDoNotAskCredentialsOnBootSet();
1374 }
Xiyuan Xiaaa262942015-05-05 15:18:45 -07001375
1376 private void throwIfCalledOnMainThread() {
1377 if (Looper.getMainLooper().isCurrentThread()) {
1378 throw new IllegalStateException("should not be called from the main thread.");
1379 }
1380 }
Adrian Roosb5e47222015-08-14 15:53:06 -07001381
1382 public void registerStrongAuthTracker(final StrongAuthTracker strongAuthTracker) {
1383 try {
1384 getLockSettings().registerStrongAuthTracker(strongAuthTracker.mStub);
1385 } catch (RemoteException e) {
1386 throw new RuntimeException("Could not register StrongAuthTracker");
1387 }
1388 }
1389
1390 public void unregisterStrongAuthTracker(final StrongAuthTracker strongAuthTracker) {
1391 try {
1392 getLockSettings().unregisterStrongAuthTracker(strongAuthTracker.mStub);
1393 } catch (RemoteException e) {
1394 Log.e(TAG, "Could not unregister StrongAuthTracker", e);
1395 }
1396 }
1397
1398 /**
1399 * Tracks the global strong authentication state.
1400 */
1401 public static class StrongAuthTracker {
1402
1403 @IntDef(flag = true,
1404 value = { STRONG_AUTH_NOT_REQUIRED,
1405 STRONG_AUTH_REQUIRED_AFTER_BOOT,
1406 STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW,
Jorim Jaggi16093fe32015-09-09 23:29:17 +00001407 SOME_AUTH_REQUIRED_AFTER_USER_REQUEST})
Adrian Roosb5e47222015-08-14 15:53:06 -07001408 @Retention(RetentionPolicy.SOURCE)
1409 public @interface StrongAuthFlags {}
1410
1411 /**
1412 * Strong authentication is not required.
1413 */
1414 public static final int STRONG_AUTH_NOT_REQUIRED = 0x0;
1415
1416 /**
1417 * Strong authentication is required because the user has not authenticated since boot.
1418 */
1419 public static final int STRONG_AUTH_REQUIRED_AFTER_BOOT = 0x1;
1420
1421 /**
Jorim Jaggi16093fe32015-09-09 23:29:17 +00001422 * Strong authentication is required because a device admin has requested it.
Adrian Roosb5e47222015-08-14 15:53:06 -07001423 */
1424 public static final int STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW = 0x2;
1425
1426 /**
Jorim Jaggi16093fe32015-09-09 23:29:17 +00001427 * Some authentication is required because the user has temporarily disabled trust.
Adrian Roosb5e47222015-08-14 15:53:06 -07001428 */
Jorim Jaggi16093fe32015-09-09 23:29:17 +00001429 public static final int SOME_AUTH_REQUIRED_AFTER_USER_REQUEST = 0x4;
Adrian Roosb5e47222015-08-14 15:53:06 -07001430
Adrian Roos873010d2015-08-25 15:59:00 -07001431 /**
1432 * Strong authentication is required because the user has been locked out after too many
1433 * attempts.
1434 */
1435 public static final int STRONG_AUTH_REQUIRED_AFTER_LOCKOUT = 0x8;
1436
Adrian Roosaf4ab3e2015-09-02 13:23:30 -07001437 /**
1438 * Some authentication is required because the user has entered a wrong credential.
1439 */
1440 public static final int SOME_AUTH_REQUIRED_AFTER_WRONG_CREDENTIAL = 0x10;
1441
Adrian Roosaf4ab3e2015-09-02 13:23:30 -07001442 private static final int ALLOWING_FINGERPRINT = STRONG_AUTH_NOT_REQUIRED
Jorim Jaggi16093fe32015-09-09 23:29:17 +00001443 | SOME_AUTH_REQUIRED_AFTER_USER_REQUEST
Adrian Roosaf4ab3e2015-09-02 13:23:30 -07001444 | SOME_AUTH_REQUIRED_AFTER_WRONG_CREDENTIAL;
Adrian Roosb5e47222015-08-14 15:53:06 -07001445
Adrian Roosaf4ab3e2015-09-02 13:23:30 -07001446 private final SparseIntArray mStrongAuthRequiredForUser = new SparseIntArray();
Adrian Roosb5e47222015-08-14 15:53:06 -07001447 private final H mHandler;
Rakesh Iyera7aa4d62016-01-19 17:27:23 -08001448 private final int mDefaultStrongAuthFlags;
Adrian Roosb5e47222015-08-14 15:53:06 -07001449
Rakesh Iyera7aa4d62016-01-19 17:27:23 -08001450 public StrongAuthTracker(Context context) {
1451 this(context, Looper.myLooper());
Adrian Roosb5e47222015-08-14 15:53:06 -07001452 }
1453
1454 /**
1455 * @param looper the looper on whose thread calls to {@link #onStrongAuthRequiredChanged}
1456 * will be scheduled.
Rakesh Iyera7aa4d62016-01-19 17:27:23 -08001457 * @param context the current {@link Context}
Adrian Roosb5e47222015-08-14 15:53:06 -07001458 */
Rakesh Iyera7aa4d62016-01-19 17:27:23 -08001459 public StrongAuthTracker(Context context, Looper looper) {
Adrian Roosb5e47222015-08-14 15:53:06 -07001460 mHandler = new H(looper);
Rakesh Iyera7aa4d62016-01-19 17:27:23 -08001461 mDefaultStrongAuthFlags = getDefaultFlags(context);
1462 }
1463
1464 public static @StrongAuthFlags int getDefaultFlags(Context context) {
1465 boolean strongAuthRequired = context.getResources().getBoolean(
1466 com.android.internal.R.bool.config_strongAuthRequiredOnBoot);
1467 return strongAuthRequired ? STRONG_AUTH_REQUIRED_AFTER_BOOT : STRONG_AUTH_NOT_REQUIRED;
Adrian Roosb5e47222015-08-14 15:53:06 -07001468 }
1469
1470 /**
1471 * Returns {@link #STRONG_AUTH_NOT_REQUIRED} if strong authentication is not required,
1472 * otherwise returns a combination of {@link StrongAuthFlags} indicating why strong
1473 * authentication is required.
1474 *
1475 * @param userId the user for whom the state is queried.
1476 */
1477 public @StrongAuthFlags int getStrongAuthForUser(int userId) {
Rakesh Iyera7aa4d62016-01-19 17:27:23 -08001478 return mStrongAuthRequiredForUser.get(userId, mDefaultStrongAuthFlags);
Adrian Roosb5e47222015-08-14 15:53:06 -07001479 }
1480
1481 /**
1482 * @return true if unlocking with trust alone is allowed for {@param userId} by the current
1483 * strong authentication requirements.
1484 */
1485 public boolean isTrustAllowedForUser(int userId) {
1486 return getStrongAuthForUser(userId) == STRONG_AUTH_NOT_REQUIRED;
1487 }
1488
1489 /**
1490 * @return true if unlocking with fingerprint alone is allowed for {@param userId} by the
1491 * current strong authentication requirements.
1492 */
1493 public boolean isFingerprintAllowedForUser(int userId) {
Adrian Roosaf4ab3e2015-09-02 13:23:30 -07001494 return (getStrongAuthForUser(userId) & ~ALLOWING_FINGERPRINT) == 0;
Adrian Roosb5e47222015-08-14 15:53:06 -07001495 }
1496
1497 /**
1498 * Called when the strong authentication requirements for {@param userId} changed.
1499 */
1500 public void onStrongAuthRequiredChanged(int userId) {
1501 }
1502
1503 void handleStrongAuthRequiredChanged(@StrongAuthFlags int strongAuthFlags,
1504 int userId) {
1505
1506 int oldValue = getStrongAuthForUser(userId);
1507 if (strongAuthFlags != oldValue) {
Rakesh Iyera7aa4d62016-01-19 17:27:23 -08001508 if (strongAuthFlags == mDefaultStrongAuthFlags) {
Adrian Roosb5e47222015-08-14 15:53:06 -07001509 mStrongAuthRequiredForUser.delete(userId);
1510 } else {
1511 mStrongAuthRequiredForUser.put(userId, strongAuthFlags);
1512 }
1513 onStrongAuthRequiredChanged(userId);
1514 }
1515 }
1516
1517
1518 final IStrongAuthTracker.Stub mStub = new IStrongAuthTracker.Stub() {
1519 @Override
1520 public void onStrongAuthRequiredChanged(@StrongAuthFlags int strongAuthFlags,
1521 int userId) {
1522 mHandler.obtainMessage(H.MSG_ON_STRONG_AUTH_REQUIRED_CHANGED,
1523 strongAuthFlags, userId).sendToTarget();
1524 }
1525 };
1526
1527 private class H extends Handler {
1528 static final int MSG_ON_STRONG_AUTH_REQUIRED_CHANGED = 1;
1529
1530 public H(Looper looper) {
1531 super(looper);
1532 }
1533
1534 @Override
1535 public void handleMessage(Message msg) {
1536 switch (msg.what) {
1537 case MSG_ON_STRONG_AUTH_REQUIRED_CHANGED:
1538 handleStrongAuthRequiredChanged(msg.arg1, msg.arg2);
1539 break;
1540 }
1541 }
1542 };
1543 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001544}