blob: cbc735fc065c227f0826c4abca7c311c8919b017 [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() {
890 final String status = SystemProperties.get("ro.crypto.state", "unsupported");
891 return "encrypted".equalsIgnoreCase(status);
892 }
893
894 /**
Paul Lawrence5c21c702016-01-29 13:26:19 -0800895 * Determine if the device is file encrypted
896 * @return true if device is file encrypted
897 */
898 public static boolean isFileEncryptionEnabled() {
899 final String status = SystemProperties.get("ro.crypto.type", "");
900 return "file".equalsIgnoreCase(status);
901 }
902
903 /**
Svetoslav16e4a1a2014-09-29 18:16:20 -0700904 * Clears the encryption password.
905 */
906 public void clearEncryptionPassword() {
907 updateEncryptionPassword(StorageManager.CRYPT_TYPE_DEFAULT, null);
908 }
909
910 /**
Adrian Roos1572ee32014-09-01 16:24:32 +0200911 * Retrieves the quality mode for {@param userHandle}.
912 * {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
913 *
914 * @return stored password quality
915 */
916 public int getKeyguardStoredPasswordQuality(int userHandle) {
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100917 return (int) getLong(PASSWORD_TYPE_KEY,
Adrian Roos1572ee32014-09-01 16:24:32 +0200918 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, userHandle);
Jim Miller6edf2632011-09-05 16:03:14 -0700919 }
920
Danielle Millett58396982011-09-30 13:55:07 -0400921 /**
Clara Bayarria1771112015-12-18 16:29:18 +0000922 * Enables/disables the Separate Profile Challenge for this {@param userHandle}. This is a no-op
923 * for user handles that do not belong to a managed profile.
924 */
925 public void setSeparateProfileChallengeEnabled(int userHandle, boolean enabled) {
926 UserInfo info = getUserManager().getUserInfo(userHandle);
927 if (info.isManagedProfile()) {
928 setBoolean(SEPARATE_PROFILE_CHALLENGE_KEY, enabled, userHandle);
929 }
930 }
931
932 /**
933 * Retrieves whether the Separate Profile Challenge is enabled for this {@param userHandle}.
934 */
935 public boolean isSeparateProfileChallengeEnabled(int userHandle) {
936 UserInfo info = getUserManager().getUserInfo(userHandle);
Clara Bayarri8d35de82016-01-12 17:29:29 +0000937 if (info == null || !info.isManagedProfile()) {
Clara Bayarria1771112015-12-18 16:29:18 +0000938 return false;
939 }
940 return getBoolean(SEPARATE_PROFILE_CHALLENGE_KEY, false, userHandle);
941 }
942
943 /**
944 * Retrieves whether the current DPM allows use of the Profile Challenge.
945 */
946 public boolean isSeparateProfileChallengeAllowed(int userHandle) {
947 UserInfo info = getUserManager().getUserInfo(userHandle);
Clara Bayarri8d35de82016-01-12 17:29:29 +0000948 if (info == null || !info.isManagedProfile()) {
Clara Bayarria1771112015-12-18 16:29:18 +0000949 return false;
950 }
951 return getDevicePolicyManager().isSeparateProfileChallengeAllowed(userHandle);
952 }
953
954 /**
Clara Bayarrid7693912016-01-22 17:26:31 +0000955 * Retrieves whether the current profile and device locks can be unified.
956 */
957 public boolean isSeparateProfileChallengeAllowedToUnify(int userHandle) {
958 return getDevicePolicyManager().isProfileActivePasswordSufficientForParent(userHandle);
959 }
960
961 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800962 * Deserialize a pattern.
963 * @param string The pattern serialized with {@link #patternToString}
964 * @return The pattern.
965 */
966 public static List<LockPatternView.Cell> stringToPattern(String string) {
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100967 if (string == null) {
968 return null;
969 }
970
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800971 List<LockPatternView.Cell> result = Lists.newArrayList();
972
973 final byte[] bytes = string.getBytes();
974 for (int i = 0; i < bytes.length; i++) {
Andres Moralese40bad82015-05-28 14:21:36 -0700975 byte b = (byte) (bytes[i] - '1');
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800976 result.add(LockPatternView.Cell.of(b / 3, b % 3));
977 }
978 return result;
979 }
980
981 /**
982 * Serialize a pattern.
983 * @param pattern The pattern.
984 * @return The pattern in string form.
985 */
986 public static String patternToString(List<LockPatternView.Cell> pattern) {
987 if (pattern == null) {
988 return "";
989 }
990 final int patternSize = pattern.size();
991
992 byte[] res = new byte[patternSize];
993 for (int i = 0; i < patternSize; i++) {
994 LockPatternView.Cell cell = pattern.get(i);
Andres Moralese40bad82015-05-28 14:21:36 -0700995 res[i] = (byte) (cell.getRow() * 3 + cell.getColumn() + '1');
996 }
997 return new String(res);
998 }
999
1000 public static String patternStringToBaseZero(String pattern) {
1001 if (pattern == null) {
1002 return "";
1003 }
1004 final int patternSize = pattern.length();
1005
1006 byte[] res = new byte[patternSize];
1007 final byte[] bytes = pattern.getBytes();
1008 for (int i = 0; i < patternSize; i++) {
1009 res[i] = (byte) (bytes[i] - '1');
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001010 }
1011 return new String(res);
1012 }
Jim Miller69aa4a92009-12-22 19:03:28 -08001013
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001014 /*
1015 * Generate an SHA-1 hash for the pattern. Not the most secure, but it is
1016 * at least a second level of protection. First level is that the file
1017 * is in a location only readable by the system process.
1018 * @param pattern the gesture pattern.
1019 * @return the hash of the pattern in a byte array.
1020 */
Jim Millerde1af082013-09-11 14:58:26 -07001021 public static byte[] patternToHash(List<LockPatternView.Cell> pattern) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001022 if (pattern == null) {
1023 return null;
1024 }
Jim Miller69aa4a92009-12-22 19:03:28 -08001025
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001026 final int patternSize = pattern.size();
1027 byte[] res = new byte[patternSize];
1028 for (int i = 0; i < patternSize; i++) {
1029 LockPatternView.Cell cell = pattern.get(i);
1030 res[i] = (byte) (cell.getRow() * 3 + cell.getColumn());
1031 }
1032 try {
1033 MessageDigest md = MessageDigest.getInstance("SHA-1");
1034 byte[] hash = md.digest(res);
1035 return hash;
1036 } catch (NoSuchAlgorithmException nsa) {
1037 return res;
1038 }
1039 }
1040
Geoffrey Borggaard987672d22014-07-18 16:47:18 -04001041 private String getSalt(int userId) {
1042 long salt = getLong(LOCK_PASSWORD_SALT_KEY, 0, userId);
Jim Miller11b019d2010-01-20 16:34:45 -08001043 if (salt == 0) {
1044 try {
1045 salt = SecureRandom.getInstance("SHA1PRNG").nextLong();
Geoffrey Borggaard987672d22014-07-18 16:47:18 -04001046 setLong(LOCK_PASSWORD_SALT_KEY, salt, userId);
1047 Log.v(TAG, "Initialized lock password salt for user: " + userId);
Jim Miller11b019d2010-01-20 16:34:45 -08001048 } catch (NoSuchAlgorithmException e) {
1049 // Throw an exception rather than storing a password we'll never be able to recover
1050 throw new IllegalStateException("Couldn't get SecureRandom number", e);
1051 }
1052 }
1053 return Long.toHexString(salt);
1054 }
1055
Jim Miller69aa4a92009-12-22 19:03:28 -08001056 /*
1057 * Generate a hash for the given password. To avoid brute force attacks, we use a salted hash.
1058 * Not the most secure, but it is at least a second level of protection. First level is that
1059 * the file is in a location only readable by the system process.
Narayan Kamath78108a32014-12-16 12:56:23 +00001060 *
Jim Miller69aa4a92009-12-22 19:03:28 -08001061 * @param password the gesture pattern.
Narayan Kamath78108a32014-12-16 12:56:23 +00001062 *
Jim Miller69aa4a92009-12-22 19:03:28 -08001063 * @return the hash of the pattern in a byte array.
1064 */
Geoffrey Borggaard987672d22014-07-18 16:47:18 -04001065 public byte[] passwordToHash(String password, int userId) {
Jim Miller69aa4a92009-12-22 19:03:28 -08001066 if (password == null) {
1067 return null;
1068 }
Narayan Kamath78108a32014-12-16 12:56:23 +00001069
Jim Miller69aa4a92009-12-22 19:03:28 -08001070 try {
Geoffrey Borggaard987672d22014-07-18 16:47:18 -04001071 byte[] saltedPassword = (password + getSalt(userId)).getBytes();
Narayan Kamath78108a32014-12-16 12:56:23 +00001072 byte[] sha1 = MessageDigest.getInstance("SHA-1").digest(saltedPassword);
1073 byte[] md5 = MessageDigest.getInstance("MD5").digest(saltedPassword);
Jim Miller69aa4a92009-12-22 19:03:28 -08001074
Narayan Kamath78108a32014-12-16 12:56:23 +00001075 byte[] combined = new byte[sha1.length + md5.length];
1076 System.arraycopy(sha1, 0, combined, 0, sha1.length);
1077 System.arraycopy(md5, 0, combined, sha1.length, md5.length);
1078
1079 final char[] hexEncoded = HexEncoding.encode(combined);
1080 return new String(hexEncoded).getBytes(StandardCharsets.UTF_8);
1081 } catch (NoSuchAlgorithmException e) {
1082 throw new AssertionError("Missing digest algorithm: ", e);
Jim Miller69aa4a92009-12-22 19:03:28 -08001083 }
Jim Miller69aa4a92009-12-22 19:03:28 -08001084 }
1085
1086 /**
Adrian Roos9dd16eb2015-01-08 16:20:49 +01001087 * @param userId the user for which to report the value
1088 * @return Whether the lock screen is secured.
1089 */
1090 public boolean isSecure(int userId) {
1091 int mode = getKeyguardStoredPasswordQuality(userId);
1092 return isLockPatternEnabled(mode, userId) || isLockPasswordEnabled(mode, userId);
1093 }
1094
Adrian Roosdce01222015-01-07 22:39:01 +01001095 public boolean isLockPasswordEnabled(int userId) {
Adrian Roos9dd16eb2015-01-08 16:20:49 +01001096 return isLockPasswordEnabled(getKeyguardStoredPasswordQuality(userId), userId);
1097 }
1098
1099 private boolean isLockPasswordEnabled(int mode, int userId) {
Danielle Millett73da5fe2011-09-13 16:20:05 -04001100 final boolean passwordEnabled = mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC
1101 || mode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC
Jim Miller85516d02014-01-31 17:08:37 -08001102 || mode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX
Danielle Millett73da5fe2011-09-13 16:20:05 -04001103 || mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC
1104 || mode == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
Adrian Roos9dd16eb2015-01-08 16:20:49 +01001105 return passwordEnabled && savedPasswordExists(userId);
Jim Miller69aa4a92009-12-22 19:03:28 -08001106 }
1107
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001108 /**
Adrian Roos230635e2015-01-07 20:50:29 +01001109 * @return Whether the lock pattern is enabled
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001110 */
Adrian Roos50bfeec2014-11-20 16:21:11 +01001111 public boolean isLockPatternEnabled(int userId) {
Adrian Roos9dd16eb2015-01-08 16:20:49 +01001112 return isLockPatternEnabled(getKeyguardStoredPasswordQuality(userId), userId);
Danielle Millett925a7d82012-03-19 18:02:20 -04001113 }
1114
Bryce Lee46145962015-12-14 14:39:10 -08001115 @Deprecated
1116 public boolean isLegacyLockPatternEnabled(int userId) {
1117 // Note: this value should default to {@code true} to avoid any reset that might result.
1118 // We must use a special key to read this value, since it will by default return the value
1119 // based on the new logic.
1120 return getBoolean(LEGACY_LOCK_PATTERN_ENABLED, true, userId);
1121 }
1122
1123 @Deprecated
1124 public void setLegacyLockPatternEnabled(int userId) {
1125 setBoolean(Settings.Secure.LOCK_PATTERN_ENABLED, true, userId);
1126 }
1127
Adrian Roos9dd16eb2015-01-08 16:20:49 +01001128 private boolean isLockPatternEnabled(int mode, int userId) {
1129 return mode == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING
1130 && savedPatternExists(userId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001131 }
1132
1133 /**
1134 * @return Whether the visible pattern is enabled.
1135 */
Adrian Roos8150d2a2015-04-16 17:11:20 -07001136 public boolean isVisiblePatternEnabled(int userId) {
1137 return getBoolean(Settings.Secure.LOCK_PATTERN_VISIBLE, false, userId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001138 }
1139
1140 /**
1141 * Set whether the visible pattern is enabled.
1142 */
Adrian Roos8150d2a2015-04-16 17:11:20 -07001143 public void setVisiblePatternEnabled(boolean enabled, int userId) {
Adrian Roosdce01222015-01-07 22:39:01 +01001144 setBoolean(Settings.Secure.LOCK_PATTERN_VISIBLE, enabled, userId);
Paul Lawrence878ba0a2014-08-20 13:08:01 -07001145
1146 // Update for crypto if owner
Xiaohui Chen86c69dd2015-08-27 15:44:02 -07001147 if (userId != UserHandle.USER_SYSTEM) {
Paul Lawrence878ba0a2014-08-20 13:08:01 -07001148 return;
1149 }
1150
1151 IBinder service = ServiceManager.getService("mount");
1152 if (service == null) {
1153 Log.e(TAG, "Could not find the mount service to update the user info");
1154 return;
1155 }
1156
1157 IMountService mountService = IMountService.Stub.asInterface(service);
1158 try {
Elliott Hughesf839b4f2014-09-26 12:30:47 -07001159 mountService.setField(StorageManager.PATTERN_VISIBLE_KEY, enabled ? "1" : "0");
Paul Lawrence878ba0a2014-08-20 13:08:01 -07001160 } catch (RemoteException e) {
1161 Log.e(TAG, "Error changing pattern visible state", e);
1162 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001163 }
1164
1165 /**
Paul Lawrenced8fdb332015-05-18 13:26:11 -07001166 * Set whether the visible password is enabled for cryptkeeper screen.
1167 */
1168 public void setVisiblePasswordEnabled(boolean enabled, int userId) {
1169 // Update for crypto if owner
Xiaohui Chen86c69dd2015-08-27 15:44:02 -07001170 if (userId != UserHandle.USER_SYSTEM) {
Paul Lawrenced8fdb332015-05-18 13:26:11 -07001171 return;
1172 }
1173
1174 IBinder service = ServiceManager.getService("mount");
1175 if (service == null) {
1176 Log.e(TAG, "Could not find the mount service to update the user info");
1177 return;
1178 }
1179
1180 IMountService mountService = IMountService.Stub.asInterface(service);
1181 try {
1182 mountService.setField(StorageManager.PASSWORD_VISIBLE_KEY, enabled ? "1" : "0");
1183 } catch (RemoteException e) {
1184 Log.e(TAG, "Error changing password visible state", e);
1185 }
1186 }
1187
1188 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001189 * @return Whether tactile feedback for the pattern is enabled.
1190 */
1191 public boolean isTactileFeedbackEnabled() {
Jeff Sharkey5ed9d682012-10-10 14:28:27 -07001192 return Settings.System.getIntForUser(mContentResolver,
1193 Settings.System.HAPTIC_FEEDBACK_ENABLED, 1, UserHandle.USER_CURRENT) != 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001194 }
1195
1196 /**
1197 * Set and store the lockout deadline, meaning the user can't attempt his/her unlock
1198 * pattern until the deadline has passed.
1199 * @return the chosen deadline.
1200 */
Andres Morales23974272015-05-14 22:42:26 -07001201 public long setLockoutAttemptDeadline(int userId, int timeoutMs) {
1202 final long deadline = SystemClock.elapsedRealtime() + timeoutMs;
Adrian Roos8150d2a2015-04-16 17:11:20 -07001203 setLong(LOCKOUT_ATTEMPT_DEADLINE, deadline, userId);
Andres Morales23974272015-05-14 22:42:26 -07001204 setLong(LOCKOUT_ATTEMPT_TIMEOUT_MS, timeoutMs, userId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001205 return deadline;
1206 }
1207
1208 /**
1209 * @return The elapsed time in millis in the future when the user is allowed to
1210 * attempt to enter his/her lock pattern, or 0 if the user is welcome to
1211 * enter a pattern.
1212 */
Adrian Roos8150d2a2015-04-16 17:11:20 -07001213 public long getLockoutAttemptDeadline(int userId) {
Andres Moralesa4e23372015-09-08 13:17:37 -07001214 long deadline = getLong(LOCKOUT_ATTEMPT_DEADLINE, 0L, userId);
Andres Morales23974272015-05-14 22:42:26 -07001215 final long timeoutMs = getLong(LOCKOUT_ATTEMPT_TIMEOUT_MS, 0L, userId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001216 final long now = SystemClock.elapsedRealtime();
Jorim Jaggie3e6d562015-09-28 13:57:37 -07001217 if (deadline < now && deadline != 0) {
Andres Moralesa4e23372015-09-08 13:17:37 -07001218 // timeout expired
1219 setLong(LOCKOUT_ATTEMPT_DEADLINE, 0, userId);
1220 setLong(LOCKOUT_ATTEMPT_TIMEOUT_MS, 0, userId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001221 return 0L;
1222 }
Andres Moralesa4e23372015-09-08 13:17:37 -07001223
1224 if (deadline > (now + timeoutMs)) {
1225 // device was rebooted, set new deadline
1226 deadline = now + timeoutMs;
1227 setLong(LOCKOUT_ATTEMPT_DEADLINE, deadline, userId);
1228 }
1229
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001230 return deadline;
1231 }
1232
Jim Millerf45bb402013-08-20 18:58:32 -07001233 private boolean getBoolean(String secureSettingKey, boolean defaultValue, int userId) {
Amith Yamasani52c489c2012-03-28 11:42:42 -07001234 try {
Jim Millerf45bb402013-08-20 18:58:32 -07001235 return getLockSettings().getBoolean(secureSettingKey, defaultValue, userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -07001236 } catch (RemoteException re) {
1237 return defaultValue;
1238 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001239 }
1240
Jim Millerf45bb402013-08-20 18:58:32 -07001241 private void setBoolean(String secureSettingKey, boolean enabled, int userId) {
Amith Yamasani52c489c2012-03-28 11:42:42 -07001242 try {
Jim Millerf45bb402013-08-20 18:58:32 -07001243 getLockSettings().setBoolean(secureSettingKey, enabled, userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -07001244 } catch (RemoteException re) {
1245 // What can we do?
1246 Log.e(TAG, "Couldn't write boolean " + secureSettingKey + re);
1247 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001248 }
1249
Geoffrey Borggaard987672d22014-07-18 16:47:18 -04001250 private long getLong(String secureSettingKey, long defaultValue, int userHandle) {
1251 try {
1252 return getLockSettings().getLong(secureSettingKey, defaultValue, userHandle);
1253 } catch (RemoteException re) {
1254 return defaultValue;
1255 }
1256 }
1257
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001258 private void setLong(String secureSettingKey, long value, int userHandle) {
Amith Yamasani52c489c2012-03-28 11:42:42 -07001259 try {
Kenny Guy0cf13702013-11-29 16:33:05 +00001260 getLockSettings().setLong(secureSettingKey, value, userHandle);
Amith Yamasani52c489c2012-03-28 11:42:42 -07001261 } catch (RemoteException re) {
1262 // What can we do?
1263 Log.e(TAG, "Couldn't write long " + secureSettingKey + re);
1264 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001265 }
1266
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001267 private String getString(String secureSettingKey, int userHandle) {
Amith Yamasani52c489c2012-03-28 11:42:42 -07001268 try {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001269 return getLockSettings().getString(secureSettingKey, null, userHandle);
Amith Yamasani52c489c2012-03-28 11:42:42 -07001270 } catch (RemoteException re) {
1271 return null;
1272 }
Konstantin Lopyrev863f22d2010-05-12 17:16:58 -07001273 }
1274
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001275 private void setString(String secureSettingKey, String value, int userHandle) {
Amith Yamasani52c489c2012-03-28 11:42:42 -07001276 try {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001277 getLockSettings().setString(secureSettingKey, value, userHandle);
Amith Yamasani52c489c2012-03-28 11:42:42 -07001278 } catch (RemoteException re) {
1279 // What can we do?
1280 Log.e(TAG, "Couldn't write string " + secureSettingKey + re);
1281 }
Konstantin Lopyrev863f22d2010-05-12 17:16:58 -07001282 }
1283
Adrian Roos8150d2a2015-04-16 17:11:20 -07001284 public void setPowerButtonInstantlyLocks(boolean enabled, int userId) {
1285 setBoolean(LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS, enabled, userId);
Jim Millera4edd152012-01-06 18:24:04 -08001286 }
1287
Adrian Roos8150d2a2015-04-16 17:11:20 -07001288 public boolean getPowerButtonInstantlyLocks(int userId) {
1289 return getBoolean(LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS, true, userId);
Adrian Roos82142c22014-03-27 14:56:59 +01001290 }
1291
1292 public void setEnabledTrustAgents(Collection<ComponentName> activeTrustAgents, int userId) {
1293 StringBuilder sb = new StringBuilder();
1294 for (ComponentName cn : activeTrustAgents) {
1295 if (sb.length() > 0) {
1296 sb.append(',');
1297 }
1298 sb.append(cn.flattenToShortString());
1299 }
1300 setString(ENABLED_TRUST_AGENTS, sb.toString(), userId);
Adrian Roos8150d2a2015-04-16 17:11:20 -07001301 getTrustManager().reportEnabledTrustAgentsChanged(userId);
Adrian Roos82142c22014-03-27 14:56:59 +01001302 }
1303
1304 public List<ComponentName> getEnabledTrustAgents(int userId) {
1305 String serialized = getString(ENABLED_TRUST_AGENTS, userId);
1306 if (TextUtils.isEmpty(serialized)) {
1307 return null;
1308 }
1309 String[] split = serialized.split(",");
1310 ArrayList<ComponentName> activeTrustAgents = new ArrayList<ComponentName>(split.length);
1311 for (String s : split) {
1312 if (!TextUtils.isEmpty(s)) {
1313 activeTrustAgents.add(ComponentName.unflattenFromString(s));
1314 }
1315 }
1316 return activeTrustAgents;
1317 }
Adrian Roos2c12cfa2014-06-25 23:28:53 +02001318
1319 /**
Adrian Roosb5e47222015-08-14 15:53:06 -07001320 * Disable trust until credentials have been entered for user {@param userId}.
1321 *
1322 * Requires the {@link android.Manifest.permission#ACCESS_KEYGUARD_SECURE_STORAGE} permission.
1323 *
1324 * @param userId either an explicit user id or {@link android.os.UserHandle#USER_ALL}
Adrian Roos2c12cfa2014-06-25 23:28:53 +02001325 */
1326 public void requireCredentialEntry(int userId) {
Jorim Jaggi16093fe32015-09-09 23:29:17 +00001327 requireStrongAuth(StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST, userId);
Adrian Roosb5e47222015-08-14 15:53:06 -07001328 }
1329
1330 /**
1331 * Requests strong authentication for user {@param userId}.
1332 *
1333 * Requires the {@link android.Manifest.permission#ACCESS_KEYGUARD_SECURE_STORAGE} permission.
1334 *
1335 * @param strongAuthReason a combination of {@link StrongAuthTracker.StrongAuthFlags} indicating
1336 * the reason for and the strength of the requested authentication.
1337 * @param userId either an explicit user id or {@link android.os.UserHandle#USER_ALL}
1338 */
1339 public void requireStrongAuth(@StrongAuthTracker.StrongAuthFlags int strongAuthReason,
1340 int userId) {
1341 try {
1342 getLockSettings().requireStrongAuth(strongAuthReason, userId);
1343 } catch (RemoteException e) {
1344 Log.e(TAG, "Error while requesting strong auth: " + e);
1345 }
Adrian Roos2c12cfa2014-06-25 23:28:53 +02001346 }
Adrian Roos4b9e3242014-08-20 23:36:25 +02001347
Adrian Roosf8f56bc2014-11-20 23:55:34 +01001348 private void onAfterChangingPassword(int userHandle) {
1349 getTrustManager().reportEnabledTrustAgentsChanged(userHandle);
Adrian Roos4b9e3242014-08-20 23:36:25 +02001350 }
Jim Millerdd5de712014-10-16 19:50:18 -07001351
1352 public boolean isCredentialRequiredToDecrypt(boolean defaultValue) {
1353 final int value = Settings.Global.getInt(mContentResolver,
1354 Settings.Global.REQUIRE_PASSWORD_TO_DECRYPT, -1);
1355 return value == -1 ? defaultValue : (value != 0);
1356 }
1357
1358 public void setCredentialRequiredToDecrypt(boolean required) {
Robin Leed39113e2016-01-22 15:44:49 +00001359 if (!(getUserManager().isSystemUser() || getUserManager().isPrimaryUser())) {
1360 throw new IllegalStateException(
1361 "Only the system or primary user may call setCredentialRequiredForDecrypt()");
Jim Millerdd5de712014-10-16 19:50:18 -07001362 }
Paul Lawrence688af6c2015-05-15 11:26:17 -07001363
1364 if (isDeviceEncryptionEnabled()){
1365 Settings.Global.putInt(mContext.getContentResolver(),
1366 Settings.Global.REQUIRE_PASSWORD_TO_DECRYPT, required ? 1 : 0);
1367 }
Jim Millerdd5de712014-10-16 19:50:18 -07001368 }
Andrei Kapishnikov4eb6a362015-04-02 15:21:20 -04001369
1370 private boolean isDoNotAskCredentialsOnBootSet() {
1371 return mDevicePolicyManager.getDoNotAskCredentialsOnBoot();
1372 }
1373
1374 private boolean shouldEncryptWithCredentials(boolean defaultValue) {
1375 return isCredentialRequiredToDecrypt(defaultValue) && !isDoNotAskCredentialsOnBootSet();
1376 }
Xiyuan Xiaaa262942015-05-05 15:18:45 -07001377
1378 private void throwIfCalledOnMainThread() {
1379 if (Looper.getMainLooper().isCurrentThread()) {
1380 throw new IllegalStateException("should not be called from the main thread.");
1381 }
1382 }
Adrian Roosb5e47222015-08-14 15:53:06 -07001383
1384 public void registerStrongAuthTracker(final StrongAuthTracker strongAuthTracker) {
1385 try {
1386 getLockSettings().registerStrongAuthTracker(strongAuthTracker.mStub);
1387 } catch (RemoteException e) {
1388 throw new RuntimeException("Could not register StrongAuthTracker");
1389 }
1390 }
1391
1392 public void unregisterStrongAuthTracker(final StrongAuthTracker strongAuthTracker) {
1393 try {
1394 getLockSettings().unregisterStrongAuthTracker(strongAuthTracker.mStub);
1395 } catch (RemoteException e) {
1396 Log.e(TAG, "Could not unregister StrongAuthTracker", e);
1397 }
1398 }
1399
1400 /**
1401 * Tracks the global strong authentication state.
1402 */
1403 public static class StrongAuthTracker {
1404
1405 @IntDef(flag = true,
1406 value = { STRONG_AUTH_NOT_REQUIRED,
1407 STRONG_AUTH_REQUIRED_AFTER_BOOT,
1408 STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW,
Jorim Jaggi16093fe32015-09-09 23:29:17 +00001409 SOME_AUTH_REQUIRED_AFTER_USER_REQUEST})
Adrian Roosb5e47222015-08-14 15:53:06 -07001410 @Retention(RetentionPolicy.SOURCE)
1411 public @interface StrongAuthFlags {}
1412
1413 /**
1414 * Strong authentication is not required.
1415 */
1416 public static final int STRONG_AUTH_NOT_REQUIRED = 0x0;
1417
1418 /**
1419 * Strong authentication is required because the user has not authenticated since boot.
1420 */
1421 public static final int STRONG_AUTH_REQUIRED_AFTER_BOOT = 0x1;
1422
1423 /**
Jorim Jaggi16093fe32015-09-09 23:29:17 +00001424 * Strong authentication is required because a device admin has requested it.
Adrian Roosb5e47222015-08-14 15:53:06 -07001425 */
1426 public static final int STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW = 0x2;
1427
1428 /**
Jorim Jaggi16093fe32015-09-09 23:29:17 +00001429 * Some authentication is required because the user has temporarily disabled trust.
Adrian Roosb5e47222015-08-14 15:53:06 -07001430 */
Jorim Jaggi16093fe32015-09-09 23:29:17 +00001431 public static final int SOME_AUTH_REQUIRED_AFTER_USER_REQUEST = 0x4;
Adrian Roosb5e47222015-08-14 15:53:06 -07001432
Adrian Roos873010d2015-08-25 15:59:00 -07001433 /**
1434 * Strong authentication is required because the user has been locked out after too many
1435 * attempts.
1436 */
1437 public static final int STRONG_AUTH_REQUIRED_AFTER_LOCKOUT = 0x8;
1438
Adrian Roosaf4ab3e2015-09-02 13:23:30 -07001439 /**
1440 * Some authentication is required because the user has entered a wrong credential.
1441 */
1442 public static final int SOME_AUTH_REQUIRED_AFTER_WRONG_CREDENTIAL = 0x10;
1443
Adrian Roosaf4ab3e2015-09-02 13:23:30 -07001444 private static final int ALLOWING_FINGERPRINT = STRONG_AUTH_NOT_REQUIRED
Jorim Jaggi16093fe32015-09-09 23:29:17 +00001445 | SOME_AUTH_REQUIRED_AFTER_USER_REQUEST
Adrian Roosaf4ab3e2015-09-02 13:23:30 -07001446 | SOME_AUTH_REQUIRED_AFTER_WRONG_CREDENTIAL;
Adrian Roosb5e47222015-08-14 15:53:06 -07001447
Adrian Roosaf4ab3e2015-09-02 13:23:30 -07001448 private final SparseIntArray mStrongAuthRequiredForUser = new SparseIntArray();
Adrian Roosb5e47222015-08-14 15:53:06 -07001449 private final H mHandler;
Rakesh Iyera7aa4d62016-01-19 17:27:23 -08001450 private final int mDefaultStrongAuthFlags;
Adrian Roosb5e47222015-08-14 15:53:06 -07001451
Rakesh Iyera7aa4d62016-01-19 17:27:23 -08001452 public StrongAuthTracker(Context context) {
1453 this(context, Looper.myLooper());
Adrian Roosb5e47222015-08-14 15:53:06 -07001454 }
1455
1456 /**
1457 * @param looper the looper on whose thread calls to {@link #onStrongAuthRequiredChanged}
1458 * will be scheduled.
Rakesh Iyera7aa4d62016-01-19 17:27:23 -08001459 * @param context the current {@link Context}
Adrian Roosb5e47222015-08-14 15:53:06 -07001460 */
Rakesh Iyera7aa4d62016-01-19 17:27:23 -08001461 public StrongAuthTracker(Context context, Looper looper) {
Adrian Roosb5e47222015-08-14 15:53:06 -07001462 mHandler = new H(looper);
Rakesh Iyera7aa4d62016-01-19 17:27:23 -08001463 mDefaultStrongAuthFlags = getDefaultFlags(context);
1464 }
1465
1466 public static @StrongAuthFlags int getDefaultFlags(Context context) {
1467 boolean strongAuthRequired = context.getResources().getBoolean(
1468 com.android.internal.R.bool.config_strongAuthRequiredOnBoot);
1469 return strongAuthRequired ? STRONG_AUTH_REQUIRED_AFTER_BOOT : STRONG_AUTH_NOT_REQUIRED;
Adrian Roosb5e47222015-08-14 15:53:06 -07001470 }
1471
1472 /**
1473 * Returns {@link #STRONG_AUTH_NOT_REQUIRED} if strong authentication is not required,
1474 * otherwise returns a combination of {@link StrongAuthFlags} indicating why strong
1475 * authentication is required.
1476 *
1477 * @param userId the user for whom the state is queried.
1478 */
1479 public @StrongAuthFlags int getStrongAuthForUser(int userId) {
Rakesh Iyera7aa4d62016-01-19 17:27:23 -08001480 return mStrongAuthRequiredForUser.get(userId, mDefaultStrongAuthFlags);
Adrian Roosb5e47222015-08-14 15:53:06 -07001481 }
1482
1483 /**
1484 * @return true if unlocking with trust alone is allowed for {@param userId} by the current
1485 * strong authentication requirements.
1486 */
1487 public boolean isTrustAllowedForUser(int userId) {
1488 return getStrongAuthForUser(userId) == STRONG_AUTH_NOT_REQUIRED;
1489 }
1490
1491 /**
1492 * @return true if unlocking with fingerprint alone is allowed for {@param userId} by the
1493 * current strong authentication requirements.
1494 */
1495 public boolean isFingerprintAllowedForUser(int userId) {
Adrian Roosaf4ab3e2015-09-02 13:23:30 -07001496 return (getStrongAuthForUser(userId) & ~ALLOWING_FINGERPRINT) == 0;
Adrian Roosb5e47222015-08-14 15:53:06 -07001497 }
1498
1499 /**
1500 * Called when the strong authentication requirements for {@param userId} changed.
1501 */
1502 public void onStrongAuthRequiredChanged(int userId) {
1503 }
1504
1505 void handleStrongAuthRequiredChanged(@StrongAuthFlags int strongAuthFlags,
1506 int userId) {
1507
1508 int oldValue = getStrongAuthForUser(userId);
1509 if (strongAuthFlags != oldValue) {
Rakesh Iyera7aa4d62016-01-19 17:27:23 -08001510 if (strongAuthFlags == mDefaultStrongAuthFlags) {
Adrian Roosb5e47222015-08-14 15:53:06 -07001511 mStrongAuthRequiredForUser.delete(userId);
1512 } else {
1513 mStrongAuthRequiredForUser.put(userId, strongAuthFlags);
1514 }
1515 onStrongAuthRequiredChanged(userId);
1516 }
1517 }
1518
1519
1520 final IStrongAuthTracker.Stub mStub = new IStrongAuthTracker.Stub() {
1521 @Override
1522 public void onStrongAuthRequiredChanged(@StrongAuthFlags int strongAuthFlags,
1523 int userId) {
1524 mHandler.obtainMessage(H.MSG_ON_STRONG_AUTH_REQUIRED_CHANGED,
1525 strongAuthFlags, userId).sendToTarget();
1526 }
1527 };
1528
1529 private class H extends Handler {
1530 static final int MSG_ON_STRONG_AUTH_REQUIRED_CHANGED = 1;
1531
1532 public H(Looper looper) {
1533 super(looper);
1534 }
1535
1536 @Override
1537 public void handleMessage(Message msg) {
1538 switch (msg.what) {
1539 case MSG_ON_STRONG_AUTH_REQUIRED_CHANGED:
1540 handleStrongAuthRequiredChanged(msg.arg1, msg.arg2);
1541 break;
1542 }
1543 }
1544 };
1545 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001546}