blob: d4ab4265b3fb9aba06cc81452255afe948ec2070 [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
Rubin Xu682d1672018-03-21 09:13:44 +000019import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC;
20import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC;
21import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
22import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_MANAGED;
23import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
24import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX;
25import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
26import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
27
Adrian Roosb5e47222015-08-14 15:53:06 -070028import android.annotation.IntDef;
Jorim Jaggie8fde5d2016-06-30 23:41:37 -070029import android.annotation.Nullable;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -080030import android.app.admin.DevicePolicyManager;
Andrew Scull5f9e6f32016-08-02 14:22:17 +010031import android.app.admin.PasswordMetrics;
Adrian Roosb5e47222015-08-14 15:53:06 -070032import android.app.trust.IStrongAuthTracker;
Adrian Roos82142c22014-03-27 14:56:59 +010033import android.app.trust.TrustManager;
Adrian Roos82142c22014-03-27 14:56:59 +010034import android.content.ComponentName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080035import android.content.ContentResolver;
Jim Miller31f90b62010-01-20 13:35:20 -080036import android.content.Context;
Clara Bayarria1771112015-12-18 16:29:18 +000037import android.content.pm.UserInfo;
Paul Lawrence3a5a0be2014-09-25 09:26:34 -070038import android.os.AsyncTask;
Adrian Roosb5e47222015-08-14 15:53:06 -070039import android.os.Handler;
Jason parksf7b3cd42011-01-27 09:28:25 -060040import android.os.IBinder;
Xiyuan Xiaaa262942015-05-05 15:18:45 -070041import android.os.Looper;
Adrian Roosb5e47222015-08-14 15:53:06 -070042import android.os.Message;
Jim Miller69ac9882010-02-24 15:35:05 -080043import android.os.RemoteException;
44import android.os.ServiceManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080045import android.os.SystemClock;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -070046import android.os.UserHandle;
Clara Bayarria1771112015-12-18 16:29:18 +000047import android.os.UserManager;
Sudheer Shanka2250d562016-11-07 15:41:02 -080048import android.os.storage.IStorageManager;
Paul Lawrence8e397362014-01-27 15:22:30 -080049import android.os.storage.StorageManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080050import android.provider.Settings;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080051import android.text.TextUtils;
52import android.util.Log;
Adrian Roosb5e47222015-08-14 15:53:06 -070053import android.util.SparseIntArray;
Kevin Chyna3e55822017-10-04 15:47:24 -070054import android.util.SparseLongArray;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080055
Rubin Xu0cbc19e2016-12-09 14:00:21 +000056import com.android.internal.annotations.VisibleForTesting;
Rubin Xufcd49f92017-08-24 18:21:52 +010057import com.android.server.LocalServices;
Michael Jurka1254f2f2012-10-25 11:44:31 -070058import com.google.android.collect.Lists;
Adrian Roos9dd16eb2015-01-08 16:20:49 +010059
Rubin Xu1de89b32016-11-30 20:03:13 +000060import libcore.util.HexEncoding;
61
Adrian Roosb5e47222015-08-14 15:53:06 -070062import java.lang.annotation.Retention;
63import java.lang.annotation.RetentionPolicy;
Narayan Kamath78108a32014-12-16 12:56:23 +000064import java.nio.charset.StandardCharsets;
Brian Carlstrom929a1c22011-02-01 21:54:09 -080065import java.security.MessageDigest;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080066import java.security.NoSuchAlgorithmException;
Jim Miller11b019d2010-01-20 16:34:45 -080067import java.security.SecureRandom;
Adrian Roos82142c22014-03-27 14:56:59 +010068import java.util.ArrayList;
69import java.util.Collection;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080070import java.util.List;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080071/**
Brian Carlstrom5cfee3f2011-05-31 01:00:15 -070072 * Utilities for the lock pattern and its settings.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080073 */
74public class LockPatternUtils {
75
76 private static final String TAG = "LockPatternUtils";
Brian Colonnaa0ee0042014-07-16 13:50:47 -040077 private static final boolean DEBUG = false;
Adrian Roos8370e472017-07-23 14:35:59 +020078 private static final boolean FRP_CREDENTIAL_ENABLED = true;
Jim Miller69aa4a92009-12-22 19:03:28 -080079
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080080 /**
Rubin Xu1de89b32016-11-30 20:03:13 +000081 * The key to identify when the lock pattern enabled flag is being accessed for legacy reasons.
Bryce Lee46145962015-12-14 14:39:10 -080082 */
83 public static final String LEGACY_LOCK_PATTERN_ENABLED = "legacy_lock_pattern_enabled";
84
85 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080086 * The number of incorrect attempts before which we fall back on an alternative
87 * method of verifying the user, and resetting their lock pattern.
88 */
89 public static final int FAILED_ATTEMPTS_BEFORE_RESET = 20;
90
91 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080092 * The interval of the countdown for showing progress of the lockout.
93 */
94 public static final long FAILED_ATTEMPT_COUNTDOWN_INTERVAL_MS = 1000L;
95
Jim Miller4f369952011-08-19 18:29:22 -070096
97 /**
98 * This dictates when we start telling the user that continued failed attempts will wipe
99 * their device.
100 */
101 public static final int FAILED_ATTEMPTS_BEFORE_WIPE_GRACE = 5;
102
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800103 /**
104 * The minimum number of dots in a valid pattern.
105 */
106 public static final int MIN_LOCK_PATTERN_SIZE = 4;
107
108 /**
Adrian Roosf80e66ce92015-01-15 23:27:24 +0100109 * The minimum size of a valid password.
110 */
111 public static final int MIN_LOCK_PASSWORD_SIZE = 4;
112
113 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800114 * The minimum number of dots the user must include in a wrong pattern
115 * attempt for it to be counted against the counts that affect
116 * {@link #FAILED_ATTEMPTS_BEFORE_TIMEOUT} and {@link #FAILED_ATTEMPTS_BEFORE_RESET}
117 */
Jim Miller4f369952011-08-19 18:29:22 -0700118 public static final int MIN_PATTERN_REGISTER_FAIL = MIN_LOCK_PATTERN_SIZE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800119
Rubin Xu1de89b32016-11-30 20:03:13 +0000120 public static final int CREDENTIAL_TYPE_NONE = -1;
121
122 public static final int CREDENTIAL_TYPE_PATTERN = 1;
123
124 public static final int CREDENTIAL_TYPE_PASSWORD = 2;
125
Adrian Roos7374d3a2017-03-31 14:14:53 -0700126 /**
127 * Special user id for triggering the FRP verification flow.
128 */
129 public static final int USER_FRP = UserHandle.USER_NULL + 1;
130
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100131 @Deprecated
Jeff Sharkey7a96c392012-11-15 14:01:46 -0800132 public final static String LOCKOUT_PERMANENT_KEY = "lockscreen.lockedoutpermanently";
Jeff Sharkey7a96c392012-11-15 14:01:46 -0800133 public final static String PATTERN_EVER_CHOSEN_KEY = "lockscreen.patterneverchosen";
Jim Miller69aa4a92009-12-22 19:03:28 -0800134 public final static String PASSWORD_TYPE_KEY = "lockscreen.password_type";
Adrian Roos230635e2015-01-07 20:50:29 +0100135 @Deprecated
136 public final static String PASSWORD_TYPE_ALTERNATE_KEY = "lockscreen.password_type_alternate";
Jeff Sharkey7a96c392012-11-15 14:01:46 -0800137 public final static String LOCK_PASSWORD_SALT_KEY = "lockscreen.password_salt";
138 public final static String DISABLE_LOCKSCREEN_KEY = "lockscreen.disabled";
139 public final static String LOCKSCREEN_OPTIONS = "lockscreen.options";
Adrian Roos230635e2015-01-07 20:50:29 +0100140 @Deprecated
Jim Miller6edf2632011-09-05 16:03:14 -0700141 public final static String LOCKSCREEN_BIOMETRIC_WEAK_FALLBACK
142 = "lockscreen.biometric_weak_fallback";
Adrian Roos230635e2015-01-07 20:50:29 +0100143 @Deprecated
Danielle Millett7a072192011-10-03 17:36:01 -0400144 public final static String BIOMETRIC_WEAK_EVER_CHOSEN_KEY
145 = "lockscreen.biometricweakeverchosen";
Jim Millera4edd152012-01-06 18:24:04 -0800146 public final static String LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS
147 = "lockscreen.power_button_instantly_locks";
Adrian Roos230635e2015-01-07 20:50:29 +0100148 @Deprecated
Jim Millerf45bb402013-08-20 18:58:32 -0700149 public final static String LOCKSCREEN_WIDGETS_ENABLED = "lockscreen.widgets_enabled";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800150
Jeff Sharkey7a96c392012-11-15 14:01:46 -0800151 public final static String PASSWORD_HISTORY_KEY = "lockscreen.passwordhistory";
Konstantin Lopyrev863f22d2010-05-12 17:16:58 -0700152
Jim Miller187ec582013-04-15 18:27:54 -0700153 private static final String LOCK_SCREEN_OWNER_INFO = Settings.Secure.LOCK_SCREEN_OWNER_INFO;
154 private static final String LOCK_SCREEN_OWNER_INFO_ENABLED =
155 Settings.Secure.LOCK_SCREEN_OWNER_INFO_ENABLED;
156
Andrei Stingaceanu6644cd92015-11-10 13:03:31 +0000157 private static final String LOCK_SCREEN_DEVICE_OWNER_INFO = "lockscreen.device_owner_info";
158
Adrian Roos82142c22014-03-27 14:56:59 +0100159 private static final String ENABLED_TRUST_AGENTS = "lockscreen.enabledtrustagents";
Adrian Roosc13723f2016-01-12 20:29:03 +0100160 private static final String IS_TRUST_USUALLY_MANAGED = "lockscreen.istrustusuallymanaged";
Adrian Roos82142c22014-03-27 14:56:59 +0100161
Ricky Waid3982442016-05-24 19:27:08 +0100162 public static final String PROFILE_KEY_NAME_ENCRYPT = "profile_key_name_encrypt_";
163 public static final String PROFILE_KEY_NAME_DECRYPT = "profile_key_name_decrypt_";
Rubin Xu3bf722a2016-12-15 16:07:38 +0000164 public static final String SYNTHETIC_PASSWORD_KEY_PREFIX = "synthetic_password_";
165
166 public static final String SYNTHETIC_PASSWORD_HANDLE_KEY = "sp-handle";
167 public static final String SYNTHETIC_PASSWORD_ENABLED_KEY = "enable-sp";
Ricky Waid3982442016-05-24 19:27:08 +0100168
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800169 private final Context mContext;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800170 private final ContentResolver mContentResolver;
Jim Miller31f90b62010-01-20 13:35:20 -0800171 private DevicePolicyManager mDevicePolicyManager;
Amith Yamasani52c489c2012-03-28 11:42:42 -0700172 private ILockSettings mLockSettingsService;
Clara Bayarria1771112015-12-18 16:29:18 +0000173 private UserManager mUserManager;
Adrian Roos7a3bf7c2016-07-12 15:31:55 -0700174 private final Handler mHandler;
Kevin Chyna3e55822017-10-04 15:47:24 -0700175 private final SparseLongArray mLockoutDeadlines = new SparseLongArray();
Jim Milleree82f8f2012-10-01 16:26:18 -0700176
Adrian Roosc13723f2016-01-12 20:29:03 +0100177 /**
178 * Use {@link TrustManager#isTrustUsuallyManaged(int)}.
179 *
180 * This returns the lazily-peristed value and should only be used by TrustManagerService.
181 */
182 public boolean isTrustUsuallyManaged(int userId) {
183 if (!(mLockSettingsService instanceof ILockSettings.Stub)) {
184 throw new IllegalStateException("May only be called by TrustManagerService. "
185 + "Use TrustManager.isTrustUsuallyManaged()");
186 }
187 try {
188 return getLockSettings().getBoolean(IS_TRUST_USUALLY_MANAGED, false, userId);
189 } catch (RemoteException e) {
190 return false;
191 }
192 }
193
194 public void setTrustUsuallyManaged(boolean managed, int userId) {
195 try {
196 getLockSettings().setBoolean(IS_TRUST_USUALLY_MANAGED, managed, userId);
197 } catch (RemoteException e) {
198 // System dead.
199 }
200 }
Andres Morales23974272015-05-14 22:42:26 -0700201
Adrian Roos4ab7e592016-04-13 15:38:13 -0700202 public void userPresent(int userId) {
203 try {
204 getLockSettings().userPresent(userId);
205 } catch (RemoteException e) {
206 throw e.rethrowFromSystemServer();
207 }
208 }
209
Andres Morales23974272015-05-14 22:42:26 -0700210 public static final class RequestThrottledException extends Exception {
211 private int mTimeoutMs;
212 public RequestThrottledException(int timeoutMs) {
213 mTimeoutMs = timeoutMs;
214 }
215
216 /**
217 * @return The amount of time in ms before another request may
218 * be executed
219 */
220 public int getTimeoutMs() {
221 return mTimeoutMs;
222 }
223
224 }
225
Jim Millercd709882010-03-25 18:24:02 -0700226 public DevicePolicyManager getDevicePolicyManager() {
Jim Miller5b0fb3a2010-02-23 13:46:35 -0800227 if (mDevicePolicyManager == null) {
228 mDevicePolicyManager =
229 (DevicePolicyManager)mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
230 if (mDevicePolicyManager == null) {
231 Log.e(TAG, "Can't get DevicePolicyManagerService: is it running?",
232 new IllegalStateException("Stack trace:"));
233 }
234 }
235 return mDevicePolicyManager;
236 }
Amith Yamasani52c489c2012-03-28 11:42:42 -0700237
Clara Bayarria1771112015-12-18 16:29:18 +0000238 private UserManager getUserManager() {
239 if (mUserManager == null) {
240 mUserManager = UserManager.get(mContext);
241 }
242 return mUserManager;
243 }
244
Adrian Roos82142c22014-03-27 14:56:59 +0100245 private TrustManager getTrustManager() {
246 TrustManager trust = (TrustManager) mContext.getSystemService(Context.TRUST_SERVICE);
247 if (trust == null) {
248 Log.e(TAG, "Can't get TrustManagerService: is it running?",
249 new IllegalStateException("Stack trace:"));
250 }
251 return trust;
252 }
253
Jim Miller31f90b62010-01-20 13:35:20 -0800254 public LockPatternUtils(Context context) {
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800255 mContext = context;
Jim Miller31f90b62010-01-20 13:35:20 -0800256 mContentResolver = context.getContentResolver();
Adrian Roos7a3bf7c2016-07-12 15:31:55 -0700257
258 Looper looper = Looper.myLooper();
259 mHandler = looper != null ? new Handler(looper) : null;
Amith Yamasani52c489c2012-03-28 11:42:42 -0700260 }
Jim Miller69aa4a92009-12-22 19:03:28 -0800261
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000262 @VisibleForTesting
263 public ILockSettings getLockSettings() {
Amith Yamasani52c489c2012-03-28 11:42:42 -0700264 if (mLockSettingsService == null) {
Adrian Roos450ce9f2014-10-29 14:30:37 +0100265 ILockSettings service = ILockSettings.Stub.asInterface(
266 ServiceManager.getService("lock_settings"));
Adrian Roos138b8332014-11-11 13:51:07 +0100267 mLockSettingsService = service;
Brad Fitzpatrick90881002010-08-23 18:30:08 -0700268 }
Amith Yamasani52c489c2012-03-28 11:42:42 -0700269 return mLockSettingsService;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800270 }
271
Adrian Roos8150d2a2015-04-16 17:11:20 -0700272 public int getRequestedMinimumPasswordLength(int userId) {
273 return getDevicePolicyManager().getPasswordMinimumLength(null, userId);
Jim Miller31f90b62010-01-20 13:35:20 -0800274 }
275
Jim Miller31f90b62010-01-20 13:35:20 -0800276 /**
277 * Gets the device policy password mode. If the mode is non-specific, returns
278 * MODE_PATTERN which allows the user to choose anything.
Jim Miller31f90b62010-01-20 13:35:20 -0800279 */
Adrian Roos8150d2a2015-04-16 17:11:20 -0700280 public int getRequestedPasswordQuality(int userId) {
281 return getDevicePolicyManager().getPasswordQuality(null, userId);
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100282 }
283
284 private int getRequestedPasswordHistoryLength(int userId) {
285 return getDevicePolicyManager().getPasswordHistoryLength(null, userId);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700286 }
287
Adrian Roos8150d2a2015-04-16 17:11:20 -0700288 public int getRequestedPasswordMinimumLetters(int userId) {
289 return getDevicePolicyManager().getPasswordMinimumLetters(null, userId);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700290 }
291
Adrian Roos8150d2a2015-04-16 17:11:20 -0700292 public int getRequestedPasswordMinimumUpperCase(int userId) {
293 return getDevicePolicyManager().getPasswordMinimumUpperCase(null, userId);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700294 }
295
Adrian Roos8150d2a2015-04-16 17:11:20 -0700296 public int getRequestedPasswordMinimumLowerCase(int userId) {
297 return getDevicePolicyManager().getPasswordMinimumLowerCase(null, userId);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700298 }
299
Adrian Roos8150d2a2015-04-16 17:11:20 -0700300 public int getRequestedPasswordMinimumNumeric(int userId) {
301 return getDevicePolicyManager().getPasswordMinimumNumeric(null, userId);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700302 }
303
Adrian Roos8150d2a2015-04-16 17:11:20 -0700304 public int getRequestedPasswordMinimumSymbols(int userId) {
305 return getDevicePolicyManager().getPasswordMinimumSymbols(null, userId);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700306 }
307
Adrian Roos8150d2a2015-04-16 17:11:20 -0700308 public int getRequestedPasswordMinimumNonLetter(int userId) {
309 return getDevicePolicyManager().getPasswordMinimumNonLetter(null, userId);
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700310 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700311
Adrian Roos8150d2a2015-04-16 17:11:20 -0700312 public void reportFailedPasswordAttempt(int userId) {
Adrian Roos2adc2632017-09-05 17:01:42 +0200313 if (userId == USER_FRP && frpCredentialEnabled(mContext)) {
Adrian Roos7374d3a2017-03-31 14:14:53 -0700314 return;
315 }
Adrian Roos4f994eb2014-07-23 15:45:05 +0200316 getDevicePolicyManager().reportFailedPasswordAttempt(userId);
317 getTrustManager().reportUnlockAttempt(false /* authenticated */, userId);
Jim Miller31f90b62010-01-20 13:35:20 -0800318 }
319
Adrian Roos8150d2a2015-04-16 17:11:20 -0700320 public void reportSuccessfulPasswordAttempt(int userId) {
Adrian Roos2adc2632017-09-05 17:01:42 +0200321 if (userId == USER_FRP && frpCredentialEnabled(mContext)) {
Adrian Roos7374d3a2017-03-31 14:14:53 -0700322 return;
323 }
Adrian Roos8150d2a2015-04-16 17:11:20 -0700324 getDevicePolicyManager().reportSuccessfulPasswordAttempt(userId);
325 getTrustManager().reportUnlockAttempt(true /* authenticated */, userId);
Jim Miller31f90b62010-01-20 13:35:20 -0800326 }
327
Zachary Iqbal327323d2017-01-12 14:41:13 -0800328 public void reportPasswordLockout(int timeoutMs, int userId) {
Adrian Roos2adc2632017-09-05 17:01:42 +0200329 if (userId == USER_FRP && frpCredentialEnabled(mContext)) {
Adrian Roos7374d3a2017-03-31 14:14:53 -0700330 return;
331 }
Zachary Iqbal327323d2017-01-12 14:41:13 -0800332 getTrustManager().reportUnlockLockout(timeoutMs, userId);
333 }
334
Clara Bayarri51e41ad2016-02-11 17:48:53 +0000335 public int getCurrentFailedPasswordAttempts(int userId) {
Adrian Roos2adc2632017-09-05 17:01:42 +0200336 if (userId == USER_FRP && frpCredentialEnabled(mContext)) {
Adrian Roos7374d3a2017-03-31 14:14:53 -0700337 return 0;
338 }
Clara Bayarri51e41ad2016-02-11 17:48:53 +0000339 return getDevicePolicyManager().getCurrentFailedPasswordAttempts(userId);
340 }
341
342 public int getMaximumFailedPasswordsForWipe(int userId) {
Adrian Roos2adc2632017-09-05 17:01:42 +0200343 if (userId == USER_FRP && frpCredentialEnabled(mContext)) {
Adrian Roos7374d3a2017-03-31 14:14:53 -0700344 return 0;
345 }
Clara Bayarri51e41ad2016-02-11 17:48:53 +0000346 return getDevicePolicyManager().getMaximumFailedPasswordsForWipe(
347 null /* componentName */, userId);
348 }
349
Rubin Xu1de89b32016-11-30 20:03:13 +0000350 private byte[] verifyCredential(String credential, int type, long challenge, int userId)
351 throws RequestThrottledException {
352 try {
353 VerifyCredentialResponse response = getLockSettings().verifyCredential(credential,
354 type, challenge, userId);
355 if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
356 return response.getPayload();
357 } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {
358 throw new RequestThrottledException(response.getTimeout());
359 } else {
360 return null;
361 }
362 } catch (RemoteException re) {
363 return null;
364 }
365 }
366
367 private boolean checkCredential(String credential, int type, int userId,
368 @Nullable CheckCredentialProgressCallback progressCallback)
369 throws RequestThrottledException {
370 try {
371 VerifyCredentialResponse response = getLockSettings().checkCredential(credential, type,
372 userId, wrapCallback(progressCallback));
373
374 if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
375 return true;
376 } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {
377 throw new RequestThrottledException(response.getTimeout());
378 } else {
379 return false;
380 }
381 } catch (RemoteException re) {
382 return false;
383 }
384 }
385
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800386 /**
Andres Moralesd9fc85a2015-04-09 19:14:42 -0700387 * Check to see if a pattern matches the saved pattern.
388 * If pattern matches, return an opaque attestation that the challenge
389 * was verified.
390 *
391 * @param pattern The pattern to check.
392 * @param challenge The challenge to verify against the pattern
393 * @return the attestation that the challenge was verified, or null.
394 */
Andres Morales23974272015-05-14 22:42:26 -0700395 public byte[] verifyPattern(List<LockPatternView.Cell> pattern, long challenge, int userId)
396 throws RequestThrottledException {
Xiyuan Xiaaa262942015-05-05 15:18:45 -0700397 throwIfCalledOnMainThread();
Rubin Xu1de89b32016-11-30 20:03:13 +0000398 return verifyCredential(patternToString(pattern), CREDENTIAL_TYPE_PATTERN, challenge,
399 userId);
Andres Moralesd9fc85a2015-04-09 19:14:42 -0700400 }
401
402 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800403 * Check to see if a pattern matches the saved pattern. If no pattern exists,
404 * always returns true.
405 * @param pattern The pattern to check.
Jim Miller69aa4a92009-12-22 19:03:28 -0800406 * @return Whether the pattern matches the stored one.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800407 */
Andres Morales23974272015-05-14 22:42:26 -0700408 public boolean checkPattern(List<LockPatternView.Cell> pattern, int userId)
409 throws RequestThrottledException {
Jorim Jaggie8fde5d2016-06-30 23:41:37 -0700410 return checkPattern(pattern, userId, null /* progressCallback */);
411 }
412
413 /**
414 * Check to see if a pattern matches the saved pattern. If no pattern exists,
415 * always returns true.
416 * @param pattern The pattern to check.
417 * @return Whether the pattern matches the stored one.
418 */
419 public boolean checkPattern(List<LockPatternView.Cell> pattern, int userId,
420 @Nullable CheckCredentialProgressCallback progressCallback)
421 throws RequestThrottledException {
Xiyuan Xiaaa262942015-05-05 15:18:45 -0700422 throwIfCalledOnMainThread();
Rubin Xu1de89b32016-11-30 20:03:13 +0000423 return checkCredential(patternToString(pattern), CREDENTIAL_TYPE_PATTERN, userId,
424 progressCallback);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800425 }
426
427 /**
Andres Moralesd9fc85a2015-04-09 19:14:42 -0700428 * Check to see if a password matches the saved password.
429 * If password matches, return an opaque attestation that the challenge
430 * was verified.
431 *
432 * @param password The password to check.
433 * @param challenge The challenge to verify against the password
434 * @return the attestation that the challenge was verified, or null.
435 */
Andres Morales23974272015-05-14 22:42:26 -0700436 public byte[] verifyPassword(String password, long challenge, int userId)
437 throws RequestThrottledException {
Xiyuan Xiaaa262942015-05-05 15:18:45 -0700438 throwIfCalledOnMainThread();
Rubin Xu1de89b32016-11-30 20:03:13 +0000439 return verifyCredential(password, CREDENTIAL_TYPE_PASSWORD, challenge, userId);
Andres Moralesd9fc85a2015-04-09 19:14:42 -0700440 }
441
Ricky Wai53940d42016-04-05 15:29:24 +0100442
443 /**
444 * Check to see if a password matches the saved password.
445 * If password matches, return an opaque attestation that the challenge
446 * was verified.
447 *
448 * @param password The password to check.
449 * @param challenge The challenge to verify against the password
450 * @return the attestation that the challenge was verified, or null.
451 */
452 public byte[] verifyTiedProfileChallenge(String password, boolean isPattern, long challenge,
453 int userId) throws RequestThrottledException {
454 throwIfCalledOnMainThread();
455 try {
456 VerifyCredentialResponse response =
Rubin Xu1de89b32016-11-30 20:03:13 +0000457 getLockSettings().verifyTiedProfileChallenge(password,
458 isPattern ? CREDENTIAL_TYPE_PATTERN : CREDENTIAL_TYPE_PASSWORD, challenge,
Ricky Wai53940d42016-04-05 15:29:24 +0100459 userId);
460
461 if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
462 return response.getPayload();
463 } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {
464 throw new RequestThrottledException(response.getTimeout());
465 } else {
466 return null;
467 }
468 } catch (RemoteException re) {
469 return null;
470 }
471 }
472
Andres Moralesd9fc85a2015-04-09 19:14:42 -0700473 /**
Jim Miller69aa4a92009-12-22 19:03:28 -0800474 * Check to see if a password matches the saved password. If no password exists,
475 * always returns true.
476 * @param password The password to check.
477 * @return Whether the password matches the stored one.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800478 */
Andres Morales23974272015-05-14 22:42:26 -0700479 public boolean checkPassword(String password, int userId) throws RequestThrottledException {
Jorim Jaggie8fde5d2016-06-30 23:41:37 -0700480 return checkPassword(password, userId, null /* progressCallback */);
481 }
482
483 /**
484 * Check to see if a password matches the saved password. If no password exists,
485 * always returns true.
486 * @param password The password to check.
487 * @return Whether the password matches the stored one.
488 */
489 public boolean checkPassword(String password, int userId,
490 @Nullable CheckCredentialProgressCallback progressCallback)
491 throws RequestThrottledException {
Xiyuan Xiaaa262942015-05-05 15:18:45 -0700492 throwIfCalledOnMainThread();
Rubin Xu1de89b32016-11-30 20:03:13 +0000493 return checkCredential(password, CREDENTIAL_TYPE_PASSWORD, userId, progressCallback);
Jim Miller69aa4a92009-12-22 19:03:28 -0800494 }
495
496 /**
Paul Lawrence945490c2014-03-27 16:37:28 +0000497 * Check to see if vold already has the password.
498 * Note that this also clears vold's copy of the password.
499 * @return Whether the vold password matches or not.
500 */
Adrian Roos8150d2a2015-04-16 17:11:20 -0700501 public boolean checkVoldPassword(int userId) {
Paul Lawrence945490c2014-03-27 16:37:28 +0000502 try {
503 return getLockSettings().checkVoldPassword(userId);
504 } catch (RemoteException re) {
505 return false;
506 }
507 }
508
509 /**
Konstantin Lopyrev863f22d2010-05-12 17:16:58 -0700510 * Check to see if a password matches any of the passwords stored in the
511 * password history.
512 *
513 * @param password The password to check.
514 * @return Whether the password matches any in the history.
515 */
Adrian Roos8150d2a2015-04-16 17:11:20 -0700516 public boolean checkPasswordHistory(String password, int userId) {
Geoffrey Borggaard987672d22014-07-18 16:47:18 -0400517 String passwordHashString = new String(
Adrian Roosdce01222015-01-07 22:39:01 +0100518 passwordToHash(password, userId), StandardCharsets.UTF_8);
519 String passwordHistory = getString(PASSWORD_HISTORY_KEY, userId);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700520 if (passwordHistory == null) {
521 return false;
522 }
523 // Password History may be too long...
524 int passwordHashLength = passwordHashString.length();
Adrian Roos8150d2a2015-04-16 17:11:20 -0700525 int passwordHistoryLength = getRequestedPasswordHistoryLength(userId);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700526 if(passwordHistoryLength == 0) {
527 return false;
528 }
529 int neededPasswordHistoryLength = passwordHashLength * passwordHistoryLength
530 + passwordHistoryLength - 1;
531 if (passwordHistory.length() > neededPasswordHistoryLength) {
532 passwordHistory = passwordHistory.substring(0, neededPasswordHistoryLength);
533 }
534 return passwordHistory.contains(passwordHashString);
Konstantin Lopyrev863f22d2010-05-12 17:16:58 -0700535 }
536
537 /**
Jim Miller69aa4a92009-12-22 19:03:28 -0800538 * Check to see if the user has stored a lock pattern.
539 * @return Whether a saved pattern exists.
540 */
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100541 private boolean savedPatternExists(int userId) {
Amith Yamasani52c489c2012-03-28 11:42:42 -0700542 try {
Adrian Roos50bfeec2014-11-20 16:21:11 +0100543 return getLockSettings().havePattern(userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -0700544 } catch (RemoteException re) {
545 return false;
546 }
Jim Miller69aa4a92009-12-22 19:03:28 -0800547 }
548
549 /**
550 * Check to see if the user has stored a lock pattern.
551 * @return Whether a saved pattern exists.
552 */
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100553 private boolean savedPasswordExists(int userId) {
Amith Yamasani52c489c2012-03-28 11:42:42 -0700554 try {
Adrian Roos50bfeec2014-11-20 16:21:11 +0100555 return getLockSettings().havePassword(userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -0700556 } catch (RemoteException re) {
557 return false;
558 }
Jim Miller69aa4a92009-12-22 19:03:28 -0800559 }
560
561 /**
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -0700562 * Return true if the user has ever chosen a pattern. This is true even if the pattern is
563 * currently cleared.
564 *
565 * @return True if the user has ever chosen a pattern.
566 */
Adrian Roos8150d2a2015-04-16 17:11:20 -0700567 public boolean isPatternEverChosen(int userId) {
568 return getBoolean(PATTERN_EVER_CHOSEN_KEY, false, userId);
Adrian Roosdce01222015-01-07 22:39:01 +0100569 }
570
571 /**
Bryan Mawhinneye483b562017-05-15 14:46:05 +0100572 * Records that the user has chosen a pattern at some time, even if the pattern is
573 * currently cleared.
574 */
575 public void reportPatternWasChosen(int userId) {
576 setBoolean(PATTERN_EVER_CHOSEN_KEY, true, userId);
577 }
578
579 /**
Adrian Roosdce01222015-01-07 22:39:01 +0100580 * Used by device policy manager to validate the current password
581 * information it has.
582 */
583 public int getActivePasswordQuality(int userId) {
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100584 int quality = getKeyguardStoredPasswordQuality(userId);
Adrian Roosdce01222015-01-07 22:39:01 +0100585
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100586 if (isLockPasswordEnabled(quality, userId)) {
587 // Quality is a password and a password exists. Return the quality.
588 return quality;
589 }
590
591 if (isLockPatternEnabled(quality, userId)) {
592 // Quality is a pattern and a pattern exists. Return the quality.
593 return quality;
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700594 }
Danielle Millettc8fb5322011-10-04 12:18:51 -0400595
Rubin Xu682d1672018-03-21 09:13:44 +0000596 return PASSWORD_QUALITY_UNSPECIFIED;
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700597 }
Jim Millercd709882010-03-25 18:24:02 -0700598
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700599 /**
Ricky Wai4613fe42016-05-24 11:11:42 +0100600 * Use it to reset keystore without wiping work profile
601 */
602 public void resetKeyStore(int userId) {
603 try {
604 getLockSettings().resetKeyStore(userId);
605 } catch (RemoteException e) {
606 // It should not happen
607 Log.e(TAG, "Couldn't reset keystore " + e);
608 }
609 }
610
611 /**
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800612 * Clear any lock pattern or password.
613 */
Rubin Xua55b1682017-01-31 10:06:56 +0000614 public void clearLock(String savedCredential, int userHandle) {
Rubin Xu682d1672018-03-21 09:13:44 +0000615 final int currentQuality = getKeyguardStoredPasswordQuality(userHandle);
616 setKeyguardStoredPasswordQuality(PASSWORD_QUALITY_UNSPECIFIED, userHandle);
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100617
Rubin Xua55b1682017-01-31 10:06:56 +0000618 try{
619 getLockSettings().setLockCredential(null, CREDENTIAL_TYPE_NONE, savedCredential,
Rubin Xu682d1672018-03-21 09:13:44 +0000620 PASSWORD_QUALITY_UNSPECIFIED, userHandle);
621 } catch (Exception e) {
622 Log.e(TAG, "Failed to clear lock", e);
623 setKeyguardStoredPasswordQuality(currentQuality, userHandle);
624 return;
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100625 }
626
Xiaohui Chen86c69dd2015-08-27 15:44:02 -0700627 if (userHandle == UserHandle.USER_SYSTEM) {
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100628 // Set the encryption password to default.
629 updateEncryptionPassword(StorageManager.CRYPT_TYPE_DEFAULT, null);
Robin Leed39113e2016-01-22 15:44:49 +0000630 setCredentialRequiredToDecrypt(false);
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100631 }
632
Adrian Roosf8f56bc2014-11-20 23:55:34 +0100633 onAfterChangingPassword(userHandle);
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800634 }
Jim Miller5b0fb3a2010-02-23 13:46:35 -0800635
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800636 /**
Benjamin Franz51ed7942015-04-07 16:34:56 +0100637 * Disable showing lock screen at all for a given user.
638 * This is only meaningful if pattern, pin or password are not set.
Jim Miller2a98a4c2010-11-19 18:49:26 -0800639 *
Benjamin Franz51ed7942015-04-07 16:34:56 +0100640 * @param disable Disables lock screen when true
641 * @param userId User ID of the user this has effect on
642 */
643 public void setLockScreenDisabled(boolean disable, int userId) {
644 setBoolean(DISABLE_LOCKSCREEN_KEY, disable, userId);
645 }
646
647 /**
648 * Determine if LockScreen is disabled for the current user. This is used to decide whether
649 * LockScreen is shown after reboot or after screen timeout / short press on power.
650 *
651 * @return true if lock screen is disabled
Jim Miller2a98a4c2010-11-19 18:49:26 -0800652 */
Adrian Roos8150d2a2015-04-16 17:11:20 -0700653 public boolean isLockScreenDisabled(int userId) {
Evan Rosky2eff7452016-06-09 12:32:33 -0700654 if (isSecure(userId)) {
655 return false;
656 }
657 boolean disabledByDefault = mContext.getResources().getBoolean(
658 com.android.internal.R.bool.config_disableLockscreenByDefault);
659 boolean isSystemUser = UserManager.isSplitSystemUser() && userId == UserHandle.USER_SYSTEM;
Christine Franks5856be82017-06-23 18:12:46 -0700660 UserInfo userInfo = getUserManager().getUserInfo(userId);
661 boolean isDemoUser = UserManager.isDeviceInDemoMode(mContext) && userInfo != null
662 && userInfo.isDemo();
Evan Rosky2eff7452016-06-09 12:32:33 -0700663 return getBoolean(DISABLE_LOCKSCREEN_KEY, false, userId)
Christine Franks5856be82017-06-23 18:12:46 -0700664 || (disabledByDefault && !isSystemUser)
665 || isDemoUser;
Jim Miller2a98a4c2010-11-19 18:49:26 -0800666 }
667
668 /**
Jim Miller6edf2632011-09-05 16:03:14 -0700669 * Save a lock pattern.
670 * @param pattern The new pattern to save.
Adrian Roos8150d2a2015-04-16 17:11:20 -0700671 * @param userId the user whose pattern is to be saved.
Danielle Millett2364a222011-12-21 17:02:32 -0500672 */
Andres Morales8fa56652015-03-31 09:19:50 -0700673 public void saveLockPattern(List<LockPatternView.Cell> pattern, int userId) {
674 this.saveLockPattern(pattern, null, userId);
675 }
Danielle Millett2364a222011-12-21 17:02:32 -0500676 /**
677 * Save a lock pattern.
678 * @param pattern The new pattern to save.
Andres Morales8fa56652015-03-31 09:19:50 -0700679 * @param savedPattern The previously saved pattern, converted to String format
Adrian Roosf8f56bc2014-11-20 23:55:34 +0100680 * @param userId the user whose pattern is to be saved.
681 */
Andres Morales8fa56652015-03-31 09:19:50 -0700682 public void saveLockPattern(List<LockPatternView.Cell> pattern, String savedPattern, int userId) {
Rubin Xu682d1672018-03-21 09:13:44 +0000683 if (pattern == null || pattern.size() < MIN_LOCK_PATTERN_SIZE) {
684 throw new IllegalArgumentException("pattern must not be null and at least "
685 + MIN_LOCK_PATTERN_SIZE + " dots long.");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800686 }
Rubin Xu682d1672018-03-21 09:13:44 +0000687
688 final String stringPattern = patternToString(pattern);
689 final int currentQuality = getKeyguardStoredPasswordQuality(userId);
690 setKeyguardStoredPasswordQuality(PASSWORD_QUALITY_SOMETHING, userId);
691 try {
692 getLockSettings().setLockCredential(stringPattern, CREDENTIAL_TYPE_PATTERN,
693 savedPattern, PASSWORD_QUALITY_SOMETHING, userId);
694 } catch (Exception e) {
695 Log.e(TAG, "Couldn't save lock pattern", e);
696 setKeyguardStoredPasswordQuality(currentQuality, userId);
697 return;
698 }
699 // Update the device encryption password.
700 if (userId == UserHandle.USER_SYSTEM
701 && LockPatternUtils.isDeviceEncryptionEnabled()) {
702 if (!shouldEncryptWithCredentials(true)) {
703 clearEncryptionPassword();
704 } else {
705 updateEncryptionPassword(StorageManager.CRYPT_TYPE_PATTERN, stringPattern);
706 }
707 }
708
709 reportPatternWasChosen(userId);
710 onAfterChangingPassword(userId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800711 }
712
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100713 private void updateCryptoUserInfo(int userId) {
Xiaohui Chen86c69dd2015-08-27 15:44:02 -0700714 if (userId != UserHandle.USER_SYSTEM) {
Paul Lawrencee51dcf92014-03-18 10:56:00 -0700715 return;
716 }
717
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100718 final String ownerInfo = isOwnerInfoEnabled(userId) ? getOwnerInfo(userId) : "";
Paul Lawrencee51dcf92014-03-18 10:56:00 -0700719
720 IBinder service = ServiceManager.getService("mount");
721 if (service == null) {
722 Log.e(TAG, "Could not find the mount service to update the user info");
723 return;
724 }
725
Sudheer Shanka2250d562016-11-07 15:41:02 -0800726 IStorageManager storageManager = IStorageManager.Stub.asInterface(service);
Paul Lawrencee51dcf92014-03-18 10:56:00 -0700727 try {
728 Log.d(TAG, "Setting owner info");
Sudheer Shanka2250d562016-11-07 15:41:02 -0800729 storageManager.setField(StorageManager.OWNER_INFO_KEY, ownerInfo);
Paul Lawrencee51dcf92014-03-18 10:56:00 -0700730 } catch (RemoteException e) {
731 Log.e(TAG, "Error changing user info", e);
732 }
733 }
734
Jim Miller187ec582013-04-15 18:27:54 -0700735 public void setOwnerInfo(String info, int userId) {
736 setString(LOCK_SCREEN_OWNER_INFO, info, userId);
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100737 updateCryptoUserInfo(userId);
Jim Miller187ec582013-04-15 18:27:54 -0700738 }
739
Adrian Roos8150d2a2015-04-16 17:11:20 -0700740 public void setOwnerInfoEnabled(boolean enabled, int userId) {
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100741 setBoolean(LOCK_SCREEN_OWNER_INFO_ENABLED, enabled, userId);
742 updateCryptoUserInfo(userId);
Jim Miller187ec582013-04-15 18:27:54 -0700743 }
744
745 public String getOwnerInfo(int userId) {
Adrian Roosdce01222015-01-07 22:39:01 +0100746 return getString(LOCK_SCREEN_OWNER_INFO, userId);
Jim Miller187ec582013-04-15 18:27:54 -0700747 }
748
Adrian Roos8150d2a2015-04-16 17:11:20 -0700749 public boolean isOwnerInfoEnabled(int userId) {
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100750 return getBoolean(LOCK_SCREEN_OWNER_INFO_ENABLED, false, userId);
Jim Miller187ec582013-04-15 18:27:54 -0700751 }
752
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800753 /**
Andrei Stingaceanu6644cd92015-11-10 13:03:31 +0000754 * Sets the device owner information. If the information is {@code null} or empty then the
755 * device owner info is cleared.
756 *
757 * @param info Device owner information which will be displayed instead of the user
758 * owner info.
759 */
760 public void setDeviceOwnerInfo(String info) {
761 if (info != null && info.isEmpty()) {
762 info = null;
763 }
764
765 setString(LOCK_SCREEN_DEVICE_OWNER_INFO, info, UserHandle.USER_SYSTEM);
766 }
767
768 public String getDeviceOwnerInfo() {
769 return getString(LOCK_SCREEN_DEVICE_OWNER_INFO, UserHandle.USER_SYSTEM);
770 }
771
772 public boolean isDeviceOwnerInfoEnabled() {
773 return getDeviceOwnerInfo() != null;
774 }
775
Jason parksf7b3cd42011-01-27 09:28:25 -0600776 /** Update the encryption password if it is enabled **/
Paul Lawrence3a5a0be2014-09-25 09:26:34 -0700777 private void updateEncryptionPassword(final int type, final String password) {
Amith Yamasanicd410ba2014-10-17 11:16:58 -0700778 if (!isDeviceEncryptionEnabled()) {
Jason parksf7b3cd42011-01-27 09:28:25 -0600779 return;
780 }
Paul Lawrence3a5a0be2014-09-25 09:26:34 -0700781 final IBinder service = ServiceManager.getService("mount");
Jason parksf7b3cd42011-01-27 09:28:25 -0600782 if (service == null) {
783 Log.e(TAG, "Could not find the mount service to update the encryption password");
784 return;
785 }
786
Paul Lawrence3a5a0be2014-09-25 09:26:34 -0700787 new AsyncTask<Void, Void, Void>() {
788 @Override
789 protected Void doInBackground(Void... dummy) {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800790 IStorageManager storageManager = IStorageManager.Stub.asInterface(service);
Paul Lawrence3a5a0be2014-09-25 09:26:34 -0700791 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800792 storageManager.changeEncryptionPassword(type, password);
Paul Lawrence3a5a0be2014-09-25 09:26:34 -0700793 } catch (RemoteException e) {
794 Log.e(TAG, "Error changing encryption password", e);
795 }
796 return null;
797 }
798 }.execute();
Jason parksf7b3cd42011-01-27 09:28:25 -0600799 }
800
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800801 /**
Jim Millercd709882010-03-25 18:24:02 -0700802 * Save a lock password. Does not ensure that the password is as good
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800803 * as the requested mode, but will adjust the mode to be as good as the
Adrian Roos8150d2a2015-04-16 17:11:20 -0700804 * password.
Jim Miller69aa4a92009-12-22 19:03:28 -0800805 * @param password The password to save
Andres Morales8fa56652015-03-31 09:19:50 -0700806 * @param savedPassword The previously saved lock password, or null if none
Adrian Roos7374d3a2017-03-31 14:14:53 -0700807 * @param requestedQuality {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700808 * @param userHandle The userId of the user to change the password for
809 */
Adrian Roos7374d3a2017-03-31 14:14:53 -0700810 public void saveLockPassword(String password, String savedPassword, int requestedQuality,
Andres Morales8fa56652015-03-31 09:19:50 -0700811 int userHandle) {
Rubin Xu682d1672018-03-21 09:13:44 +0000812 if (password == null || password.length() < MIN_LOCK_PASSWORD_SIZE) {
813 throw new IllegalArgumentException("password must not be null and at least "
814 + "of length " + MIN_LOCK_PASSWORD_SIZE);
Jim Miller69aa4a92009-12-22 19:03:28 -0800815 }
Rubin Xu682d1672018-03-21 09:13:44 +0000816
817 final int currentQuality = getKeyguardStoredPasswordQuality(userHandle);
818 setKeyguardStoredPasswordQuality(
819 computePasswordQuality(CREDENTIAL_TYPE_PASSWORD, password, requestedQuality),
820 userHandle);
821 try {
822 getLockSettings().setLockCredential(password, CREDENTIAL_TYPE_PASSWORD,
823 savedPassword, requestedQuality, userHandle);
824 } catch (Exception e) {
825 Log.e(TAG, "Unable to save lock password", e);
826 setKeyguardStoredPasswordQuality(currentQuality, userHandle);
827 return;
828 }
829
830 updateEncryptionPasswordIfNeeded(password,
831 PasswordMetrics.computeForPassword(password).quality, userHandle);
832 updatePasswordHistory(password, userHandle);
Jim Miller69aa4a92009-12-22 19:03:28 -0800833 }
834
Rubin Xuf095f832017-01-31 15:23:34 +0000835 /**
836 * Update device encryption password if calling user is USER_SYSTEM and device supports
837 * encryption.
838 */
839 private void updateEncryptionPasswordIfNeeded(String password, int quality, int userHandle) {
Rubin Xua55b1682017-01-31 10:06:56 +0000840 // Update the device encryption password.
841 if (userHandle == UserHandle.USER_SYSTEM
842 && LockPatternUtils.isDeviceEncryptionEnabled()) {
843 if (!shouldEncryptWithCredentials(true)) {
844 clearEncryptionPassword();
845 } else {
Rubin Xu682d1672018-03-21 09:13:44 +0000846 boolean numeric = quality == PASSWORD_QUALITY_NUMERIC;
847 boolean numericComplex = quality == PASSWORD_QUALITY_NUMERIC_COMPLEX;
Rubin Xua55b1682017-01-31 10:06:56 +0000848 int type = numeric || numericComplex ? StorageManager.CRYPT_TYPE_PIN
849 : StorageManager.CRYPT_TYPE_PASSWORD;
850 updateEncryptionPassword(type, password);
851 }
852 }
853 }
854
855 private void updatePasswordHistory(String password, int userHandle) {
856
857 // Add the password to the password history. We assume all
858 // password hashes have the same length for simplicity of implementation.
859 String passwordHistory = getString(PASSWORD_HISTORY_KEY, userHandle);
860 if (passwordHistory == null) {
861 passwordHistory = "";
862 }
863 int passwordHistoryLength = getRequestedPasswordHistoryLength(userHandle);
864 if (passwordHistoryLength == 0) {
865 passwordHistory = "";
866 } else {
867 byte[] hash = passwordToHash(password, userHandle);
868 passwordHistory = new String(hash, StandardCharsets.UTF_8) + "," + passwordHistory;
869 // Cut it to contain passwordHistoryLength hashes
870 // and passwordHistoryLength -1 commas.
871 passwordHistory = passwordHistory.substring(0, Math.min(hash.length
872 * passwordHistoryLength + passwordHistoryLength - 1, passwordHistory
873 .length()));
874 }
875 setString(PASSWORD_HISTORY_KEY, passwordHistory, userHandle);
876 onAfterChangingPassword(userHandle);
877 }
878
Jim Millercd709882010-03-25 18:24:02 -0700879 /**
Jim Miller6848dc82014-10-13 18:51:53 -0700880 * Determine if the device supports encryption, even if it's set to default. This
881 * differs from isDeviceEncrypted() in that it returns true even if the device is
882 * encrypted with the default password.
883 * @return true if device encryption is enabled
884 */
885 public static boolean isDeviceEncryptionEnabled() {
Paul Lawrence20be5d62016-02-26 13:51:17 -0800886 return StorageManager.isEncrypted();
Jim Miller6848dc82014-10-13 18:51:53 -0700887 }
888
889 /**
Paul Lawrence5c21c702016-01-29 13:26:19 -0800890 * Determine if the device is file encrypted
891 * @return true if device is file encrypted
892 */
893 public static boolean isFileEncryptionEnabled() {
Paul Lawrence20be5d62016-02-26 13:51:17 -0800894 return StorageManager.isFileEncryptedNativeOrEmulated();
Paul Lawrence5c21c702016-01-29 13:26:19 -0800895 }
896
897 /**
Svetoslav16e4a1a2014-09-29 18:16:20 -0700898 * Clears the encryption password.
899 */
900 public void clearEncryptionPassword() {
901 updateEncryptionPassword(StorageManager.CRYPT_TYPE_DEFAULT, null);
902 }
903
904 /**
Adrian Roos1572ee32014-09-01 16:24:32 +0200905 * Retrieves the quality mode for {@param userHandle}.
906 * {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
907 *
908 * @return stored password quality
909 */
910 public int getKeyguardStoredPasswordQuality(int userHandle) {
Rubin Xu682d1672018-03-21 09:13:44 +0000911 return (int) getLong(PASSWORD_TYPE_KEY, PASSWORD_QUALITY_UNSPECIFIED, userHandle);
912 }
913
914 private void setKeyguardStoredPasswordQuality(int quality, int userHandle) {
915 setLong(PASSWORD_TYPE_KEY, quality, userHandle);
Jim Miller6edf2632011-09-05 16:03:14 -0700916 }
917
Danielle Millett58396982011-09-30 13:55:07 -0400918 /**
Rubin Xu7cf45092017-08-28 11:47:35 +0100919 * Returns the password quality of the given credential, promoting it to a higher level
920 * if DevicePolicyManager has a stronger quality requirement. This value will be written
921 * to PASSWORD_TYPE_KEY.
922 */
923 private int computePasswordQuality(int type, String credential, int requestedQuality) {
924 final int quality;
925 if (type == CREDENTIAL_TYPE_PASSWORD) {
926 int computedQuality = PasswordMetrics.computeForPassword(credential).quality;
927 quality = Math.max(requestedQuality, computedQuality);
928 } else if (type == CREDENTIAL_TYPE_PATTERN) {
Rubin Xu682d1672018-03-21 09:13:44 +0000929 quality = PASSWORD_QUALITY_SOMETHING;
Rubin Xu7cf45092017-08-28 11:47:35 +0100930 } else /* if (type == CREDENTIAL_TYPE_NONE) */ {
Rubin Xu682d1672018-03-21 09:13:44 +0000931 quality = PASSWORD_QUALITY_UNSPECIFIED;
Rubin Xu7cf45092017-08-28 11:47:35 +0100932 }
933 return quality;
934 }
935
936 /**
Clara Bayarria1771112015-12-18 16:29:18 +0000937 * Enables/disables the Separate Profile Challenge for this {@param userHandle}. This is a no-op
938 * for user handles that do not belong to a managed profile.
Ricky Waidc283a82016-03-24 19:55:08 +0000939 *
940 * @param userHandle Managed profile user id
941 * @param enabled True if separate challenge is enabled
942 * @param managedUserPassword Managed profile previous password. Null when {@param enabled} is
943 * true
Clara Bayarria1771112015-12-18 16:29:18 +0000944 */
Ricky Waidc283a82016-03-24 19:55:08 +0000945 public void setSeparateProfileChallengeEnabled(int userHandle, boolean enabled,
946 String managedUserPassword) {
Pavel Grafovb3191252017-07-14 12:30:31 +0100947 if (!isManagedProfile(userHandle)) {
948 return;
949 }
950 try {
951 getLockSettings().setSeparateProfileChallengeEnabled(userHandle, enabled,
952 managedUserPassword);
953 onAfterChangingPassword(userHandle);
954 } catch (RemoteException e) {
955 Log.e(TAG, "Couldn't update work profile challenge enabled");
Clara Bayarria1771112015-12-18 16:29:18 +0000956 }
957 }
958
959 /**
Pavel Grafovb3191252017-07-14 12:30:31 +0100960 * Returns true if {@param userHandle} is a managed profile with separate challenge.
Clara Bayarria1771112015-12-18 16:29:18 +0000961 */
962 public boolean isSeparateProfileChallengeEnabled(int userHandle) {
Pavel Grafovb3191252017-07-14 12:30:31 +0100963 return isManagedProfile(userHandle) && hasSeparateChallenge(userHandle);
964 }
965
966 /**
967 * Returns true if {@param userHandle} is a managed profile with unified challenge.
968 */
969 public boolean isManagedProfileWithUnifiedChallenge(int userHandle) {
970 return isManagedProfile(userHandle) && !hasSeparateChallenge(userHandle);
971 }
972
973 /**
974 * Retrieves whether the current DPM allows use of the Profile Challenge.
975 */
976 public boolean isSeparateProfileChallengeAllowed(int userHandle) {
977 return isManagedProfile(userHandle)
978 && getDevicePolicyManager().isSeparateProfileChallengeAllowed(userHandle);
979 }
980
981 /**
982 * Retrieves whether the current profile and device locks can be unified.
Pavel Grafovc4f87e92017-10-26 16:34:25 +0100983 * @param userHandle profile user handle.
Pavel Grafovb3191252017-07-14 12:30:31 +0100984 */
985 public boolean isSeparateProfileChallengeAllowedToUnify(int userHandle) {
Pavel Grafovc4f87e92017-10-26 16:34:25 +0100986 return getDevicePolicyManager().isProfileActivePasswordSufficientForParent(userHandle)
987 && !getUserManager().hasUserRestriction(
988 UserManager.DISALLOW_UNIFIED_PASSWORD, UserHandle.of(userHandle));
Pavel Grafovb3191252017-07-14 12:30:31 +0100989 }
990
991 private boolean hasSeparateChallenge(int userHandle) {
Ricky Waidc283a82016-03-24 19:55:08 +0000992 try {
993 return getLockSettings().getSeparateProfileChallengeEnabled(userHandle);
994 } catch (RemoteException e) {
995 Log.e(TAG, "Couldn't get separate profile challenge enabled");
996 // Default value is false
997 return false;
998 }
Clara Bayarria1771112015-12-18 16:29:18 +0000999 }
1000
Pavel Grafovb3191252017-07-14 12:30:31 +01001001 private boolean isManagedProfile(int userHandle) {
1002 final UserInfo info = getUserManager().getUserInfo(userHandle);
1003 return info != null && info.isManagedProfile();
Clara Bayarrid7693912016-01-22 17:26:31 +00001004 }
1005
1006 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001007 * Deserialize a pattern.
1008 * @param string The pattern serialized with {@link #patternToString}
1009 * @return The pattern.
1010 */
1011 public static List<LockPatternView.Cell> stringToPattern(String string) {
Adrian Roos9dd16eb2015-01-08 16:20:49 +01001012 if (string == null) {
1013 return null;
1014 }
1015
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001016 List<LockPatternView.Cell> result = Lists.newArrayList();
1017
1018 final byte[] bytes = string.getBytes();
1019 for (int i = 0; i < bytes.length; i++) {
Andres Moralese40bad82015-05-28 14:21:36 -07001020 byte b = (byte) (bytes[i] - '1');
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001021 result.add(LockPatternView.Cell.of(b / 3, b % 3));
1022 }
1023 return result;
1024 }
1025
1026 /**
1027 * Serialize a pattern.
1028 * @param pattern The pattern.
1029 * @return The pattern in string form.
1030 */
1031 public static String patternToString(List<LockPatternView.Cell> pattern) {
1032 if (pattern == null) {
1033 return "";
1034 }
1035 final int patternSize = pattern.size();
1036
1037 byte[] res = new byte[patternSize];
1038 for (int i = 0; i < patternSize; i++) {
1039 LockPatternView.Cell cell = pattern.get(i);
Andres Moralese40bad82015-05-28 14:21:36 -07001040 res[i] = (byte) (cell.getRow() * 3 + cell.getColumn() + '1');
1041 }
1042 return new String(res);
1043 }
1044
1045 public static String patternStringToBaseZero(String pattern) {
1046 if (pattern == null) {
1047 return "";
1048 }
1049 final int patternSize = pattern.length();
1050
1051 byte[] res = new byte[patternSize];
1052 final byte[] bytes = pattern.getBytes();
1053 for (int i = 0; i < patternSize; i++) {
1054 res[i] = (byte) (bytes[i] - '1');
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001055 }
1056 return new String(res);
1057 }
Jim Miller69aa4a92009-12-22 19:03:28 -08001058
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001059 /*
1060 * Generate an SHA-1 hash for the pattern. Not the most secure, but it is
1061 * at least a second level of protection. First level is that the file
1062 * is in a location only readable by the system process.
1063 * @param pattern the gesture pattern.
1064 * @return the hash of the pattern in a byte array.
1065 */
Jim Millerde1af082013-09-11 14:58:26 -07001066 public static byte[] patternToHash(List<LockPatternView.Cell> pattern) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001067 if (pattern == null) {
1068 return null;
1069 }
Jim Miller69aa4a92009-12-22 19:03:28 -08001070
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001071 final int patternSize = pattern.size();
1072 byte[] res = new byte[patternSize];
1073 for (int i = 0; i < patternSize; i++) {
1074 LockPatternView.Cell cell = pattern.get(i);
1075 res[i] = (byte) (cell.getRow() * 3 + cell.getColumn());
1076 }
1077 try {
1078 MessageDigest md = MessageDigest.getInstance("SHA-1");
1079 byte[] hash = md.digest(res);
1080 return hash;
1081 } catch (NoSuchAlgorithmException nsa) {
1082 return res;
1083 }
1084 }
1085
Geoffrey Borggaard987672d22014-07-18 16:47:18 -04001086 private String getSalt(int userId) {
1087 long salt = getLong(LOCK_PASSWORD_SALT_KEY, 0, userId);
Jim Miller11b019d2010-01-20 16:34:45 -08001088 if (salt == 0) {
1089 try {
1090 salt = SecureRandom.getInstance("SHA1PRNG").nextLong();
Geoffrey Borggaard987672d22014-07-18 16:47:18 -04001091 setLong(LOCK_PASSWORD_SALT_KEY, salt, userId);
1092 Log.v(TAG, "Initialized lock password salt for user: " + userId);
Jim Miller11b019d2010-01-20 16:34:45 -08001093 } catch (NoSuchAlgorithmException e) {
1094 // Throw an exception rather than storing a password we'll never be able to recover
1095 throw new IllegalStateException("Couldn't get SecureRandom number", e);
1096 }
1097 }
1098 return Long.toHexString(salt);
1099 }
1100
Jim Miller69aa4a92009-12-22 19:03:28 -08001101 /*
1102 * Generate a hash for the given password. To avoid brute force attacks, we use a salted hash.
1103 * Not the most secure, but it is at least a second level of protection. First level is that
1104 * the file is in a location only readable by the system process.
Narayan Kamath78108a32014-12-16 12:56:23 +00001105 *
Jim Miller69aa4a92009-12-22 19:03:28 -08001106 * @param password the gesture pattern.
Narayan Kamath78108a32014-12-16 12:56:23 +00001107 *
Jim Miller69aa4a92009-12-22 19:03:28 -08001108 * @return the hash of the pattern in a byte array.
1109 */
Geoffrey Borggaard987672d22014-07-18 16:47:18 -04001110 public byte[] passwordToHash(String password, int userId) {
Jim Miller69aa4a92009-12-22 19:03:28 -08001111 if (password == null) {
1112 return null;
1113 }
Narayan Kamath78108a32014-12-16 12:56:23 +00001114
Jim Miller69aa4a92009-12-22 19:03:28 -08001115 try {
Geoffrey Borggaard987672d22014-07-18 16:47:18 -04001116 byte[] saltedPassword = (password + getSalt(userId)).getBytes();
Narayan Kamath78108a32014-12-16 12:56:23 +00001117 byte[] sha1 = MessageDigest.getInstance("SHA-1").digest(saltedPassword);
1118 byte[] md5 = MessageDigest.getInstance("MD5").digest(saltedPassword);
Jim Miller69aa4a92009-12-22 19:03:28 -08001119
Narayan Kamath78108a32014-12-16 12:56:23 +00001120 byte[] combined = new byte[sha1.length + md5.length];
1121 System.arraycopy(sha1, 0, combined, 0, sha1.length);
1122 System.arraycopy(md5, 0, combined, sha1.length, md5.length);
1123
1124 final char[] hexEncoded = HexEncoding.encode(combined);
1125 return new String(hexEncoded).getBytes(StandardCharsets.UTF_8);
1126 } catch (NoSuchAlgorithmException e) {
1127 throw new AssertionError("Missing digest algorithm: ", e);
Jim Miller69aa4a92009-12-22 19:03:28 -08001128 }
Jim Miller69aa4a92009-12-22 19:03:28 -08001129 }
1130
1131 /**
Adrian Roos9dd16eb2015-01-08 16:20:49 +01001132 * @param userId the user for which to report the value
1133 * @return Whether the lock screen is secured.
1134 */
1135 public boolean isSecure(int userId) {
1136 int mode = getKeyguardStoredPasswordQuality(userId);
1137 return isLockPatternEnabled(mode, userId) || isLockPasswordEnabled(mode, userId);
1138 }
1139
Adrian Roosdce01222015-01-07 22:39:01 +01001140 public boolean isLockPasswordEnabled(int userId) {
Adrian Roos9dd16eb2015-01-08 16:20:49 +01001141 return isLockPasswordEnabled(getKeyguardStoredPasswordQuality(userId), userId);
1142 }
1143
1144 private boolean isLockPasswordEnabled(int mode, int userId) {
Rubin Xu682d1672018-03-21 09:13:44 +00001145 final boolean passwordEnabled = mode == PASSWORD_QUALITY_ALPHABETIC
1146 || mode == PASSWORD_QUALITY_NUMERIC
1147 || mode == PASSWORD_QUALITY_NUMERIC_COMPLEX
1148 || mode == PASSWORD_QUALITY_ALPHANUMERIC
1149 || mode == PASSWORD_QUALITY_COMPLEX
1150 || mode == PASSWORD_QUALITY_MANAGED;
Adrian Roos9dd16eb2015-01-08 16:20:49 +01001151 return passwordEnabled && savedPasswordExists(userId);
Jim Miller69aa4a92009-12-22 19:03:28 -08001152 }
1153
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001154 /**
Adrian Roos230635e2015-01-07 20:50:29 +01001155 * @return Whether the lock pattern is enabled
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001156 */
Adrian Roos50bfeec2014-11-20 16:21:11 +01001157 public boolean isLockPatternEnabled(int userId) {
Adrian Roos9dd16eb2015-01-08 16:20:49 +01001158 return isLockPatternEnabled(getKeyguardStoredPasswordQuality(userId), userId);
Danielle Millett925a7d82012-03-19 18:02:20 -04001159 }
1160
Bryce Lee46145962015-12-14 14:39:10 -08001161 @Deprecated
1162 public boolean isLegacyLockPatternEnabled(int userId) {
1163 // Note: this value should default to {@code true} to avoid any reset that might result.
1164 // We must use a special key to read this value, since it will by default return the value
1165 // based on the new logic.
1166 return getBoolean(LEGACY_LOCK_PATTERN_ENABLED, true, userId);
1167 }
1168
1169 @Deprecated
1170 public void setLegacyLockPatternEnabled(int userId) {
1171 setBoolean(Settings.Secure.LOCK_PATTERN_ENABLED, true, userId);
1172 }
1173
Adrian Roos9dd16eb2015-01-08 16:20:49 +01001174 private boolean isLockPatternEnabled(int mode, int userId) {
Rubin Xu682d1672018-03-21 09:13:44 +00001175 return mode == PASSWORD_QUALITY_SOMETHING && savedPatternExists(userId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001176 }
1177
1178 /**
1179 * @return Whether the visible pattern is enabled.
1180 */
Adrian Roos8150d2a2015-04-16 17:11:20 -07001181 public boolean isVisiblePatternEnabled(int userId) {
1182 return getBoolean(Settings.Secure.LOCK_PATTERN_VISIBLE, false, userId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001183 }
1184
1185 /**
1186 * Set whether the visible pattern is enabled.
1187 */
Adrian Roos8150d2a2015-04-16 17:11:20 -07001188 public void setVisiblePatternEnabled(boolean enabled, int userId) {
Adrian Roosdce01222015-01-07 22:39:01 +01001189 setBoolean(Settings.Secure.LOCK_PATTERN_VISIBLE, enabled, userId);
Paul Lawrence878ba0a2014-08-20 13:08:01 -07001190
1191 // Update for crypto if owner
Xiaohui Chen86c69dd2015-08-27 15:44:02 -07001192 if (userId != UserHandle.USER_SYSTEM) {
Paul Lawrence878ba0a2014-08-20 13:08:01 -07001193 return;
1194 }
1195
1196 IBinder service = ServiceManager.getService("mount");
1197 if (service == null) {
1198 Log.e(TAG, "Could not find the mount service to update the user info");
1199 return;
1200 }
1201
Sudheer Shanka2250d562016-11-07 15:41:02 -08001202 IStorageManager storageManager = IStorageManager.Stub.asInterface(service);
Paul Lawrence878ba0a2014-08-20 13:08:01 -07001203 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -08001204 storageManager.setField(StorageManager.PATTERN_VISIBLE_KEY, enabled ? "1" : "0");
Paul Lawrence878ba0a2014-08-20 13:08:01 -07001205 } catch (RemoteException e) {
1206 Log.e(TAG, "Error changing pattern visible state", e);
1207 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001208 }
1209
Bryan Mawhinneye483b562017-05-15 14:46:05 +01001210 public boolean isVisiblePatternEverChosen(int userId) {
1211 return getString(Settings.Secure.LOCK_PATTERN_VISIBLE, userId) != null;
1212 }
1213
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001214 /**
Paul Lawrenced8fdb332015-05-18 13:26:11 -07001215 * Set whether the visible password is enabled for cryptkeeper screen.
1216 */
1217 public void setVisiblePasswordEnabled(boolean enabled, int userId) {
1218 // Update for crypto if owner
Xiaohui Chen86c69dd2015-08-27 15:44:02 -07001219 if (userId != UserHandle.USER_SYSTEM) {
Paul Lawrenced8fdb332015-05-18 13:26:11 -07001220 return;
1221 }
1222
1223 IBinder service = ServiceManager.getService("mount");
1224 if (service == null) {
1225 Log.e(TAG, "Could not find the mount service to update the user info");
1226 return;
1227 }
1228
Sudheer Shanka2250d562016-11-07 15:41:02 -08001229 IStorageManager storageManager = IStorageManager.Stub.asInterface(service);
Paul Lawrenced8fdb332015-05-18 13:26:11 -07001230 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -08001231 storageManager.setField(StorageManager.PASSWORD_VISIBLE_KEY, enabled ? "1" : "0");
Paul Lawrenced8fdb332015-05-18 13:26:11 -07001232 } catch (RemoteException e) {
1233 Log.e(TAG, "Error changing password visible state", e);
1234 }
1235 }
1236
1237 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001238 * @return Whether tactile feedback for the pattern is enabled.
1239 */
1240 public boolean isTactileFeedbackEnabled() {
Jeff Sharkey5ed9d682012-10-10 14:28:27 -07001241 return Settings.System.getIntForUser(mContentResolver,
1242 Settings.System.HAPTIC_FEEDBACK_ENABLED, 1, UserHandle.USER_CURRENT) != 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001243 }
1244
1245 /**
1246 * Set and store the lockout deadline, meaning the user can't attempt his/her unlock
1247 * pattern until the deadline has passed.
1248 * @return the chosen deadline.
1249 */
Andres Morales23974272015-05-14 22:42:26 -07001250 public long setLockoutAttemptDeadline(int userId, int timeoutMs) {
1251 final long deadline = SystemClock.elapsedRealtime() + timeoutMs;
Adrian Roosb7d81d92017-08-08 13:08:01 +02001252 if (userId == USER_FRP) {
1253 // For secure password storage (that is required for FRP), the underlying storage also
1254 // enforces the deadline. Since we cannot store settings for the FRP user, don't.
1255 return deadline;
1256 }
Kevin Chyna3e55822017-10-04 15:47:24 -07001257 mLockoutDeadlines.put(userId, deadline);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001258 return deadline;
1259 }
1260
1261 /**
1262 * @return The elapsed time in millis in the future when the user is allowed to
1263 * attempt to enter his/her lock pattern, or 0 if the user is welcome to
1264 * enter a pattern.
1265 */
Adrian Roos8150d2a2015-04-16 17:11:20 -07001266 public long getLockoutAttemptDeadline(int userId) {
Kevin Chyna3e55822017-10-04 15:47:24 -07001267 final long deadline = mLockoutDeadlines.get(userId, 0L);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001268 final long now = SystemClock.elapsedRealtime();
Jorim Jaggie3e6d562015-09-28 13:57:37 -07001269 if (deadline < now && deadline != 0) {
Andres Moralesa4e23372015-09-08 13:17:37 -07001270 // timeout expired
Kevin Chyna3e55822017-10-04 15:47:24 -07001271 mLockoutDeadlines.put(userId, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001272 return 0L;
1273 }
1274 return deadline;
1275 }
1276
Jim Millerf45bb402013-08-20 18:58:32 -07001277 private boolean getBoolean(String secureSettingKey, boolean defaultValue, int userId) {
Amith Yamasani52c489c2012-03-28 11:42:42 -07001278 try {
Jim Millerf45bb402013-08-20 18:58:32 -07001279 return getLockSettings().getBoolean(secureSettingKey, defaultValue, userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -07001280 } catch (RemoteException re) {
1281 return defaultValue;
1282 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001283 }
1284
Jim Millerf45bb402013-08-20 18:58:32 -07001285 private void setBoolean(String secureSettingKey, boolean enabled, int userId) {
Amith Yamasani52c489c2012-03-28 11:42:42 -07001286 try {
Jim Millerf45bb402013-08-20 18:58:32 -07001287 getLockSettings().setBoolean(secureSettingKey, enabled, userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -07001288 } catch (RemoteException re) {
1289 // What can we do?
1290 Log.e(TAG, "Couldn't write boolean " + secureSettingKey + re);
1291 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001292 }
1293
Geoffrey Borggaard987672d22014-07-18 16:47:18 -04001294 private long getLong(String secureSettingKey, long defaultValue, int userHandle) {
1295 try {
1296 return getLockSettings().getLong(secureSettingKey, defaultValue, userHandle);
1297 } catch (RemoteException re) {
1298 return defaultValue;
1299 }
1300 }
1301
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001302 private void setLong(String secureSettingKey, long value, int userHandle) {
Amith Yamasani52c489c2012-03-28 11:42:42 -07001303 try {
Kenny Guy0cf13702013-11-29 16:33:05 +00001304 getLockSettings().setLong(secureSettingKey, value, userHandle);
Amith Yamasani52c489c2012-03-28 11:42:42 -07001305 } catch (RemoteException re) {
1306 // What can we do?
1307 Log.e(TAG, "Couldn't write long " + secureSettingKey + re);
1308 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001309 }
1310
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001311 private String getString(String secureSettingKey, int userHandle) {
Amith Yamasani52c489c2012-03-28 11:42:42 -07001312 try {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001313 return getLockSettings().getString(secureSettingKey, null, userHandle);
Amith Yamasani52c489c2012-03-28 11:42:42 -07001314 } catch (RemoteException re) {
1315 return null;
1316 }
Konstantin Lopyrev863f22d2010-05-12 17:16:58 -07001317 }
1318
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001319 private void setString(String secureSettingKey, String value, int userHandle) {
Amith Yamasani52c489c2012-03-28 11:42:42 -07001320 try {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001321 getLockSettings().setString(secureSettingKey, value, userHandle);
Amith Yamasani52c489c2012-03-28 11:42:42 -07001322 } catch (RemoteException re) {
1323 // What can we do?
1324 Log.e(TAG, "Couldn't write string " + secureSettingKey + re);
1325 }
Konstantin Lopyrev863f22d2010-05-12 17:16:58 -07001326 }
1327
Adrian Roos8150d2a2015-04-16 17:11:20 -07001328 public void setPowerButtonInstantlyLocks(boolean enabled, int userId) {
1329 setBoolean(LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS, enabled, userId);
Jim Millera4edd152012-01-06 18:24:04 -08001330 }
1331
Adrian Roos8150d2a2015-04-16 17:11:20 -07001332 public boolean getPowerButtonInstantlyLocks(int userId) {
1333 return getBoolean(LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS, true, userId);
Adrian Roos82142c22014-03-27 14:56:59 +01001334 }
1335
Bryan Mawhinneye483b562017-05-15 14:46:05 +01001336 public boolean isPowerButtonInstantlyLocksEverChosen(int userId) {
1337 return getString(LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS, userId) != null;
1338 }
1339
Adrian Roos82142c22014-03-27 14:56:59 +01001340 public void setEnabledTrustAgents(Collection<ComponentName> activeTrustAgents, int userId) {
1341 StringBuilder sb = new StringBuilder();
1342 for (ComponentName cn : activeTrustAgents) {
1343 if (sb.length() > 0) {
1344 sb.append(',');
1345 }
1346 sb.append(cn.flattenToShortString());
1347 }
1348 setString(ENABLED_TRUST_AGENTS, sb.toString(), userId);
Adrian Roos8150d2a2015-04-16 17:11:20 -07001349 getTrustManager().reportEnabledTrustAgentsChanged(userId);
Adrian Roos82142c22014-03-27 14:56:59 +01001350 }
1351
1352 public List<ComponentName> getEnabledTrustAgents(int userId) {
1353 String serialized = getString(ENABLED_TRUST_AGENTS, userId);
1354 if (TextUtils.isEmpty(serialized)) {
1355 return null;
1356 }
1357 String[] split = serialized.split(",");
1358 ArrayList<ComponentName> activeTrustAgents = new ArrayList<ComponentName>(split.length);
1359 for (String s : split) {
1360 if (!TextUtils.isEmpty(s)) {
1361 activeTrustAgents.add(ComponentName.unflattenFromString(s));
1362 }
1363 }
1364 return activeTrustAgents;
1365 }
Adrian Roos2c12cfa2014-06-25 23:28:53 +02001366
1367 /**
Adrian Roosb5e47222015-08-14 15:53:06 -07001368 * Disable trust until credentials have been entered for user {@param userId}.
1369 *
1370 * Requires the {@link android.Manifest.permission#ACCESS_KEYGUARD_SECURE_STORAGE} permission.
1371 *
1372 * @param userId either an explicit user id or {@link android.os.UserHandle#USER_ALL}
Adrian Roos2c12cfa2014-06-25 23:28:53 +02001373 */
1374 public void requireCredentialEntry(int userId) {
Jorim Jaggi16093fe32015-09-09 23:29:17 +00001375 requireStrongAuth(StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST, userId);
Adrian Roosb5e47222015-08-14 15:53:06 -07001376 }
1377
1378 /**
1379 * Requests strong authentication for user {@param userId}.
1380 *
1381 * Requires the {@link android.Manifest.permission#ACCESS_KEYGUARD_SECURE_STORAGE} permission.
1382 *
1383 * @param strongAuthReason a combination of {@link StrongAuthTracker.StrongAuthFlags} indicating
1384 * the reason for and the strength of the requested authentication.
1385 * @param userId either an explicit user id or {@link android.os.UserHandle#USER_ALL}
1386 */
1387 public void requireStrongAuth(@StrongAuthTracker.StrongAuthFlags int strongAuthReason,
1388 int userId) {
1389 try {
1390 getLockSettings().requireStrongAuth(strongAuthReason, userId);
1391 } catch (RemoteException e) {
1392 Log.e(TAG, "Error while requesting strong auth: " + e);
1393 }
Adrian Roos2c12cfa2014-06-25 23:28:53 +02001394 }
Adrian Roos4b9e3242014-08-20 23:36:25 +02001395
Adrian Roosf8f56bc2014-11-20 23:55:34 +01001396 private void onAfterChangingPassword(int userHandle) {
1397 getTrustManager().reportEnabledTrustAgentsChanged(userHandle);
Adrian Roos4b9e3242014-08-20 23:36:25 +02001398 }
Jim Millerdd5de712014-10-16 19:50:18 -07001399
1400 public boolean isCredentialRequiredToDecrypt(boolean defaultValue) {
1401 final int value = Settings.Global.getInt(mContentResolver,
1402 Settings.Global.REQUIRE_PASSWORD_TO_DECRYPT, -1);
1403 return value == -1 ? defaultValue : (value != 0);
1404 }
1405
1406 public void setCredentialRequiredToDecrypt(boolean required) {
Robin Leed39113e2016-01-22 15:44:49 +00001407 if (!(getUserManager().isSystemUser() || getUserManager().isPrimaryUser())) {
1408 throw new IllegalStateException(
1409 "Only the system or primary user may call setCredentialRequiredForDecrypt()");
Jim Millerdd5de712014-10-16 19:50:18 -07001410 }
Paul Lawrence688af6c2015-05-15 11:26:17 -07001411
1412 if (isDeviceEncryptionEnabled()){
1413 Settings.Global.putInt(mContext.getContentResolver(),
1414 Settings.Global.REQUIRE_PASSWORD_TO_DECRYPT, required ? 1 : 0);
1415 }
Jim Millerdd5de712014-10-16 19:50:18 -07001416 }
Andrei Kapishnikov4eb6a362015-04-02 15:21:20 -04001417
1418 private boolean isDoNotAskCredentialsOnBootSet() {
Rubin Xu4929a5d2017-01-23 23:55:28 +00001419 return getDevicePolicyManager().getDoNotAskCredentialsOnBoot();
Andrei Kapishnikov4eb6a362015-04-02 15:21:20 -04001420 }
1421
1422 private boolean shouldEncryptWithCredentials(boolean defaultValue) {
1423 return isCredentialRequiredToDecrypt(defaultValue) && !isDoNotAskCredentialsOnBootSet();
1424 }
Xiyuan Xiaaa262942015-05-05 15:18:45 -07001425
1426 private void throwIfCalledOnMainThread() {
1427 if (Looper.getMainLooper().isCurrentThread()) {
1428 throw new IllegalStateException("should not be called from the main thread.");
1429 }
1430 }
Adrian Roosb5e47222015-08-14 15:53:06 -07001431
1432 public void registerStrongAuthTracker(final StrongAuthTracker strongAuthTracker) {
1433 try {
1434 getLockSettings().registerStrongAuthTracker(strongAuthTracker.mStub);
1435 } catch (RemoteException e) {
1436 throw new RuntimeException("Could not register StrongAuthTracker");
1437 }
1438 }
1439
1440 public void unregisterStrongAuthTracker(final StrongAuthTracker strongAuthTracker) {
1441 try {
1442 getLockSettings().unregisterStrongAuthTracker(strongAuthTracker.mStub);
1443 } catch (RemoteException e) {
1444 Log.e(TAG, "Could not unregister StrongAuthTracker", e);
1445 }
1446 }
1447
1448 /**
Victor Changa0940d32016-05-16 19:36:08 +01001449 * @see StrongAuthTracker#getStrongAuthForUser
1450 */
1451 public int getStrongAuthForUser(int userId) {
1452 try {
1453 return getLockSettings().getStrongAuthForUser(userId);
1454 } catch (RemoteException e) {
1455 Log.e(TAG, "Could not get StrongAuth", e);
1456 return StrongAuthTracker.getDefaultFlags(mContext);
1457 }
1458 }
1459
1460 /**
1461 * @see StrongAuthTracker#isTrustAllowedForUser
1462 */
1463 public boolean isTrustAllowedForUser(int userId) {
1464 return getStrongAuthForUser(userId) == StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED;
1465 }
1466
1467 /**
1468 * @see StrongAuthTracker#isFingerprintAllowedForUser
1469 */
1470 public boolean isFingerprintAllowedForUser(int userId) {
1471 return (getStrongAuthForUser(userId) & ~StrongAuthTracker.ALLOWING_FINGERPRINT) == 0;
1472 }
1473
Chad Brubakerea8c5ef2018-03-15 16:37:43 -07001474 public boolean isUserInLockdown(int userId) {
1475 return getStrongAuthForUser(userId)
1476 == StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN;
1477 }
1478
Jorim Jaggie8fde5d2016-06-30 23:41:37 -07001479 private ICheckCredentialProgressCallback wrapCallback(
1480 final CheckCredentialProgressCallback callback) {
1481 if (callback == null) {
1482 return null;
1483 } else {
Adrian Roos7a3bf7c2016-07-12 15:31:55 -07001484 if (mHandler == null) {
1485 throw new IllegalStateException("Must construct LockPatternUtils on a looper thread"
1486 + " to use progress callbacks.");
1487 }
Jorim Jaggie8fde5d2016-06-30 23:41:37 -07001488 return new ICheckCredentialProgressCallback.Stub() {
1489
1490 @Override
1491 public void onCredentialVerified() throws RemoteException {
1492 mHandler.post(callback::onEarlyMatched);
1493 }
1494 };
1495 }
1496 }
1497
Rubin Xufcd49f92017-08-24 18:21:52 +01001498 private LockSettingsInternal getLockSettingsInternal() {
1499 LockSettingsInternal service = LocalServices.getService(LockSettingsInternal.class);
1500 if (service == null) {
1501 throw new SecurityException("Only available to system server itself");
1502 }
1503 return service;
1504 }
Jorim Jaggie8fde5d2016-06-30 23:41:37 -07001505 /**
Rubin Xuf095f832017-01-31 15:23:34 +00001506 * Create an escrow token for the current user, which can later be used to unlock FBE
1507 * or change user password.
1508 *
1509 * After adding, if the user currently has lockscreen password, he will need to perform a
1510 * confirm credential operation in order to activate the token for future use. If the user
1511 * has no secure lockscreen, then the token is activated immediately.
1512 *
Rubin Xufcd49f92017-08-24 18:21:52 +01001513 * <p>This method is only available to code running in the system server process itself.
1514 *
Rubin Xuf095f832017-01-31 15:23:34 +00001515 * @return a unique 64-bit token handle which is needed to refer to this token later.
1516 */
1517 public long addEscrowToken(byte[] token, int userId) {
Rubin Xufcd49f92017-08-24 18:21:52 +01001518 return getLockSettingsInternal().addEscrowToken(token, userId);
Rubin Xuf095f832017-01-31 15:23:34 +00001519 }
1520
1521 /**
1522 * Remove an escrow token.
Rubin Xufcd49f92017-08-24 18:21:52 +01001523 *
1524 * <p>This method is only available to code running in the system server process itself.
1525 *
Rubin Xuf095f832017-01-31 15:23:34 +00001526 * @return true if the given handle refers to a valid token previously returned from
1527 * {@link #addEscrowToken}, whether it's active or not. return false otherwise.
1528 */
1529 public boolean removeEscrowToken(long handle, int userId) {
Rubin Xufcd49f92017-08-24 18:21:52 +01001530 return getLockSettingsInternal().removeEscrowToken(handle, userId);
Rubin Xuf095f832017-01-31 15:23:34 +00001531 }
1532
1533 /**
1534 * Check if the given escrow token is active or not. Only active token can be used to call
1535 * {@link #setLockCredentialWithToken} and {@link #unlockUserWithToken}
Rubin Xufcd49f92017-08-24 18:21:52 +01001536 *
1537 * <p>This method is only available to code running in the system server process itself.
Rubin Xuf095f832017-01-31 15:23:34 +00001538 */
1539 public boolean isEscrowTokenActive(long handle, int userId) {
Rubin Xufcd49f92017-08-24 18:21:52 +01001540 return getLockSettingsInternal().isEscrowTokenActive(handle, userId);
Rubin Xuf095f832017-01-31 15:23:34 +00001541 }
1542
Rubin Xu7cf45092017-08-28 11:47:35 +01001543 /**
1544 * Change a user's lock credential with a pre-configured escrow token.
1545 *
Rubin Xufcd49f92017-08-24 18:21:52 +01001546 * <p>This method is only available to code running in the system server process itself.
1547 *
Rubin Xu7cf45092017-08-28 11:47:35 +01001548 * @param credential The new credential to be set
1549 * @param type Credential type: password / pattern / none.
1550 * @param requestedQuality the requested password quality by DevicePolicyManager.
1551 * See {@link DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
1552 * @param tokenHandle Handle of the escrow token
1553 * @param token Escrow token
1554 * @param userId The user who's lock credential to be changed
1555 * @return {@code true} if the operation is successful.
1556 */
1557 public boolean setLockCredentialWithToken(String credential, int type, int requestedQuality,
1558 long tokenHandle, byte[] token, int userId) {
Rubin Xufcd49f92017-08-24 18:21:52 +01001559 LockSettingsInternal localService = getLockSettingsInternal();
1560 if (type != CREDENTIAL_TYPE_NONE) {
1561 if (TextUtils.isEmpty(credential) || credential.length() < MIN_LOCK_PASSWORD_SIZE) {
1562 throw new IllegalArgumentException("password must not be null and at least "
1563 + "of length " + MIN_LOCK_PASSWORD_SIZE);
Rubin Xuf095f832017-01-31 15:23:34 +00001564 }
Rubin Xufcd49f92017-08-24 18:21:52 +01001565 final int quality = computePasswordQuality(type, credential, requestedQuality);
1566 if (!localService.setLockCredentialWithToken(credential, type, tokenHandle,
1567 token, quality, userId)) {
1568 return false;
1569 }
Rubin Xu682d1672018-03-21 09:13:44 +00001570 setKeyguardStoredPasswordQuality(quality, userId);
Rubin Xufcd49f92017-08-24 18:21:52 +01001571
1572 updateEncryptionPasswordIfNeeded(credential, quality, userId);
1573 updatePasswordHistory(credential, userId);
1574 } else {
1575 if (!TextUtils.isEmpty(credential)) {
1576 throw new IllegalArgumentException("password must be emtpy for NONE type");
1577 }
1578 if (!localService.setLockCredentialWithToken(null, CREDENTIAL_TYPE_NONE,
Rubin Xu682d1672018-03-21 09:13:44 +00001579 tokenHandle, token, PASSWORD_QUALITY_UNSPECIFIED, userId)) {
Rubin Xufcd49f92017-08-24 18:21:52 +01001580 return false;
1581 }
Rubin Xu682d1672018-03-21 09:13:44 +00001582 setKeyguardStoredPasswordQuality(PASSWORD_QUALITY_UNSPECIFIED, userId);
Rubin Xufcd49f92017-08-24 18:21:52 +01001583
1584 if (userId == UserHandle.USER_SYSTEM) {
1585 // Set the encryption password to default.
1586 updateEncryptionPassword(StorageManager.CRYPT_TYPE_DEFAULT, null);
1587 setCredentialRequiredToDecrypt(false);
1588 }
Rubin Xuf095f832017-01-31 15:23:34 +00001589 }
Rubin Xufcd49f92017-08-24 18:21:52 +01001590 onAfterChangingPassword(userId);
1591 return true;
Rubin Xuf095f832017-01-31 15:23:34 +00001592 }
1593
Rubin Xufcd49f92017-08-24 18:21:52 +01001594 /**
1595 * Unlock the specified user by an pre-activated escrow token. This should have the same effect
1596 * on device encryption as the user entering his lockscreen credentials for the first time after
1597 * boot, this includes unlocking the user's credential-encrypted storage as well as the keystore
1598 *
1599 * <p>This method is only available to code running in the system server process itself.
1600 *
1601 * @return {@code true} if the supplied token is valid and unlock succeeds,
1602 * {@code false} otherwise.
1603 */
1604 public boolean unlockUserWithToken(long tokenHandle, byte[] token, int userId) {
1605 return getLockSettingsInternal().unlockUserWithToken(tokenHandle, token, userId);
Rubin Xuf095f832017-01-31 15:23:34 +00001606 }
1607
1608
1609 /**
Jorim Jaggie8fde5d2016-06-30 23:41:37 -07001610 * Callback to be notified about progress when checking credentials.
1611 */
1612 public interface CheckCredentialProgressCallback {
1613
1614 /**
1615 * Called as soon as possible when we know that the credentials match but the user hasn't
1616 * been fully unlocked.
1617 */
1618 void onEarlyMatched();
1619 }
1620
Victor Changa0940d32016-05-16 19:36:08 +01001621 /**
Adrian Roosb5e47222015-08-14 15:53:06 -07001622 * Tracks the global strong authentication state.
1623 */
1624 public static class StrongAuthTracker {
1625
1626 @IntDef(flag = true,
1627 value = { STRONG_AUTH_NOT_REQUIRED,
1628 STRONG_AUTH_REQUIRED_AFTER_BOOT,
1629 STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW,
Adrian Roos9d6fc922016-08-10 17:09:55 -07001630 SOME_AUTH_REQUIRED_AFTER_USER_REQUEST,
Michal Karpinskic52f8672016-11-18 11:32:45 +00001631 STRONG_AUTH_REQUIRED_AFTER_LOCKOUT,
Chad Brubaker4f28f0d2017-09-07 14:28:13 -07001632 STRONG_AUTH_REQUIRED_AFTER_TIMEOUT,
1633 STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN})
Adrian Roosb5e47222015-08-14 15:53:06 -07001634 @Retention(RetentionPolicy.SOURCE)
1635 public @interface StrongAuthFlags {}
1636
1637 /**
1638 * Strong authentication is not required.
1639 */
1640 public static final int STRONG_AUTH_NOT_REQUIRED = 0x0;
1641
1642 /**
1643 * Strong authentication is required because the user has not authenticated since boot.
1644 */
1645 public static final int STRONG_AUTH_REQUIRED_AFTER_BOOT = 0x1;
1646
1647 /**
Jorim Jaggi16093fe32015-09-09 23:29:17 +00001648 * Strong authentication is required because a device admin has requested it.
Adrian Roosb5e47222015-08-14 15:53:06 -07001649 */
1650 public static final int STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW = 0x2;
1651
1652 /**
Jorim Jaggi16093fe32015-09-09 23:29:17 +00001653 * Some authentication is required because the user has temporarily disabled trust.
Adrian Roosb5e47222015-08-14 15:53:06 -07001654 */
Jorim Jaggi16093fe32015-09-09 23:29:17 +00001655 public static final int SOME_AUTH_REQUIRED_AFTER_USER_REQUEST = 0x4;
Adrian Roosb5e47222015-08-14 15:53:06 -07001656
Adrian Roos873010d2015-08-25 15:59:00 -07001657 /**
1658 * Strong authentication is required because the user has been locked out after too many
1659 * attempts.
1660 */
1661 public static final int STRONG_AUTH_REQUIRED_AFTER_LOCKOUT = 0x8;
1662
Adrian Roosaf4ab3e2015-09-02 13:23:30 -07001663 /**
Michal Karpinskic52f8672016-11-18 11:32:45 +00001664 * Strong authentication is required because it hasn't been used for a time required by
1665 * a device admin.
1666 */
1667 public static final int STRONG_AUTH_REQUIRED_AFTER_TIMEOUT = 0x10;
1668
1669 /**
Chad Brubaker4f28f0d2017-09-07 14:28:13 -07001670 * Strong authentication is required because the user has triggered lockdown.
1671 */
1672 public static final int STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN = 0x20;
1673
1674 /**
Adrian Roos9d6fc922016-08-10 17:09:55 -07001675 * Strong auth flags that do not prevent fingerprint from being accepted as auth.
1676 *
1677 * If any other flags are set, fingerprint is disabled.
Adrian Roosaf4ab3e2015-09-02 13:23:30 -07001678 */
Adrian Roosaf4ab3e2015-09-02 13:23:30 -07001679 private static final int ALLOWING_FINGERPRINT = STRONG_AUTH_NOT_REQUIRED
Adrian Roos9d6fc922016-08-10 17:09:55 -07001680 | SOME_AUTH_REQUIRED_AFTER_USER_REQUEST;
Adrian Roosb5e47222015-08-14 15:53:06 -07001681
Adrian Roosaf4ab3e2015-09-02 13:23:30 -07001682 private final SparseIntArray mStrongAuthRequiredForUser = new SparseIntArray();
Adrian Roosb5e47222015-08-14 15:53:06 -07001683 private final H mHandler;
Rakesh Iyera7aa4d62016-01-19 17:27:23 -08001684 private final int mDefaultStrongAuthFlags;
Adrian Roosb5e47222015-08-14 15:53:06 -07001685
Rakesh Iyera7aa4d62016-01-19 17:27:23 -08001686 public StrongAuthTracker(Context context) {
1687 this(context, Looper.myLooper());
Adrian Roosb5e47222015-08-14 15:53:06 -07001688 }
1689
1690 /**
1691 * @param looper the looper on whose thread calls to {@link #onStrongAuthRequiredChanged}
1692 * will be scheduled.
Rakesh Iyera7aa4d62016-01-19 17:27:23 -08001693 * @param context the current {@link Context}
Adrian Roosb5e47222015-08-14 15:53:06 -07001694 */
Rakesh Iyera7aa4d62016-01-19 17:27:23 -08001695 public StrongAuthTracker(Context context, Looper looper) {
Adrian Roosb5e47222015-08-14 15:53:06 -07001696 mHandler = new H(looper);
Rakesh Iyera7aa4d62016-01-19 17:27:23 -08001697 mDefaultStrongAuthFlags = getDefaultFlags(context);
1698 }
1699
1700 public static @StrongAuthFlags int getDefaultFlags(Context context) {
1701 boolean strongAuthRequired = context.getResources().getBoolean(
1702 com.android.internal.R.bool.config_strongAuthRequiredOnBoot);
1703 return strongAuthRequired ? STRONG_AUTH_REQUIRED_AFTER_BOOT : STRONG_AUTH_NOT_REQUIRED;
Adrian Roosb5e47222015-08-14 15:53:06 -07001704 }
1705
1706 /**
1707 * Returns {@link #STRONG_AUTH_NOT_REQUIRED} if strong authentication is not required,
1708 * otherwise returns a combination of {@link StrongAuthFlags} indicating why strong
1709 * authentication is required.
1710 *
1711 * @param userId the user for whom the state is queried.
1712 */
1713 public @StrongAuthFlags int getStrongAuthForUser(int userId) {
Rakesh Iyera7aa4d62016-01-19 17:27:23 -08001714 return mStrongAuthRequiredForUser.get(userId, mDefaultStrongAuthFlags);
Adrian Roosb5e47222015-08-14 15:53:06 -07001715 }
1716
1717 /**
1718 * @return true if unlocking with trust alone is allowed for {@param userId} by the current
1719 * strong authentication requirements.
1720 */
1721 public boolean isTrustAllowedForUser(int userId) {
1722 return getStrongAuthForUser(userId) == STRONG_AUTH_NOT_REQUIRED;
1723 }
1724
1725 /**
1726 * @return true if unlocking with fingerprint alone is allowed for {@param userId} by the
1727 * current strong authentication requirements.
1728 */
1729 public boolean isFingerprintAllowedForUser(int userId) {
Adrian Roosaf4ab3e2015-09-02 13:23:30 -07001730 return (getStrongAuthForUser(userId) & ~ALLOWING_FINGERPRINT) == 0;
Adrian Roosb5e47222015-08-14 15:53:06 -07001731 }
1732
1733 /**
1734 * Called when the strong authentication requirements for {@param userId} changed.
1735 */
1736 public void onStrongAuthRequiredChanged(int userId) {
1737 }
1738
Victor Changa0940d32016-05-16 19:36:08 +01001739 protected void handleStrongAuthRequiredChanged(@StrongAuthFlags int strongAuthFlags,
Adrian Roosb5e47222015-08-14 15:53:06 -07001740 int userId) {
Adrian Roosb5e47222015-08-14 15:53:06 -07001741 int oldValue = getStrongAuthForUser(userId);
1742 if (strongAuthFlags != oldValue) {
Rakesh Iyera7aa4d62016-01-19 17:27:23 -08001743 if (strongAuthFlags == mDefaultStrongAuthFlags) {
Adrian Roosb5e47222015-08-14 15:53:06 -07001744 mStrongAuthRequiredForUser.delete(userId);
1745 } else {
1746 mStrongAuthRequiredForUser.put(userId, strongAuthFlags);
1747 }
1748 onStrongAuthRequiredChanged(userId);
1749 }
1750 }
1751
1752
Victor Changa0940d32016-05-16 19:36:08 +01001753 protected final IStrongAuthTracker.Stub mStub = new IStrongAuthTracker.Stub() {
Adrian Roosb5e47222015-08-14 15:53:06 -07001754 @Override
1755 public void onStrongAuthRequiredChanged(@StrongAuthFlags int strongAuthFlags,
1756 int userId) {
1757 mHandler.obtainMessage(H.MSG_ON_STRONG_AUTH_REQUIRED_CHANGED,
1758 strongAuthFlags, userId).sendToTarget();
1759 }
1760 };
1761
1762 private class H extends Handler {
1763 static final int MSG_ON_STRONG_AUTH_REQUIRED_CHANGED = 1;
1764
1765 public H(Looper looper) {
1766 super(looper);
1767 }
1768
1769 @Override
1770 public void handleMessage(Message msg) {
1771 switch (msg.what) {
1772 case MSG_ON_STRONG_AUTH_REQUIRED_CHANGED:
1773 handleStrongAuthRequiredChanged(msg.arg1, msg.arg2);
1774 break;
1775 }
1776 }
Rubin Xu3bf722a2016-12-15 16:07:38 +00001777 }
1778 }
1779
1780 public void enableSyntheticPassword() {
1781 setLong(SYNTHETIC_PASSWORD_ENABLED_KEY, 1L, UserHandle.USER_SYSTEM);
1782 }
1783
Paul Crowley7a0cc0a2017-05-31 22:12:57 +00001784 public void disableSyntheticPassword() {
1785 setLong(SYNTHETIC_PASSWORD_ENABLED_KEY, 0L, UserHandle.USER_SYSTEM);
1786 }
1787
Rubin Xu3bf722a2016-12-15 16:07:38 +00001788 public boolean isSyntheticPasswordEnabled() {
1789 return getLong(SYNTHETIC_PASSWORD_ENABLED_KEY, 0, UserHandle.USER_SYSTEM) != 0;
Adrian Roosb5e47222015-08-14 15:53:06 -07001790 }
Adrian Roos7374d3a2017-03-31 14:14:53 -07001791
Adrian Roos2adc2632017-09-05 17:01:42 +02001792 public static boolean userOwnsFrpCredential(Context context, UserInfo info) {
1793 return info != null && info.isPrimary() && info.isAdmin() && frpCredentialEnabled(context);
Adrian Roos7374d3a2017-03-31 14:14:53 -07001794 }
1795
Adrian Roos2adc2632017-09-05 17:01:42 +02001796 public static boolean frpCredentialEnabled(Context context) {
1797 return FRP_CREDENTIAL_ENABLED && context.getResources().getBoolean(
1798 com.android.internal.R.bool.config_enableCredentialFactoryResetProtection);
Adrian Roos7374d3a2017-03-31 14:14:53 -07001799 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001800}