blob: c09537670556e4bb97f5c44225875f5135eece96 [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;
Lenka Trochtova66c492a2018-12-06 11:29:21 +010037import android.content.pm.PackageManager;
Clara Bayarria1771112015-12-18 16:29:18 +000038import android.content.pm.UserInfo;
Paul Lawrence3a5a0be2014-09-25 09:26:34 -070039import android.os.AsyncTask;
Adrian Roosb5e47222015-08-14 15:53:06 -070040import android.os.Handler;
Jason parksf7b3cd42011-01-27 09:28:25 -060041import android.os.IBinder;
Xiyuan Xiaaa262942015-05-05 15:18:45 -070042import android.os.Looper;
Adrian Roosb5e47222015-08-14 15:53:06 -070043import android.os.Message;
Jim Miller69ac9882010-02-24 15:35:05 -080044import android.os.RemoteException;
45import android.os.ServiceManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080046import android.os.SystemClock;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -070047import android.os.UserHandle;
Clara Bayarria1771112015-12-18 16:29:18 +000048import android.os.UserManager;
Sudheer Shanka2250d562016-11-07 15:41:02 -080049import android.os.storage.IStorageManager;
Paul Lawrence8e397362014-01-27 15:22:30 -080050import android.os.storage.StorageManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080051import android.provider.Settings;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080052import android.text.TextUtils;
53import android.util.Log;
Adrian Roosb5e47222015-08-14 15:53:06 -070054import android.util.SparseIntArray;
Kevin Chyna3e55822017-10-04 15:47:24 -070055import android.util.SparseLongArray;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080056
Rubin Xu0cbc19e2016-12-09 14:00:21 +000057import com.android.internal.annotations.VisibleForTesting;
Rubin Xufcd49f92017-08-24 18:21:52 +010058import com.android.server.LocalServices;
Kevin Chynb17d4092018-10-01 19:07:03 -070059
Michael Jurka1254f2f2012-10-25 11:44:31 -070060import com.google.android.collect.Lists;
Adrian Roos9dd16eb2015-01-08 16:20:49 +010061
Rubin Xu1de89b32016-11-30 20:03:13 +000062import libcore.util.HexEncoding;
63
Adrian Roosb5e47222015-08-14 15:53:06 -070064import java.lang.annotation.Retention;
65import java.lang.annotation.RetentionPolicy;
Brian Carlstrom929a1c22011-02-01 21:54:09 -080066import java.security.MessageDigest;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080067import java.security.NoSuchAlgorithmException;
Jim Miller11b019d2010-01-20 16:34:45 -080068import java.security.SecureRandom;
Adrian Roos82142c22014-03-27 14:56:59 +010069import java.util.ArrayList;
Rich Canningsf64ec632019-02-21 12:40:36 -080070import java.util.Arrays;
Adrian Roos82142c22014-03-27 14:56:59 +010071import java.util.Collection;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080072import java.util.List;
Rubin Xuf01e9072018-03-30 20:59:28 +010073import java.util.StringJoiner;
Kevin Chynb17d4092018-10-01 19:07:03 -070074
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080075/**
Brian Carlstrom5cfee3f2011-05-31 01:00:15 -070076 * Utilities for the lock pattern and its settings.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080077 */
78public class LockPatternUtils {
79
80 private static final String TAG = "LockPatternUtils";
Brian Colonnaa0ee0042014-07-16 13:50:47 -040081 private static final boolean DEBUG = false;
Adrian Roos8370e472017-07-23 14:35:59 +020082 private static final boolean FRP_CREDENTIAL_ENABLED = true;
Jim Miller69aa4a92009-12-22 19:03:28 -080083
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080084 /**
Rubin Xu1de89b32016-11-30 20:03:13 +000085 * The key to identify when the lock pattern enabled flag is being accessed for legacy reasons.
Bryce Lee46145962015-12-14 14:39:10 -080086 */
87 public static final String LEGACY_LOCK_PATTERN_ENABLED = "legacy_lock_pattern_enabled";
88
89 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080090 * The number of incorrect attempts before which we fall back on an alternative
91 * method of verifying the user, and resetting their lock pattern.
92 */
93 public static final int FAILED_ATTEMPTS_BEFORE_RESET = 20;
94
95 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080096 * The interval of the countdown for showing progress of the lockout.
97 */
98 public static final long FAILED_ATTEMPT_COUNTDOWN_INTERVAL_MS = 1000L;
99
Jim Miller4f369952011-08-19 18:29:22 -0700100
101 /**
102 * This dictates when we start telling the user that continued failed attempts will wipe
103 * their device.
104 */
105 public static final int FAILED_ATTEMPTS_BEFORE_WIPE_GRACE = 5;
106
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800107 /**
108 * The minimum number of dots in a valid pattern.
109 */
110 public static final int MIN_LOCK_PATTERN_SIZE = 4;
111
112 /**
Adrian Roosf80e66ce92015-01-15 23:27:24 +0100113 * The minimum size of a valid password.
114 */
115 public static final int MIN_LOCK_PASSWORD_SIZE = 4;
116
117 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800118 * The minimum number of dots the user must include in a wrong pattern
119 * attempt for it to be counted against the counts that affect
120 * {@link #FAILED_ATTEMPTS_BEFORE_TIMEOUT} and {@link #FAILED_ATTEMPTS_BEFORE_RESET}
121 */
Jim Miller4f369952011-08-19 18:29:22 -0700122 public static final int MIN_PATTERN_REGISTER_FAIL = MIN_LOCK_PATTERN_SIZE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800123
Rubin Xu1de89b32016-11-30 20:03:13 +0000124 public static final int CREDENTIAL_TYPE_NONE = -1;
125
126 public static final int CREDENTIAL_TYPE_PATTERN = 1;
127
128 public static final int CREDENTIAL_TYPE_PASSWORD = 2;
129
Adrian Roos7374d3a2017-03-31 14:14:53 -0700130 /**
131 * Special user id for triggering the FRP verification flow.
132 */
133 public static final int USER_FRP = UserHandle.USER_NULL + 1;
134
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100135 @Deprecated
Jeff Sharkey7a96c392012-11-15 14:01:46 -0800136 public final static String LOCKOUT_PERMANENT_KEY = "lockscreen.lockedoutpermanently";
Jeff Sharkey7a96c392012-11-15 14:01:46 -0800137 public final static String PATTERN_EVER_CHOSEN_KEY = "lockscreen.patterneverchosen";
Jim Miller69aa4a92009-12-22 19:03:28 -0800138 public final static String PASSWORD_TYPE_KEY = "lockscreen.password_type";
Adrian Roos230635e2015-01-07 20:50:29 +0100139 @Deprecated
140 public final static String PASSWORD_TYPE_ALTERNATE_KEY = "lockscreen.password_type_alternate";
Jeff Sharkey7a96c392012-11-15 14:01:46 -0800141 public final static String LOCK_PASSWORD_SALT_KEY = "lockscreen.password_salt";
142 public final static String DISABLE_LOCKSCREEN_KEY = "lockscreen.disabled";
143 public final static String LOCKSCREEN_OPTIONS = "lockscreen.options";
Adrian Roos230635e2015-01-07 20:50:29 +0100144 @Deprecated
Jim Miller6edf2632011-09-05 16:03:14 -0700145 public final static String LOCKSCREEN_BIOMETRIC_WEAK_FALLBACK
146 = "lockscreen.biometric_weak_fallback";
Adrian Roos230635e2015-01-07 20:50:29 +0100147 @Deprecated
Danielle Millett7a072192011-10-03 17:36:01 -0400148 public final static String BIOMETRIC_WEAK_EVER_CHOSEN_KEY
149 = "lockscreen.biometricweakeverchosen";
Jim Millera4edd152012-01-06 18:24:04 -0800150 public final static String LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS
151 = "lockscreen.power_button_instantly_locks";
Adrian Roos230635e2015-01-07 20:50:29 +0100152 @Deprecated
Jim Millerf45bb402013-08-20 18:58:32 -0700153 public final static String LOCKSCREEN_WIDGETS_ENABLED = "lockscreen.widgets_enabled";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800154
Jeff Sharkey7a96c392012-11-15 14:01:46 -0800155 public final static String PASSWORD_HISTORY_KEY = "lockscreen.passwordhistory";
Konstantin Lopyrev863f22d2010-05-12 17:16:58 -0700156
Jim Miller187ec582013-04-15 18:27:54 -0700157 private static final String LOCK_SCREEN_OWNER_INFO = Settings.Secure.LOCK_SCREEN_OWNER_INFO;
158 private static final String LOCK_SCREEN_OWNER_INFO_ENABLED =
159 Settings.Secure.LOCK_SCREEN_OWNER_INFO_ENABLED;
160
Andrei Stingaceanu6644cd92015-11-10 13:03:31 +0000161 private static final String LOCK_SCREEN_DEVICE_OWNER_INFO = "lockscreen.device_owner_info";
162
Adrian Roos82142c22014-03-27 14:56:59 +0100163 private static final String ENABLED_TRUST_AGENTS = "lockscreen.enabledtrustagents";
Adrian Roosc13723f2016-01-12 20:29:03 +0100164 private static final String IS_TRUST_USUALLY_MANAGED = "lockscreen.istrustusuallymanaged";
Adrian Roos82142c22014-03-27 14:56:59 +0100165
Ricky Waid3982442016-05-24 19:27:08 +0100166 public static final String PROFILE_KEY_NAME_ENCRYPT = "profile_key_name_encrypt_";
167 public static final String PROFILE_KEY_NAME_DECRYPT = "profile_key_name_decrypt_";
Rubin Xu3bf722a2016-12-15 16:07:38 +0000168 public static final String SYNTHETIC_PASSWORD_KEY_PREFIX = "synthetic_password_";
169
170 public static final String SYNTHETIC_PASSWORD_HANDLE_KEY = "sp-handle";
171 public static final String SYNTHETIC_PASSWORD_ENABLED_KEY = "enable-sp";
Rubin Xuf01e9072018-03-30 20:59:28 +0100172 private static final String HISTORY_DELIMITER = ",";
Ricky Waid3982442016-05-24 19:27:08 +0100173
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800174 private final Context mContext;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800175 private final ContentResolver mContentResolver;
Jim Miller31f90b62010-01-20 13:35:20 -0800176 private DevicePolicyManager mDevicePolicyManager;
Amith Yamasani52c489c2012-03-28 11:42:42 -0700177 private ILockSettings mLockSettingsService;
Clara Bayarria1771112015-12-18 16:29:18 +0000178 private UserManager mUserManager;
Adrian Roos7a3bf7c2016-07-12 15:31:55 -0700179 private final Handler mHandler;
Kevin Chyna3e55822017-10-04 15:47:24 -0700180 private final SparseLongArray mLockoutDeadlines = new SparseLongArray();
Lenka Trochtova66c492a2018-12-06 11:29:21 +0100181 private Boolean mHasSecureLockScreen;
Jim Milleree82f8f2012-10-01 16:26:18 -0700182
Adrian Roosc13723f2016-01-12 20:29:03 +0100183 /**
184 * Use {@link TrustManager#isTrustUsuallyManaged(int)}.
185 *
186 * This returns the lazily-peristed value and should only be used by TrustManagerService.
187 */
188 public boolean isTrustUsuallyManaged(int userId) {
189 if (!(mLockSettingsService instanceof ILockSettings.Stub)) {
190 throw new IllegalStateException("May only be called by TrustManagerService. "
191 + "Use TrustManager.isTrustUsuallyManaged()");
192 }
193 try {
194 return getLockSettings().getBoolean(IS_TRUST_USUALLY_MANAGED, false, userId);
195 } catch (RemoteException e) {
196 return false;
197 }
198 }
199
200 public void setTrustUsuallyManaged(boolean managed, int userId) {
201 try {
202 getLockSettings().setBoolean(IS_TRUST_USUALLY_MANAGED, managed, userId);
203 } catch (RemoteException e) {
204 // System dead.
205 }
206 }
Andres Morales23974272015-05-14 22:42:26 -0700207
Adrian Roos4ab7e592016-04-13 15:38:13 -0700208 public void userPresent(int userId) {
209 try {
210 getLockSettings().userPresent(userId);
211 } catch (RemoteException e) {
212 throw e.rethrowFromSystemServer();
213 }
214 }
215
Andres Morales23974272015-05-14 22:42:26 -0700216 public static final class RequestThrottledException extends Exception {
217 private int mTimeoutMs;
218 public RequestThrottledException(int timeoutMs) {
219 mTimeoutMs = timeoutMs;
220 }
221
222 /**
223 * @return The amount of time in ms before another request may
224 * be executed
225 */
226 public int getTimeoutMs() {
227 return mTimeoutMs;
228 }
229
230 }
231
Jim Millercd709882010-03-25 18:24:02 -0700232 public DevicePolicyManager getDevicePolicyManager() {
Jim Miller5b0fb3a2010-02-23 13:46:35 -0800233 if (mDevicePolicyManager == null) {
234 mDevicePolicyManager =
235 (DevicePolicyManager)mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
236 if (mDevicePolicyManager == null) {
237 Log.e(TAG, "Can't get DevicePolicyManagerService: is it running?",
238 new IllegalStateException("Stack trace:"));
239 }
240 }
241 return mDevicePolicyManager;
242 }
Amith Yamasani52c489c2012-03-28 11:42:42 -0700243
Clara Bayarria1771112015-12-18 16:29:18 +0000244 private UserManager getUserManager() {
245 if (mUserManager == null) {
246 mUserManager = UserManager.get(mContext);
247 }
248 return mUserManager;
249 }
250
Adrian Roos82142c22014-03-27 14:56:59 +0100251 private TrustManager getTrustManager() {
252 TrustManager trust = (TrustManager) mContext.getSystemService(Context.TRUST_SERVICE);
253 if (trust == null) {
254 Log.e(TAG, "Can't get TrustManagerService: is it running?",
255 new IllegalStateException("Stack trace:"));
256 }
257 return trust;
258 }
259
Jim Miller31f90b62010-01-20 13:35:20 -0800260 public LockPatternUtils(Context context) {
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800261 mContext = context;
Jim Miller31f90b62010-01-20 13:35:20 -0800262 mContentResolver = context.getContentResolver();
Adrian Roos7a3bf7c2016-07-12 15:31:55 -0700263
264 Looper looper = Looper.myLooper();
265 mHandler = looper != null ? new Handler(looper) : null;
Amith Yamasani52c489c2012-03-28 11:42:42 -0700266 }
Jim Miller69aa4a92009-12-22 19:03:28 -0800267
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000268 @VisibleForTesting
269 public ILockSettings getLockSettings() {
Amith Yamasani52c489c2012-03-28 11:42:42 -0700270 if (mLockSettingsService == null) {
Adrian Roos450ce9f2014-10-29 14:30:37 +0100271 ILockSettings service = ILockSettings.Stub.asInterface(
272 ServiceManager.getService("lock_settings"));
Adrian Roos138b8332014-11-11 13:51:07 +0100273 mLockSettingsService = service;
Brad Fitzpatrick90881002010-08-23 18:30:08 -0700274 }
Amith Yamasani52c489c2012-03-28 11:42:42 -0700275 return mLockSettingsService;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800276 }
277
Adrian Roos8150d2a2015-04-16 17:11:20 -0700278 public int getRequestedMinimumPasswordLength(int userId) {
279 return getDevicePolicyManager().getPasswordMinimumLength(null, userId);
Jim Miller31f90b62010-01-20 13:35:20 -0800280 }
281
Pavel Grafov2e7929e2018-05-04 17:29:36 +0100282 public int getMaximumPasswordLength(int quality) {
283 return getDevicePolicyManager().getPasswordMaximumLength(quality);
284 }
285
Jim Miller31f90b62010-01-20 13:35:20 -0800286 /**
287 * Gets the device policy password mode. If the mode is non-specific, returns
288 * MODE_PATTERN which allows the user to choose anything.
Jim Miller31f90b62010-01-20 13:35:20 -0800289 */
Adrian Roos8150d2a2015-04-16 17:11:20 -0700290 public int getRequestedPasswordQuality(int userId) {
291 return getDevicePolicyManager().getPasswordQuality(null, userId);
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100292 }
293
294 private int getRequestedPasswordHistoryLength(int userId) {
295 return getDevicePolicyManager().getPasswordHistoryLength(null, userId);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700296 }
297
Adrian Roos8150d2a2015-04-16 17:11:20 -0700298 public int getRequestedPasswordMinimumLetters(int userId) {
299 return getDevicePolicyManager().getPasswordMinimumLetters(null, userId);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700300 }
301
Adrian Roos8150d2a2015-04-16 17:11:20 -0700302 public int getRequestedPasswordMinimumUpperCase(int userId) {
303 return getDevicePolicyManager().getPasswordMinimumUpperCase(null, userId);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700304 }
305
Adrian Roos8150d2a2015-04-16 17:11:20 -0700306 public int getRequestedPasswordMinimumLowerCase(int userId) {
307 return getDevicePolicyManager().getPasswordMinimumLowerCase(null, userId);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700308 }
309
Adrian Roos8150d2a2015-04-16 17:11:20 -0700310 public int getRequestedPasswordMinimumNumeric(int userId) {
311 return getDevicePolicyManager().getPasswordMinimumNumeric(null, userId);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700312 }
313
Adrian Roos8150d2a2015-04-16 17:11:20 -0700314 public int getRequestedPasswordMinimumSymbols(int userId) {
315 return getDevicePolicyManager().getPasswordMinimumSymbols(null, userId);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700316 }
317
Adrian Roos8150d2a2015-04-16 17:11:20 -0700318 public int getRequestedPasswordMinimumNonLetter(int userId) {
319 return getDevicePolicyManager().getPasswordMinimumNonLetter(null, userId);
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700320 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700321
Adrian Roos8150d2a2015-04-16 17:11:20 -0700322 public void reportFailedPasswordAttempt(int userId) {
Adrian Roos2adc2632017-09-05 17:01:42 +0200323 if (userId == USER_FRP && frpCredentialEnabled(mContext)) {
Adrian Roos7374d3a2017-03-31 14:14:53 -0700324 return;
325 }
Adrian Roos4f994eb2014-07-23 15:45:05 +0200326 getDevicePolicyManager().reportFailedPasswordAttempt(userId);
327 getTrustManager().reportUnlockAttempt(false /* authenticated */, userId);
Jim Miller31f90b62010-01-20 13:35:20 -0800328 }
329
Adrian Roos8150d2a2015-04-16 17:11:20 -0700330 public void reportSuccessfulPasswordAttempt(int userId) {
Adrian Roos2adc2632017-09-05 17:01:42 +0200331 if (userId == USER_FRP && frpCredentialEnabled(mContext)) {
Adrian Roos7374d3a2017-03-31 14:14:53 -0700332 return;
333 }
Adrian Roos8150d2a2015-04-16 17:11:20 -0700334 getDevicePolicyManager().reportSuccessfulPasswordAttempt(userId);
335 getTrustManager().reportUnlockAttempt(true /* authenticated */, userId);
Jim Miller31f90b62010-01-20 13:35:20 -0800336 }
337
Zachary Iqbal327323d2017-01-12 14:41:13 -0800338 public void reportPasswordLockout(int timeoutMs, int userId) {
Adrian Roos2adc2632017-09-05 17:01:42 +0200339 if (userId == USER_FRP && frpCredentialEnabled(mContext)) {
Adrian Roos7374d3a2017-03-31 14:14:53 -0700340 return;
341 }
Zachary Iqbal327323d2017-01-12 14:41:13 -0800342 getTrustManager().reportUnlockLockout(timeoutMs, userId);
343 }
344
Clara Bayarri51e41ad2016-02-11 17:48:53 +0000345 public int getCurrentFailedPasswordAttempts(int userId) {
Adrian Roos2adc2632017-09-05 17:01:42 +0200346 if (userId == USER_FRP && frpCredentialEnabled(mContext)) {
Adrian Roos7374d3a2017-03-31 14:14:53 -0700347 return 0;
348 }
Clara Bayarri51e41ad2016-02-11 17:48:53 +0000349 return getDevicePolicyManager().getCurrentFailedPasswordAttempts(userId);
350 }
351
352 public int getMaximumFailedPasswordsForWipe(int userId) {
Adrian Roos2adc2632017-09-05 17:01:42 +0200353 if (userId == USER_FRP && frpCredentialEnabled(mContext)) {
Adrian Roos7374d3a2017-03-31 14:14:53 -0700354 return 0;
355 }
Clara Bayarri51e41ad2016-02-11 17:48:53 +0000356 return getDevicePolicyManager().getMaximumFailedPasswordsForWipe(
357 null /* componentName */, userId);
358 }
359
Rich Canningsf64ec632019-02-21 12:40:36 -0800360 private byte[] verifyCredential(byte[] credential, int type, long challenge, int userId)
Rubin Xu1de89b32016-11-30 20:03:13 +0000361 throws RequestThrottledException {
362 try {
363 VerifyCredentialResponse response = getLockSettings().verifyCredential(credential,
364 type, challenge, userId);
365 if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
366 return response.getPayload();
367 } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {
368 throw new RequestThrottledException(response.getTimeout());
369 } else {
370 return null;
371 }
372 } catch (RemoteException re) {
373 return null;
374 }
375 }
376
Rich Canningsf64ec632019-02-21 12:40:36 -0800377 private boolean checkCredential(byte[] credential, int type, int userId,
Rubin Xu1de89b32016-11-30 20:03:13 +0000378 @Nullable CheckCredentialProgressCallback progressCallback)
379 throws RequestThrottledException {
380 try {
381 VerifyCredentialResponse response = getLockSettings().checkCredential(credential, type,
382 userId, wrapCallback(progressCallback));
383
384 if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
385 return true;
386 } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {
387 throw new RequestThrottledException(response.getTimeout());
388 } else {
389 return false;
390 }
391 } catch (RemoteException re) {
392 return false;
393 }
394 }
395
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800396 /**
Andres Moralesd9fc85a2015-04-09 19:14:42 -0700397 * Check to see if a pattern matches the saved pattern.
398 * If pattern matches, return an opaque attestation that the challenge
399 * was verified.
400 *
401 * @param pattern The pattern to check.
402 * @param challenge The challenge to verify against the pattern
403 * @return the attestation that the challenge was verified, or null.
404 */
Andres Morales23974272015-05-14 22:42:26 -0700405 public byte[] verifyPattern(List<LockPatternView.Cell> pattern, long challenge, int userId)
406 throws RequestThrottledException {
Xiyuan Xiaaa262942015-05-05 15:18:45 -0700407 throwIfCalledOnMainThread();
Rich Canningsf64ec632019-02-21 12:40:36 -0800408 return verifyCredential(patternToByteArray(pattern), CREDENTIAL_TYPE_PATTERN, challenge,
Rubin Xu1de89b32016-11-30 20:03:13 +0000409 userId);
Andres Moralesd9fc85a2015-04-09 19:14:42 -0700410 }
411
412 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800413 * Check to see if a pattern matches the saved pattern. If no pattern exists,
414 * always returns true.
415 * @param pattern The pattern to check.
Jim Miller69aa4a92009-12-22 19:03:28 -0800416 * @return Whether the pattern matches the stored one.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800417 */
Andres Morales23974272015-05-14 22:42:26 -0700418 public boolean checkPattern(List<LockPatternView.Cell> pattern, int userId)
419 throws RequestThrottledException {
Jorim Jaggie8fde5d2016-06-30 23:41:37 -0700420 return checkPattern(pattern, userId, null /* progressCallback */);
421 }
422
423 /**
424 * Check to see if a pattern matches the saved pattern. If no pattern exists,
425 * always returns true.
426 * @param pattern The pattern to check.
427 * @return Whether the pattern matches the stored one.
428 */
429 public boolean checkPattern(List<LockPatternView.Cell> pattern, int userId,
430 @Nullable CheckCredentialProgressCallback progressCallback)
431 throws RequestThrottledException {
Xiyuan Xiaaa262942015-05-05 15:18:45 -0700432 throwIfCalledOnMainThread();
Rich Canningsf64ec632019-02-21 12:40:36 -0800433 return checkCredential(patternToByteArray(pattern), CREDENTIAL_TYPE_PATTERN, userId,
Rubin Xu1de89b32016-11-30 20:03:13 +0000434 progressCallback);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800435 }
436
437 /**
Andres Moralesd9fc85a2015-04-09 19:14:42 -0700438 * Check to see if a password matches the saved password.
439 * If password matches, return an opaque attestation that the challenge
440 * was verified.
441 *
442 * @param password The password to check.
443 * @param challenge The challenge to verify against the password
444 * @return the attestation that the challenge was verified, or null.
445 */
Rich Canningsf64ec632019-02-21 12:40:36 -0800446 public byte[] verifyPassword(byte[] password, long challenge, int userId)
Andres Morales23974272015-05-14 22:42:26 -0700447 throws RequestThrottledException {
Xiyuan Xiaaa262942015-05-05 15:18:45 -0700448 throwIfCalledOnMainThread();
Rubin Xu1de89b32016-11-30 20:03:13 +0000449 return verifyCredential(password, CREDENTIAL_TYPE_PASSWORD, challenge, userId);
Andres Moralesd9fc85a2015-04-09 19:14:42 -0700450 }
451
Ricky Wai53940d42016-04-05 15:29:24 +0100452
453 /**
454 * Check to see if a password matches the saved password.
455 * If password matches, return an opaque attestation that the challenge
456 * was verified.
457 *
458 * @param password The password to check.
459 * @param challenge The challenge to verify against the password
460 * @return the attestation that the challenge was verified, or null.
461 */
Rich Canningsf64ec632019-02-21 12:40:36 -0800462 public byte[] verifyTiedProfileChallenge(byte[] password, boolean isPattern, long challenge,
Ricky Wai53940d42016-04-05 15:29:24 +0100463 int userId) throws RequestThrottledException {
464 throwIfCalledOnMainThread();
465 try {
466 VerifyCredentialResponse response =
Rubin Xu1de89b32016-11-30 20:03:13 +0000467 getLockSettings().verifyTiedProfileChallenge(password,
468 isPattern ? CREDENTIAL_TYPE_PATTERN : CREDENTIAL_TYPE_PASSWORD, challenge,
Ricky Wai53940d42016-04-05 15:29:24 +0100469 userId);
470
471 if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
472 return response.getPayload();
473 } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {
474 throw new RequestThrottledException(response.getTimeout());
475 } else {
476 return null;
477 }
478 } catch (RemoteException re) {
479 return null;
480 }
481 }
482
Andres Moralesd9fc85a2015-04-09 19:14:42 -0700483 /**
Rich Canningsf64ec632019-02-21 12:40:36 -0800484 *
Jim Miller69aa4a92009-12-22 19:03:28 -0800485 * Check to see if a password matches the saved password. If no password exists,
486 * always returns true.
487 * @param password The password to check.
488 * @return Whether the password matches the stored one.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800489 */
Andres Morales23974272015-05-14 22:42:26 -0700490 public boolean checkPassword(String password, int userId) throws RequestThrottledException {
Rich Canningsf64ec632019-02-21 12:40:36 -0800491 byte[] passwordBytes = password != null ? password.getBytes() : null;
492 return checkPassword(passwordBytes, userId, null /* progressCallback */);
493 }
494
495
496 /**
497 *
498 * Check to see if a password matches the saved password. If no password exists,
499 * always returns true.
500 * @param password The password to check.
501 * @return Whether the password matches the stored one.
502 */
503 public boolean checkPassword(byte[] password, int userId) throws RequestThrottledException {
Jorim Jaggie8fde5d2016-06-30 23:41:37 -0700504 return checkPassword(password, userId, null /* progressCallback */);
505 }
506
Rich Canningsf64ec632019-02-21 12:40:36 -0800507 // TODO(b/120484642): This method is necessary for vendor/qcom code and is a hidden api
508 /* *
509 * Check to see if a password matches the saved password. If no password exists,
510 * always returns true.
511 * @param password The password to check.
512 * @return Whether the password matches the stored one.
513 */
514 public boolean checkPassword(String password, int userId,
515 @Nullable CheckCredentialProgressCallback progressCallback)
516 throws RequestThrottledException {
517 byte[] passwordBytes = password != null ? password.getBytes() : null;
518 throwIfCalledOnMainThread();
519 return checkCredential(passwordBytes, CREDENTIAL_TYPE_PASSWORD, userId, progressCallback);
520
521 }
522
Jorim Jaggie8fde5d2016-06-30 23:41:37 -0700523 /**
524 * Check to see if a password matches the saved password. If no password exists,
525 * always returns true.
526 * @param password The password to check.
527 * @return Whether the password matches the stored one.
528 */
Rich Canningsf64ec632019-02-21 12:40:36 -0800529
530 public boolean checkPassword(byte[] password, int userId,
Jorim Jaggie8fde5d2016-06-30 23:41:37 -0700531 @Nullable CheckCredentialProgressCallback progressCallback)
532 throws RequestThrottledException {
Xiyuan Xiaaa262942015-05-05 15:18:45 -0700533 throwIfCalledOnMainThread();
Rubin Xu1de89b32016-11-30 20:03:13 +0000534 return checkCredential(password, CREDENTIAL_TYPE_PASSWORD, userId, progressCallback);
Jim Miller69aa4a92009-12-22 19:03:28 -0800535 }
536
537 /**
Paul Lawrence945490c2014-03-27 16:37:28 +0000538 * Check to see if vold already has the password.
539 * Note that this also clears vold's copy of the password.
540 * @return Whether the vold password matches or not.
541 */
Adrian Roos8150d2a2015-04-16 17:11:20 -0700542 public boolean checkVoldPassword(int userId) {
Paul Lawrence945490c2014-03-27 16:37:28 +0000543 try {
544 return getLockSettings().checkVoldPassword(userId);
545 } catch (RemoteException re) {
546 return false;
547 }
548 }
549
550 /**
Rubin Xuf01e9072018-03-30 20:59:28 +0100551 * Returns the password history hash factor, needed to check new password against password
552 * history with {@link #checkPasswordHistory(String, byte[], int)}
553 */
Rich Canningsf64ec632019-02-21 12:40:36 -0800554 public byte[] getPasswordHistoryHashFactor(byte[] currentPassword, int userId) {
Rubin Xuf01e9072018-03-30 20:59:28 +0100555 try {
556 return getLockSettings().getHashFactor(currentPassword, userId);
557 } catch (RemoteException e) {
558 Log.e(TAG, "failed to get hash factor", e);
559 return null;
560 }
561 }
562
563 /**
Konstantin Lopyrev863f22d2010-05-12 17:16:58 -0700564 * Check to see if a password matches any of the passwords stored in the
565 * password history.
566 *
Rubin Xuf01e9072018-03-30 20:59:28 +0100567 * @param passwordToCheck The password to check.
568 * @param hashFactor Hash factor of the current user returned from
569 * {@link ILockSettings#getHashFactor}
Konstantin Lopyrev863f22d2010-05-12 17:16:58 -0700570 * @return Whether the password matches any in the history.
571 */
Rich Canningsf64ec632019-02-21 12:40:36 -0800572 public boolean checkPasswordHistory(byte[] passwordToCheck, byte[] hashFactor, int userId) {
573 if (passwordToCheck == null || passwordToCheck.length == 0) {
Rubin Xuf01e9072018-03-30 20:59:28 +0100574 Log.e(TAG, "checkPasswordHistory: empty password");
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700575 return false;
576 }
Rubin Xuf01e9072018-03-30 20:59:28 +0100577 String passwordHistory = getString(PASSWORD_HISTORY_KEY, userId);
578 if (TextUtils.isEmpty(passwordHistory)) {
579 return false;
580 }
Adrian Roos8150d2a2015-04-16 17:11:20 -0700581 int passwordHistoryLength = getRequestedPasswordHistoryLength(userId);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700582 if(passwordHistoryLength == 0) {
583 return false;
584 }
Rubin Xuf01e9072018-03-30 20:59:28 +0100585 String legacyHash = legacyPasswordToHash(passwordToCheck, userId);
586 String passwordHash = passwordToHistoryHash(passwordToCheck, hashFactor, userId);
587 String[] history = passwordHistory.split(HISTORY_DELIMITER);
588 // Password History may be too long...
589 for (int i = 0; i < Math.min(passwordHistoryLength, history.length); i++) {
590 if (history[i].equals(legacyHash) || history[i].equals(passwordHash)) {
591 return true;
592 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700593 }
Rubin Xuf01e9072018-03-30 20:59:28 +0100594 return false;
Konstantin Lopyrev863f22d2010-05-12 17:16:58 -0700595 }
596
597 /**
Jim Miller69aa4a92009-12-22 19:03:28 -0800598 * Check to see if the user has stored a lock pattern.
599 * @return Whether a saved pattern exists.
600 */
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100601 private boolean savedPatternExists(int userId) {
Amith Yamasani52c489c2012-03-28 11:42:42 -0700602 try {
Adrian Roos50bfeec2014-11-20 16:21:11 +0100603 return getLockSettings().havePattern(userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -0700604 } catch (RemoteException re) {
605 return false;
606 }
Jim Miller69aa4a92009-12-22 19:03:28 -0800607 }
608
609 /**
610 * Check to see if the user has stored a lock pattern.
611 * @return Whether a saved pattern exists.
612 */
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100613 private boolean savedPasswordExists(int userId) {
Amith Yamasani52c489c2012-03-28 11:42:42 -0700614 try {
Adrian Roos50bfeec2014-11-20 16:21:11 +0100615 return getLockSettings().havePassword(userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -0700616 } catch (RemoteException re) {
617 return false;
618 }
Jim Miller69aa4a92009-12-22 19:03:28 -0800619 }
620
621 /**
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -0700622 * Return true if the user has ever chosen a pattern. This is true even if the pattern is
623 * currently cleared.
624 *
625 * @return True if the user has ever chosen a pattern.
626 */
Adrian Roos8150d2a2015-04-16 17:11:20 -0700627 public boolean isPatternEverChosen(int userId) {
628 return getBoolean(PATTERN_EVER_CHOSEN_KEY, false, userId);
Adrian Roosdce01222015-01-07 22:39:01 +0100629 }
630
631 /**
Bryan Mawhinneye483b562017-05-15 14:46:05 +0100632 * Records that the user has chosen a pattern at some time, even if the pattern is
633 * currently cleared.
634 */
635 public void reportPatternWasChosen(int userId) {
636 setBoolean(PATTERN_EVER_CHOSEN_KEY, true, userId);
637 }
638
639 /**
Adrian Roosdce01222015-01-07 22:39:01 +0100640 * Used by device policy manager to validate the current password
641 * information it has.
642 */
643 public int getActivePasswordQuality(int userId) {
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100644 int quality = getKeyguardStoredPasswordQuality(userId);
Adrian Roosdce01222015-01-07 22:39:01 +0100645
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100646 if (isLockPasswordEnabled(quality, userId)) {
647 // Quality is a password and a password exists. Return the quality.
648 return quality;
649 }
650
651 if (isLockPatternEnabled(quality, userId)) {
652 // Quality is a pattern and a pattern exists. Return the quality.
653 return quality;
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700654 }
Danielle Millettc8fb5322011-10-04 12:18:51 -0400655
Rubin Xu682d1672018-03-21 09:13:44 +0000656 return PASSWORD_QUALITY_UNSPECIFIED;
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700657 }
Jim Millercd709882010-03-25 18:24:02 -0700658
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700659 /**
Ricky Wai4613fe42016-05-24 11:11:42 +0100660 * Use it to reset keystore without wiping work profile
661 */
662 public void resetKeyStore(int userId) {
663 try {
664 getLockSettings().resetKeyStore(userId);
665 } catch (RemoteException e) {
666 // It should not happen
667 Log.e(TAG, "Couldn't reset keystore " + e);
668 }
669 }
670
671 /**
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800672 * Clear any lock pattern or password.
673 */
Rich Canningsf64ec632019-02-21 12:40:36 -0800674 public void clearLock(byte[] savedCredential, int userHandle) {
Rubin Xu682d1672018-03-21 09:13:44 +0000675 final int currentQuality = getKeyguardStoredPasswordQuality(userHandle);
676 setKeyguardStoredPasswordQuality(PASSWORD_QUALITY_UNSPECIFIED, userHandle);
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100677
Rubin Xua55b1682017-01-31 10:06:56 +0000678 try{
Rich Canningsf64ec632019-02-21 12:40:36 -0800679 getLockSettings().setLockCredential(null, CREDENTIAL_TYPE_NONE,
680 savedCredential, PASSWORD_QUALITY_UNSPECIFIED, userHandle);
Rubin Xu682d1672018-03-21 09:13:44 +0000681 } catch (Exception e) {
682 Log.e(TAG, "Failed to clear lock", e);
683 setKeyguardStoredPasswordQuality(currentQuality, userHandle);
684 return;
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100685 }
686
Xiaohui Chen86c69dd2015-08-27 15:44:02 -0700687 if (userHandle == UserHandle.USER_SYSTEM) {
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100688 // Set the encryption password to default.
689 updateEncryptionPassword(StorageManager.CRYPT_TYPE_DEFAULT, null);
Robin Leed39113e2016-01-22 15:44:49 +0000690 setCredentialRequiredToDecrypt(false);
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100691 }
692
Adrian Roosf8f56bc2014-11-20 23:55:34 +0100693 onAfterChangingPassword(userHandle);
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800694 }
Jim Miller5b0fb3a2010-02-23 13:46:35 -0800695
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800696 /**
Benjamin Franz51ed7942015-04-07 16:34:56 +0100697 * Disable showing lock screen at all for a given user.
698 * This is only meaningful if pattern, pin or password are not set.
Jim Miller2a98a4c2010-11-19 18:49:26 -0800699 *
Benjamin Franz51ed7942015-04-07 16:34:56 +0100700 * @param disable Disables lock screen when true
701 * @param userId User ID of the user this has effect on
702 */
703 public void setLockScreenDisabled(boolean disable, int userId) {
704 setBoolean(DISABLE_LOCKSCREEN_KEY, disable, userId);
705 }
706
707 /**
708 * Determine if LockScreen is disabled for the current user. This is used to decide whether
709 * LockScreen is shown after reboot or after screen timeout / short press on power.
710 *
711 * @return true if lock screen is disabled
Jim Miller2a98a4c2010-11-19 18:49:26 -0800712 */
Adrian Roos8150d2a2015-04-16 17:11:20 -0700713 public boolean isLockScreenDisabled(int userId) {
Evan Rosky2eff7452016-06-09 12:32:33 -0700714 if (isSecure(userId)) {
715 return false;
716 }
717 boolean disabledByDefault = mContext.getResources().getBoolean(
718 com.android.internal.R.bool.config_disableLockscreenByDefault);
719 boolean isSystemUser = UserManager.isSplitSystemUser() && userId == UserHandle.USER_SYSTEM;
Christine Franks5856be82017-06-23 18:12:46 -0700720 UserInfo userInfo = getUserManager().getUserInfo(userId);
721 boolean isDemoUser = UserManager.isDeviceInDemoMode(mContext) && userInfo != null
722 && userInfo.isDemo();
Evan Rosky2eff7452016-06-09 12:32:33 -0700723 return getBoolean(DISABLE_LOCKSCREEN_KEY, false, userId)
Christine Franks5856be82017-06-23 18:12:46 -0700724 || (disabledByDefault && !isSystemUser)
725 || isDemoUser;
Jim Miller2a98a4c2010-11-19 18:49:26 -0800726 }
727
728 /**
Jim Miller6edf2632011-09-05 16:03:14 -0700729 * Save a lock pattern.
730 * @param pattern The new pattern to save.
Adrian Roos8150d2a2015-04-16 17:11:20 -0700731 * @param userId the user whose pattern is to be saved.
Danielle Millett2364a222011-12-21 17:02:32 -0500732 */
Andres Morales8fa56652015-03-31 09:19:50 -0700733 public void saveLockPattern(List<LockPatternView.Cell> pattern, int userId) {
734 this.saveLockPattern(pattern, null, userId);
735 }
Danielle Millett2364a222011-12-21 17:02:32 -0500736 /**
737 * Save a lock pattern.
738 * @param pattern The new pattern to save.
Rich Canningsf64ec632019-02-21 12:40:36 -0800739 * @param savedPattern The previously saved pattern, converted to byte[] format
Adrian Roosf8f56bc2014-11-20 23:55:34 +0100740 * @param userId the user whose pattern is to be saved.
741 */
Rich Canningsf64ec632019-02-21 12:40:36 -0800742 public void saveLockPattern(List<LockPatternView.Cell> pattern, byte[] savedPattern,
743 int userId) {
Lenka Trochtova66c492a2018-12-06 11:29:21 +0100744 if (!hasSecureLockScreen()) {
745 throw new UnsupportedOperationException(
746 "This operation requires the lock screen feature.");
747 }
Rubin Xu682d1672018-03-21 09:13:44 +0000748 if (pattern == null || pattern.size() < MIN_LOCK_PATTERN_SIZE) {
749 throw new IllegalArgumentException("pattern must not be null and at least "
750 + MIN_LOCK_PATTERN_SIZE + " dots long.");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800751 }
Rubin Xu682d1672018-03-21 09:13:44 +0000752
Rich Canningsf64ec632019-02-21 12:40:36 -0800753 final byte[] bytePattern = patternToByteArray(pattern);
Rubin Xu682d1672018-03-21 09:13:44 +0000754 final int currentQuality = getKeyguardStoredPasswordQuality(userId);
755 setKeyguardStoredPasswordQuality(PASSWORD_QUALITY_SOMETHING, userId);
756 try {
Rich Canningsf64ec632019-02-21 12:40:36 -0800757 getLockSettings().setLockCredential(bytePattern, CREDENTIAL_TYPE_PATTERN, savedPattern,
758 PASSWORD_QUALITY_SOMETHING, userId);
Rubin Xu682d1672018-03-21 09:13:44 +0000759 } catch (Exception e) {
760 Log.e(TAG, "Couldn't save lock pattern", e);
761 setKeyguardStoredPasswordQuality(currentQuality, userId);
762 return;
763 }
764 // Update the device encryption password.
765 if (userId == UserHandle.USER_SYSTEM
766 && LockPatternUtils.isDeviceEncryptionEnabled()) {
767 if (!shouldEncryptWithCredentials(true)) {
768 clearEncryptionPassword();
769 } else {
Rich Canningsf64ec632019-02-21 12:40:36 -0800770 updateEncryptionPassword(StorageManager.CRYPT_TYPE_PATTERN, bytePattern);
Rubin Xu682d1672018-03-21 09:13:44 +0000771 }
772 }
773
774 reportPatternWasChosen(userId);
775 onAfterChangingPassword(userId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800776 }
777
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100778 private void updateCryptoUserInfo(int userId) {
Xiaohui Chen86c69dd2015-08-27 15:44:02 -0700779 if (userId != UserHandle.USER_SYSTEM) {
Paul Lawrencee51dcf92014-03-18 10:56:00 -0700780 return;
781 }
782
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100783 final String ownerInfo = isOwnerInfoEnabled(userId) ? getOwnerInfo(userId) : "";
Paul Lawrencee51dcf92014-03-18 10:56:00 -0700784
785 IBinder service = ServiceManager.getService("mount");
786 if (service == null) {
787 Log.e(TAG, "Could not find the mount service to update the user info");
788 return;
789 }
790
Sudheer Shanka2250d562016-11-07 15:41:02 -0800791 IStorageManager storageManager = IStorageManager.Stub.asInterface(service);
Paul Lawrencee51dcf92014-03-18 10:56:00 -0700792 try {
793 Log.d(TAG, "Setting owner info");
Sudheer Shanka2250d562016-11-07 15:41:02 -0800794 storageManager.setField(StorageManager.OWNER_INFO_KEY, ownerInfo);
Paul Lawrencee51dcf92014-03-18 10:56:00 -0700795 } catch (RemoteException e) {
796 Log.e(TAG, "Error changing user info", e);
797 }
798 }
799
Jim Miller187ec582013-04-15 18:27:54 -0700800 public void setOwnerInfo(String info, int userId) {
801 setString(LOCK_SCREEN_OWNER_INFO, info, userId);
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100802 updateCryptoUserInfo(userId);
Jim Miller187ec582013-04-15 18:27:54 -0700803 }
804
Adrian Roos8150d2a2015-04-16 17:11:20 -0700805 public void setOwnerInfoEnabled(boolean enabled, int userId) {
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100806 setBoolean(LOCK_SCREEN_OWNER_INFO_ENABLED, enabled, userId);
807 updateCryptoUserInfo(userId);
Jim Miller187ec582013-04-15 18:27:54 -0700808 }
809
810 public String getOwnerInfo(int userId) {
Adrian Roosdce01222015-01-07 22:39:01 +0100811 return getString(LOCK_SCREEN_OWNER_INFO, userId);
Jim Miller187ec582013-04-15 18:27:54 -0700812 }
813
Adrian Roos8150d2a2015-04-16 17:11:20 -0700814 public boolean isOwnerInfoEnabled(int userId) {
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100815 return getBoolean(LOCK_SCREEN_OWNER_INFO_ENABLED, false, userId);
Jim Miller187ec582013-04-15 18:27:54 -0700816 }
817
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800818 /**
Andrei Stingaceanu6644cd92015-11-10 13:03:31 +0000819 * Sets the device owner information. If the information is {@code null} or empty then the
820 * device owner info is cleared.
821 *
822 * @param info Device owner information which will be displayed instead of the user
823 * owner info.
824 */
825 public void setDeviceOwnerInfo(String info) {
826 if (info != null && info.isEmpty()) {
827 info = null;
828 }
829
830 setString(LOCK_SCREEN_DEVICE_OWNER_INFO, info, UserHandle.USER_SYSTEM);
831 }
832
833 public String getDeviceOwnerInfo() {
834 return getString(LOCK_SCREEN_DEVICE_OWNER_INFO, UserHandle.USER_SYSTEM);
835 }
836
837 public boolean isDeviceOwnerInfoEnabled() {
838 return getDeviceOwnerInfo() != null;
839 }
840
Jason parksf7b3cd42011-01-27 09:28:25 -0600841 /** Update the encryption password if it is enabled **/
Rich Canningsf64ec632019-02-21 12:40:36 -0800842 private void updateEncryptionPassword(final int type, final byte[] password) {
Lenka Trochtova66c492a2018-12-06 11:29:21 +0100843 if (!hasSecureLockScreen()) {
844 throw new UnsupportedOperationException(
845 "This operation requires the lock screen feature.");
846 }
Amith Yamasanicd410ba2014-10-17 11:16:58 -0700847 if (!isDeviceEncryptionEnabled()) {
Jason parksf7b3cd42011-01-27 09:28:25 -0600848 return;
849 }
Paul Lawrence3a5a0be2014-09-25 09:26:34 -0700850 final IBinder service = ServiceManager.getService("mount");
Jason parksf7b3cd42011-01-27 09:28:25 -0600851 if (service == null) {
852 Log.e(TAG, "Could not find the mount service to update the encryption password");
853 return;
854 }
855
Paul Lawrence3a5a0be2014-09-25 09:26:34 -0700856 new AsyncTask<Void, Void, Void>() {
857 @Override
858 protected Void doInBackground(Void... dummy) {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800859 IStorageManager storageManager = IStorageManager.Stub.asInterface(service);
Paul Lawrence3a5a0be2014-09-25 09:26:34 -0700860 try {
Rich Canningsf64ec632019-02-21 12:40:36 -0800861 // TODO(b/120484642): This is a location where we still use a String for vold
862 String passwordString = password != null ? new String(password) : null;
863 storageManager.changeEncryptionPassword(type, passwordString);
Paul Lawrence3a5a0be2014-09-25 09:26:34 -0700864 } catch (RemoteException e) {
865 Log.e(TAG, "Error changing encryption password", e);
866 }
867 return null;
868 }
869 }.execute();
Jason parksf7b3cd42011-01-27 09:28:25 -0600870 }
871
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800872 /**
Jim Millercd709882010-03-25 18:24:02 -0700873 * Save a lock password. Does not ensure that the password is as good
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800874 * as the requested mode, but will adjust the mode to be as good as the
Adrian Roos8150d2a2015-04-16 17:11:20 -0700875 * password.
Jim Miller69aa4a92009-12-22 19:03:28 -0800876 * @param password The password to save
Andres Morales8fa56652015-03-31 09:19:50 -0700877 * @param savedPassword The previously saved lock password, or null if none
Adrian Roos7374d3a2017-03-31 14:14:53 -0700878 * @param requestedQuality {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700879 * @param userHandle The userId of the user to change the password for
Rich Canningsf64ec632019-02-21 12:40:36 -0800880 *
881 * @deprecated Pass password as a byte array
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700882 */
Rich Canningsf64ec632019-02-21 12:40:36 -0800883 @Deprecated
Adrian Roos7374d3a2017-03-31 14:14:53 -0700884 public void saveLockPassword(String password, String savedPassword, int requestedQuality,
Andres Morales8fa56652015-03-31 09:19:50 -0700885 int userHandle) {
Rich Canningsf64ec632019-02-21 12:40:36 -0800886 byte[] passwordBytes = password != null ? password.getBytes() : null;
887 byte[] savedPasswordBytes = savedPassword != null ? savedPassword.getBytes() : null;
888 saveLockPassword(passwordBytes, savedPasswordBytes, requestedQuality, userHandle);
889 }
890
891 /**
892 * Save a lock password. Does not ensure that the password is as good
893 * as the requested mode, but will adjust the mode to be as good as the
894 * password.
895 * @param password The password to save
896 * @param savedPassword The previously saved lock password, or null if none
897 * @param requestedQuality {@see DevicePolicyManager#getPasswordQuality(
898 * android.content.ComponentName)}
899 * @param userHandle The userId of the user to change the password for
900 */
901 public void saveLockPassword(byte[] password, byte[] savedPassword, int requestedQuality,
902 int userHandle) {
Lenka Trochtova66c492a2018-12-06 11:29:21 +0100903 if (!hasSecureLockScreen()) {
904 throw new UnsupportedOperationException(
905 "This operation requires the lock screen feature.");
906 }
Rich Canningsf64ec632019-02-21 12:40:36 -0800907 if (password == null || password.length < MIN_LOCK_PASSWORD_SIZE) {
Rubin Xu682d1672018-03-21 09:13:44 +0000908 throw new IllegalArgumentException("password must not be null and at least "
909 + "of length " + MIN_LOCK_PASSWORD_SIZE);
Jim Miller69aa4a92009-12-22 19:03:28 -0800910 }
Rubin Xu682d1672018-03-21 09:13:44 +0000911
Adrian Roosebf84c22018-12-06 17:50:41 +0100912 if (requestedQuality < PASSWORD_QUALITY_NUMERIC) {
913 throw new IllegalArgumentException("quality must be at least NUMERIC, but was "
914 + requestedQuality);
915 }
916
Rubin Xu682d1672018-03-21 09:13:44 +0000917 final int currentQuality = getKeyguardStoredPasswordQuality(userHandle);
918 setKeyguardStoredPasswordQuality(
919 computePasswordQuality(CREDENTIAL_TYPE_PASSWORD, password, requestedQuality),
920 userHandle);
921 try {
Rich Canningsf64ec632019-02-21 12:40:36 -0800922 getLockSettings().setLockCredential(password, CREDENTIAL_TYPE_PASSWORD, savedPassword,
923 requestedQuality, userHandle);
Rubin Xu682d1672018-03-21 09:13:44 +0000924 } catch (Exception e) {
925 Log.e(TAG, "Unable to save lock password", e);
926 setKeyguardStoredPasswordQuality(currentQuality, userHandle);
927 return;
928 }
929
930 updateEncryptionPasswordIfNeeded(password,
931 PasswordMetrics.computeForPassword(password).quality, userHandle);
932 updatePasswordHistory(password, userHandle);
Rubin Xuf01e9072018-03-30 20:59:28 +0100933 onAfterChangingPassword(userHandle);
Jim Miller69aa4a92009-12-22 19:03:28 -0800934 }
935
Rubin Xuf095f832017-01-31 15:23:34 +0000936 /**
937 * Update device encryption password if calling user is USER_SYSTEM and device supports
938 * encryption.
939 */
Rich Canningsf64ec632019-02-21 12:40:36 -0800940 private void updateEncryptionPasswordIfNeeded(byte[] password, int quality, int userHandle) {
Rubin Xua55b1682017-01-31 10:06:56 +0000941 // Update the device encryption password.
942 if (userHandle == UserHandle.USER_SYSTEM
943 && LockPatternUtils.isDeviceEncryptionEnabled()) {
944 if (!shouldEncryptWithCredentials(true)) {
945 clearEncryptionPassword();
946 } else {
Rubin Xu682d1672018-03-21 09:13:44 +0000947 boolean numeric = quality == PASSWORD_QUALITY_NUMERIC;
948 boolean numericComplex = quality == PASSWORD_QUALITY_NUMERIC_COMPLEX;
Rubin Xua55b1682017-01-31 10:06:56 +0000949 int type = numeric || numericComplex ? StorageManager.CRYPT_TYPE_PIN
950 : StorageManager.CRYPT_TYPE_PASSWORD;
951 updateEncryptionPassword(type, password);
952 }
953 }
954 }
955
Rubin Xuf01e9072018-03-30 20:59:28 +0100956 /**
957 * Store the hash of the *current* password in the password history list, if device policy
958 * enforces password history requirement.
959 */
Rich Canningsf64ec632019-02-21 12:40:36 -0800960 private void updatePasswordHistory(byte[] password, int userHandle) {
961 if (password == null || password.length == 0) {
Rubin Xuf01e9072018-03-30 20:59:28 +0100962 Log.e(TAG, "checkPasswordHistory: empty password");
963 return;
964 }
Rubin Xua55b1682017-01-31 10:06:56 +0000965 // Add the password to the password history. We assume all
966 // password hashes have the same length for simplicity of implementation.
967 String passwordHistory = getString(PASSWORD_HISTORY_KEY, userHandle);
968 if (passwordHistory == null) {
969 passwordHistory = "";
970 }
971 int passwordHistoryLength = getRequestedPasswordHistoryLength(userHandle);
972 if (passwordHistoryLength == 0) {
973 passwordHistory = "";
974 } else {
Rubin Xuf01e9072018-03-30 20:59:28 +0100975 final byte[] hashFactor = getPasswordHistoryHashFactor(password, userHandle);
976 String hash = passwordToHistoryHash(password, hashFactor, userHandle);
977 if (hash == null) {
978 Log.e(TAG, "Compute new style password hash failed, fallback to legacy style");
979 hash = legacyPasswordToHash(password, userHandle);
980 }
981 if (TextUtils.isEmpty(passwordHistory)) {
982 passwordHistory = hash;
983 } else {
984 String[] history = passwordHistory.split(HISTORY_DELIMITER);
985 StringJoiner joiner = new StringJoiner(HISTORY_DELIMITER);
986 joiner.add(hash);
987 for (int i = 0; i < passwordHistoryLength - 1 && i < history.length; i++) {
988 joiner.add(history[i]);
989 }
990 passwordHistory = joiner.toString();
991 }
Rubin Xua55b1682017-01-31 10:06:56 +0000992 }
993 setString(PASSWORD_HISTORY_KEY, passwordHistory, userHandle);
Rubin Xua55b1682017-01-31 10:06:56 +0000994 }
995
Jim Millercd709882010-03-25 18:24:02 -0700996 /**
Jim Miller6848dc82014-10-13 18:51:53 -0700997 * Determine if the device supports encryption, even if it's set to default. This
998 * differs from isDeviceEncrypted() in that it returns true even if the device is
999 * encrypted with the default password.
1000 * @return true if device encryption is enabled
1001 */
1002 public static boolean isDeviceEncryptionEnabled() {
Paul Lawrence20be5d62016-02-26 13:51:17 -08001003 return StorageManager.isEncrypted();
Jim Miller6848dc82014-10-13 18:51:53 -07001004 }
1005
1006 /**
Paul Lawrence5c21c702016-01-29 13:26:19 -08001007 * Determine if the device is file encrypted
1008 * @return true if device is file encrypted
1009 */
1010 public static boolean isFileEncryptionEnabled() {
Paul Lawrence20be5d62016-02-26 13:51:17 -08001011 return StorageManager.isFileEncryptedNativeOrEmulated();
Paul Lawrence5c21c702016-01-29 13:26:19 -08001012 }
1013
1014 /**
Svetoslav16e4a1a2014-09-29 18:16:20 -07001015 * Clears the encryption password.
1016 */
1017 public void clearEncryptionPassword() {
1018 updateEncryptionPassword(StorageManager.CRYPT_TYPE_DEFAULT, null);
1019 }
1020
1021 /**
Adrian Roos1572ee32014-09-01 16:24:32 +02001022 * Retrieves the quality mode for {@param userHandle}.
1023 * {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
1024 *
1025 * @return stored password quality
1026 */
1027 public int getKeyguardStoredPasswordQuality(int userHandle) {
Rubin Xu682d1672018-03-21 09:13:44 +00001028 return (int) getLong(PASSWORD_TYPE_KEY, PASSWORD_QUALITY_UNSPECIFIED, userHandle);
1029 }
1030
1031 private void setKeyguardStoredPasswordQuality(int quality, int userHandle) {
1032 setLong(PASSWORD_TYPE_KEY, quality, userHandle);
Jim Miller6edf2632011-09-05 16:03:14 -07001033 }
1034
Danielle Millett58396982011-09-30 13:55:07 -04001035 /**
Rubin Xu7cf45092017-08-28 11:47:35 +01001036 * Returns the password quality of the given credential, promoting it to a higher level
1037 * if DevicePolicyManager has a stronger quality requirement. This value will be written
1038 * to PASSWORD_TYPE_KEY.
1039 */
Rich Canningsf64ec632019-02-21 12:40:36 -08001040 private int computePasswordQuality(int type, byte[] credential, int requestedQuality) {
Rubin Xu7cf45092017-08-28 11:47:35 +01001041 final int quality;
1042 if (type == CREDENTIAL_TYPE_PASSWORD) {
1043 int computedQuality = PasswordMetrics.computeForPassword(credential).quality;
1044 quality = Math.max(requestedQuality, computedQuality);
1045 } else if (type == CREDENTIAL_TYPE_PATTERN) {
Rubin Xu682d1672018-03-21 09:13:44 +00001046 quality = PASSWORD_QUALITY_SOMETHING;
Rubin Xu7cf45092017-08-28 11:47:35 +01001047 } else /* if (type == CREDENTIAL_TYPE_NONE) */ {
Rubin Xu682d1672018-03-21 09:13:44 +00001048 quality = PASSWORD_QUALITY_UNSPECIFIED;
Rubin Xu7cf45092017-08-28 11:47:35 +01001049 }
1050 return quality;
1051 }
1052
1053 /**
Clara Bayarria1771112015-12-18 16:29:18 +00001054 * Enables/disables the Separate Profile Challenge for this {@param userHandle}. This is a no-op
1055 * for user handles that do not belong to a managed profile.
Ricky Waidc283a82016-03-24 19:55:08 +00001056 *
1057 * @param userHandle Managed profile user id
1058 * @param enabled True if separate challenge is enabled
1059 * @param managedUserPassword Managed profile previous password. Null when {@param enabled} is
1060 * true
Clara Bayarria1771112015-12-18 16:29:18 +00001061 */
Ricky Waidc283a82016-03-24 19:55:08 +00001062 public void setSeparateProfileChallengeEnabled(int userHandle, boolean enabled,
Rich Canningsf64ec632019-02-21 12:40:36 -08001063 byte[] managedUserPassword) {
Pavel Grafovb3191252017-07-14 12:30:31 +01001064 if (!isManagedProfile(userHandle)) {
1065 return;
1066 }
1067 try {
1068 getLockSettings().setSeparateProfileChallengeEnabled(userHandle, enabled,
1069 managedUserPassword);
1070 onAfterChangingPassword(userHandle);
1071 } catch (RemoteException e) {
1072 Log.e(TAG, "Couldn't update work profile challenge enabled");
Clara Bayarria1771112015-12-18 16:29:18 +00001073 }
1074 }
1075
1076 /**
Pavel Grafovb3191252017-07-14 12:30:31 +01001077 * Returns true if {@param userHandle} is a managed profile with separate challenge.
Clara Bayarria1771112015-12-18 16:29:18 +00001078 */
1079 public boolean isSeparateProfileChallengeEnabled(int userHandle) {
Pavel Grafovb3191252017-07-14 12:30:31 +01001080 return isManagedProfile(userHandle) && hasSeparateChallenge(userHandle);
1081 }
1082
1083 /**
1084 * Returns true if {@param userHandle} is a managed profile with unified challenge.
1085 */
1086 public boolean isManagedProfileWithUnifiedChallenge(int userHandle) {
1087 return isManagedProfile(userHandle) && !hasSeparateChallenge(userHandle);
1088 }
1089
1090 /**
1091 * Retrieves whether the current DPM allows use of the Profile Challenge.
1092 */
1093 public boolean isSeparateProfileChallengeAllowed(int userHandle) {
1094 return isManagedProfile(userHandle)
1095 && getDevicePolicyManager().isSeparateProfileChallengeAllowed(userHandle);
1096 }
1097
1098 /**
1099 * Retrieves whether the current profile and device locks can be unified.
Pavel Grafovc4f87e92017-10-26 16:34:25 +01001100 * @param userHandle profile user handle.
Pavel Grafovb3191252017-07-14 12:30:31 +01001101 */
1102 public boolean isSeparateProfileChallengeAllowedToUnify(int userHandle) {
Pavel Grafovc4f87e92017-10-26 16:34:25 +01001103 return getDevicePolicyManager().isProfileActivePasswordSufficientForParent(userHandle)
1104 && !getUserManager().hasUserRestriction(
1105 UserManager.DISALLOW_UNIFIED_PASSWORD, UserHandle.of(userHandle));
Pavel Grafovb3191252017-07-14 12:30:31 +01001106 }
1107
1108 private boolean hasSeparateChallenge(int userHandle) {
Ricky Waidc283a82016-03-24 19:55:08 +00001109 try {
1110 return getLockSettings().getSeparateProfileChallengeEnabled(userHandle);
1111 } catch (RemoteException e) {
1112 Log.e(TAG, "Couldn't get separate profile challenge enabled");
1113 // Default value is false
1114 return false;
1115 }
Clara Bayarria1771112015-12-18 16:29:18 +00001116 }
1117
Pavel Grafovb3191252017-07-14 12:30:31 +01001118 private boolean isManagedProfile(int userHandle) {
1119 final UserInfo info = getUserManager().getUserInfo(userHandle);
1120 return info != null && info.isManagedProfile();
Clara Bayarrid7693912016-01-22 17:26:31 +00001121 }
1122
1123 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001124 * Deserialize a pattern.
1125 * @param string The pattern serialized with {@link #patternToString}
1126 * @return The pattern.
Rich Canningsf64ec632019-02-21 12:40:36 -08001127 * @deprecated Pass patterns as byte[] and use byteArrayToPattern
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001128 */
Rich Canningsf64ec632019-02-21 12:40:36 -08001129 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001130 public static List<LockPatternView.Cell> stringToPattern(String string) {
Adrian Roos9dd16eb2015-01-08 16:20:49 +01001131 if (string == null) {
1132 return null;
1133 }
Rich Canningsf64ec632019-02-21 12:40:36 -08001134 return byteArrayToPattern(string.getBytes());
1135 }
1136
1137 /**
1138 * Deserialize a pattern.
1139 * @param bytes The pattern serialized with {@link #patternToByteArray}
1140 * @return The pattern.
1141 */
1142 public static List<LockPatternView.Cell> byteArrayToPattern(byte[] bytes) {
1143 if (bytes == null) {
1144 return null;
1145 }
Adrian Roos9dd16eb2015-01-08 16:20:49 +01001146
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001147 List<LockPatternView.Cell> result = Lists.newArrayList();
1148
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001149 for (int i = 0; i < bytes.length; i++) {
Andres Moralese40bad82015-05-28 14:21:36 -07001150 byte b = (byte) (bytes[i] - '1');
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001151 result.add(LockPatternView.Cell.of(b / 3, b % 3));
1152 }
1153 return result;
1154 }
1155
1156 /**
1157 * Serialize a pattern.
1158 * @param pattern The pattern.
1159 * @return The pattern in string form.
Rich Canningsf64ec632019-02-21 12:40:36 -08001160 * @deprecated Use patternToByteArray instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001161 */
Rich Canningsf64ec632019-02-21 12:40:36 -08001162 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001163 public static String patternToString(List<LockPatternView.Cell> pattern) {
Rich Canningsf64ec632019-02-21 12:40:36 -08001164 return new String(patternToByteArray(pattern));
1165 }
1166
1167
1168 /**
1169 * Serialize a pattern.
1170 * @param pattern The pattern.
1171 * @return The pattern in byte array form.
1172 */
1173 public static byte[] patternToByteArray(List<LockPatternView.Cell> pattern) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001174 if (pattern == null) {
Rich Canningsf64ec632019-02-21 12:40:36 -08001175 return new byte[0];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001176 }
1177 final int patternSize = pattern.size();
1178
1179 byte[] res = new byte[patternSize];
1180 for (int i = 0; i < patternSize; i++) {
1181 LockPatternView.Cell cell = pattern.get(i);
Andres Moralese40bad82015-05-28 14:21:36 -07001182 res[i] = (byte) (cell.getRow() * 3 + cell.getColumn() + '1');
1183 }
Rich Canningsf64ec632019-02-21 12:40:36 -08001184 return res;
Andres Moralese40bad82015-05-28 14:21:36 -07001185 }
1186
Rich Canningsf64ec632019-02-21 12:40:36 -08001187 /**
1188 * Transform a pattern byte array to base zero form.
1189 * @param bytes pattern byte array.
1190 * @return The pattern in base zero form.
1191 */
1192 public static byte[] patternByteArrayToBaseZero(byte[] bytes) {
1193 if (bytes == null) {
1194 return new byte[0];
Andres Moralese40bad82015-05-28 14:21:36 -07001195 }
Rich Canningsf64ec632019-02-21 12:40:36 -08001196 final int patternSize = bytes.length;
Andres Moralese40bad82015-05-28 14:21:36 -07001197 byte[] res = new byte[patternSize];
Andres Moralese40bad82015-05-28 14:21:36 -07001198 for (int i = 0; i < patternSize; i++) {
1199 res[i] = (byte) (bytes[i] - '1');
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001200 }
Rich Canningsf64ec632019-02-21 12:40:36 -08001201 return res;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001202 }
Jim Miller69aa4a92009-12-22 19:03:28 -08001203
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001204 /*
1205 * Generate an SHA-1 hash for the pattern. Not the most secure, but it is
1206 * at least a second level of protection. First level is that the file
1207 * is in a location only readable by the system process.
1208 * @param pattern the gesture pattern.
1209 * @return the hash of the pattern in a byte array.
1210 */
Jim Millerde1af082013-09-11 14:58:26 -07001211 public static byte[] patternToHash(List<LockPatternView.Cell> pattern) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001212 if (pattern == null) {
1213 return null;
1214 }
Jim Miller69aa4a92009-12-22 19:03:28 -08001215
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001216 final int patternSize = pattern.size();
1217 byte[] res = new byte[patternSize];
1218 for (int i = 0; i < patternSize; i++) {
1219 LockPatternView.Cell cell = pattern.get(i);
1220 res[i] = (byte) (cell.getRow() * 3 + cell.getColumn());
1221 }
1222 try {
1223 MessageDigest md = MessageDigest.getInstance("SHA-1");
1224 byte[] hash = md.digest(res);
1225 return hash;
1226 } catch (NoSuchAlgorithmException nsa) {
1227 return res;
1228 }
1229 }
1230
Geoffrey Borggaard987672d22014-07-18 16:47:18 -04001231 private String getSalt(int userId) {
1232 long salt = getLong(LOCK_PASSWORD_SALT_KEY, 0, userId);
Jim Miller11b019d2010-01-20 16:34:45 -08001233 if (salt == 0) {
1234 try {
1235 salt = SecureRandom.getInstance("SHA1PRNG").nextLong();
Geoffrey Borggaard987672d22014-07-18 16:47:18 -04001236 setLong(LOCK_PASSWORD_SALT_KEY, salt, userId);
1237 Log.v(TAG, "Initialized lock password salt for user: " + userId);
Jim Miller11b019d2010-01-20 16:34:45 -08001238 } catch (NoSuchAlgorithmException e) {
1239 // Throw an exception rather than storing a password we'll never be able to recover
1240 throw new IllegalStateException("Couldn't get SecureRandom number", e);
1241 }
1242 }
1243 return Long.toHexString(salt);
1244 }
1245
Rubin Xuf01e9072018-03-30 20:59:28 +01001246 /**
Jim Miller69aa4a92009-12-22 19:03:28 -08001247 * Generate a hash for the given password. To avoid brute force attacks, we use a salted hash.
1248 * Not the most secure, but it is at least a second level of protection. First level is that
1249 * the file is in a location only readable by the system process.
Narayan Kamath78108a32014-12-16 12:56:23 +00001250 *
Jim Miller69aa4a92009-12-22 19:03:28 -08001251 * @param password the gesture pattern.
Narayan Kamath78108a32014-12-16 12:56:23 +00001252 *
Jim Miller69aa4a92009-12-22 19:03:28 -08001253 * @return the hash of the pattern in a byte array.
1254 */
Rich Canningsf64ec632019-02-21 12:40:36 -08001255 public String legacyPasswordToHash(byte[] password, int userId) {
1256 if (password == null || password.length == 0) {
Jim Miller69aa4a92009-12-22 19:03:28 -08001257 return null;
1258 }
Narayan Kamath78108a32014-12-16 12:56:23 +00001259
Jim Miller69aa4a92009-12-22 19:03:28 -08001260 try {
Rich Canningsf64ec632019-02-21 12:40:36 -08001261 // Previously the password was passed as a String with the following code:
1262 // byte[] saltedPassword = (password + getSalt(userId)).getBytes();
1263 // The code below creates the identical digest preimage using byte arrays:
1264 byte[] salt = getSalt(userId).getBytes();
1265 byte[] saltedPassword = Arrays.copyOf(password, password.length + salt.length);
1266 System.arraycopy(salt, 0, saltedPassword, password.length, salt.length);
Narayan Kamath78108a32014-12-16 12:56:23 +00001267 byte[] sha1 = MessageDigest.getInstance("SHA-1").digest(saltedPassword);
1268 byte[] md5 = MessageDigest.getInstance("MD5").digest(saltedPassword);
Jim Miller69aa4a92009-12-22 19:03:28 -08001269
Narayan Kamath78108a32014-12-16 12:56:23 +00001270 byte[] combined = new byte[sha1.length + md5.length];
1271 System.arraycopy(sha1, 0, combined, 0, sha1.length);
1272 System.arraycopy(md5, 0, combined, sha1.length, md5.length);
1273
1274 final char[] hexEncoded = HexEncoding.encode(combined);
Rich Canningsf64ec632019-02-21 12:40:36 -08001275 Arrays.fill(saltedPassword, (byte) 0);
Rubin Xuf01e9072018-03-30 20:59:28 +01001276 return new String(hexEncoded);
1277 } catch (NoSuchAlgorithmException e) {
1278 throw new AssertionError("Missing digest algorithm: ", e);
1279 }
1280 }
1281
1282 /**
1283 * Hash the password for password history check purpose.
1284 */
Rich Canningsf64ec632019-02-21 12:40:36 -08001285 private String passwordToHistoryHash(byte[] passwordToHash, byte[] hashFactor, int userId) {
1286 if (passwordToHash == null || passwordToHash.length == 0 || hashFactor == null) {
Rubin Xuf01e9072018-03-30 20:59:28 +01001287 return null;
1288 }
1289 try {
1290 MessageDigest sha256 = MessageDigest.getInstance("SHA-256");
1291 sha256.update(hashFactor);
Rich Canningsf64ec632019-02-21 12:40:36 -08001292 byte[] salt = getSalt(userId).getBytes();
1293 byte[] saltedPassword = Arrays.copyOf(passwordToHash, passwordToHash.length
1294 + salt.length);
1295 System.arraycopy(salt, 0, saltedPassword, passwordToHash.length, salt.length);
1296 sha256.update(saltedPassword);
1297 Arrays.fill(saltedPassword, (byte) 0);
Rubin Xuf01e9072018-03-30 20:59:28 +01001298 return new String(HexEncoding.encode(sha256.digest()));
Narayan Kamath78108a32014-12-16 12:56:23 +00001299 } catch (NoSuchAlgorithmException e) {
1300 throw new AssertionError("Missing digest algorithm: ", e);
Jim Miller69aa4a92009-12-22 19:03:28 -08001301 }
Jim Miller69aa4a92009-12-22 19:03:28 -08001302 }
1303
1304 /**
Adrian Roos9dd16eb2015-01-08 16:20:49 +01001305 * @param userId the user for which to report the value
1306 * @return Whether the lock screen is secured.
1307 */
1308 public boolean isSecure(int userId) {
1309 int mode = getKeyguardStoredPasswordQuality(userId);
1310 return isLockPatternEnabled(mode, userId) || isLockPasswordEnabled(mode, userId);
1311 }
1312
Adrian Roosdce01222015-01-07 22:39:01 +01001313 public boolean isLockPasswordEnabled(int userId) {
Adrian Roos9dd16eb2015-01-08 16:20:49 +01001314 return isLockPasswordEnabled(getKeyguardStoredPasswordQuality(userId), userId);
1315 }
1316
1317 private boolean isLockPasswordEnabled(int mode, int userId) {
Rubin Xu682d1672018-03-21 09:13:44 +00001318 final boolean passwordEnabled = mode == PASSWORD_QUALITY_ALPHABETIC
1319 || mode == PASSWORD_QUALITY_NUMERIC
1320 || mode == PASSWORD_QUALITY_NUMERIC_COMPLEX
1321 || mode == PASSWORD_QUALITY_ALPHANUMERIC
1322 || mode == PASSWORD_QUALITY_COMPLEX
1323 || mode == PASSWORD_QUALITY_MANAGED;
Adrian Roos9dd16eb2015-01-08 16:20:49 +01001324 return passwordEnabled && savedPasswordExists(userId);
Jim Miller69aa4a92009-12-22 19:03:28 -08001325 }
1326
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001327 /**
Adrian Roos230635e2015-01-07 20:50:29 +01001328 * @return Whether the lock pattern is enabled
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001329 */
Adrian Roos50bfeec2014-11-20 16:21:11 +01001330 public boolean isLockPatternEnabled(int userId) {
Adrian Roos9dd16eb2015-01-08 16:20:49 +01001331 return isLockPatternEnabled(getKeyguardStoredPasswordQuality(userId), userId);
Danielle Millett925a7d82012-03-19 18:02:20 -04001332 }
1333
Bryce Lee46145962015-12-14 14:39:10 -08001334 @Deprecated
1335 public boolean isLegacyLockPatternEnabled(int userId) {
1336 // Note: this value should default to {@code true} to avoid any reset that might result.
1337 // We must use a special key to read this value, since it will by default return the value
1338 // based on the new logic.
1339 return getBoolean(LEGACY_LOCK_PATTERN_ENABLED, true, userId);
1340 }
1341
1342 @Deprecated
1343 public void setLegacyLockPatternEnabled(int userId) {
1344 setBoolean(Settings.Secure.LOCK_PATTERN_ENABLED, true, userId);
1345 }
1346
Adrian Roos9dd16eb2015-01-08 16:20:49 +01001347 private boolean isLockPatternEnabled(int mode, int userId) {
Rubin Xu682d1672018-03-21 09:13:44 +00001348 return mode == PASSWORD_QUALITY_SOMETHING && savedPatternExists(userId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001349 }
1350
1351 /**
1352 * @return Whether the visible pattern is enabled.
1353 */
Adrian Roos8150d2a2015-04-16 17:11:20 -07001354 public boolean isVisiblePatternEnabled(int userId) {
1355 return getBoolean(Settings.Secure.LOCK_PATTERN_VISIBLE, false, userId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001356 }
1357
1358 /**
1359 * Set whether the visible pattern is enabled.
1360 */
Adrian Roos8150d2a2015-04-16 17:11:20 -07001361 public void setVisiblePatternEnabled(boolean enabled, int userId) {
Adrian Roosdce01222015-01-07 22:39:01 +01001362 setBoolean(Settings.Secure.LOCK_PATTERN_VISIBLE, enabled, userId);
Paul Lawrence878ba0a2014-08-20 13:08:01 -07001363
1364 // Update for crypto if owner
Xiaohui Chen86c69dd2015-08-27 15:44:02 -07001365 if (userId != UserHandle.USER_SYSTEM) {
Paul Lawrence878ba0a2014-08-20 13:08:01 -07001366 return;
1367 }
1368
1369 IBinder service = ServiceManager.getService("mount");
1370 if (service == null) {
1371 Log.e(TAG, "Could not find the mount service to update the user info");
1372 return;
1373 }
1374
Sudheer Shanka2250d562016-11-07 15:41:02 -08001375 IStorageManager storageManager = IStorageManager.Stub.asInterface(service);
Paul Lawrence878ba0a2014-08-20 13:08:01 -07001376 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -08001377 storageManager.setField(StorageManager.PATTERN_VISIBLE_KEY, enabled ? "1" : "0");
Paul Lawrence878ba0a2014-08-20 13:08:01 -07001378 } catch (RemoteException e) {
1379 Log.e(TAG, "Error changing pattern visible state", e);
1380 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001381 }
1382
Bryan Mawhinneye483b562017-05-15 14:46:05 +01001383 public boolean isVisiblePatternEverChosen(int userId) {
1384 return getString(Settings.Secure.LOCK_PATTERN_VISIBLE, userId) != null;
1385 }
1386
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001387 /**
Paul Lawrenced8fdb332015-05-18 13:26:11 -07001388 * Set whether the visible password is enabled for cryptkeeper screen.
1389 */
1390 public void setVisiblePasswordEnabled(boolean enabled, int userId) {
1391 // Update for crypto if owner
Xiaohui Chen86c69dd2015-08-27 15:44:02 -07001392 if (userId != UserHandle.USER_SYSTEM) {
Paul Lawrenced8fdb332015-05-18 13:26:11 -07001393 return;
1394 }
1395
1396 IBinder service = ServiceManager.getService("mount");
1397 if (service == null) {
1398 Log.e(TAG, "Could not find the mount service to update the user info");
1399 return;
1400 }
1401
Sudheer Shanka2250d562016-11-07 15:41:02 -08001402 IStorageManager storageManager = IStorageManager.Stub.asInterface(service);
Paul Lawrenced8fdb332015-05-18 13:26:11 -07001403 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -08001404 storageManager.setField(StorageManager.PASSWORD_VISIBLE_KEY, enabled ? "1" : "0");
Paul Lawrenced8fdb332015-05-18 13:26:11 -07001405 } catch (RemoteException e) {
1406 Log.e(TAG, "Error changing password visible state", e);
1407 }
1408 }
1409
1410 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001411 * @return Whether tactile feedback for the pattern is enabled.
1412 */
1413 public boolean isTactileFeedbackEnabled() {
Jeff Sharkey5ed9d682012-10-10 14:28:27 -07001414 return Settings.System.getIntForUser(mContentResolver,
1415 Settings.System.HAPTIC_FEEDBACK_ENABLED, 1, UserHandle.USER_CURRENT) != 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001416 }
1417
1418 /**
1419 * Set and store the lockout deadline, meaning the user can't attempt his/her unlock
1420 * pattern until the deadline has passed.
1421 * @return the chosen deadline.
1422 */
Andres Morales23974272015-05-14 22:42:26 -07001423 public long setLockoutAttemptDeadline(int userId, int timeoutMs) {
1424 final long deadline = SystemClock.elapsedRealtime() + timeoutMs;
Adrian Roosb7d81d92017-08-08 13:08:01 +02001425 if (userId == USER_FRP) {
1426 // For secure password storage (that is required for FRP), the underlying storage also
1427 // enforces the deadline. Since we cannot store settings for the FRP user, don't.
1428 return deadline;
1429 }
Kevin Chyna3e55822017-10-04 15:47:24 -07001430 mLockoutDeadlines.put(userId, deadline);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001431 return deadline;
1432 }
1433
1434 /**
1435 * @return The elapsed time in millis in the future when the user is allowed to
1436 * attempt to enter his/her lock pattern, or 0 if the user is welcome to
1437 * enter a pattern.
1438 */
Adrian Roos8150d2a2015-04-16 17:11:20 -07001439 public long getLockoutAttemptDeadline(int userId) {
Kevin Chyna3e55822017-10-04 15:47:24 -07001440 final long deadline = mLockoutDeadlines.get(userId, 0L);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001441 final long now = SystemClock.elapsedRealtime();
Jorim Jaggie3e6d562015-09-28 13:57:37 -07001442 if (deadline < now && deadline != 0) {
Andres Moralesa4e23372015-09-08 13:17:37 -07001443 // timeout expired
Kevin Chyna3e55822017-10-04 15:47:24 -07001444 mLockoutDeadlines.put(userId, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001445 return 0L;
1446 }
1447 return deadline;
1448 }
1449
Jim Millerf45bb402013-08-20 18:58:32 -07001450 private boolean getBoolean(String secureSettingKey, boolean defaultValue, int userId) {
Amith Yamasani52c489c2012-03-28 11:42:42 -07001451 try {
Jim Millerf45bb402013-08-20 18:58:32 -07001452 return getLockSettings().getBoolean(secureSettingKey, defaultValue, userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -07001453 } catch (RemoteException re) {
1454 return defaultValue;
1455 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001456 }
1457
Jim Millerf45bb402013-08-20 18:58:32 -07001458 private void setBoolean(String secureSettingKey, boolean enabled, int userId) {
Amith Yamasani52c489c2012-03-28 11:42:42 -07001459 try {
Jim Millerf45bb402013-08-20 18:58:32 -07001460 getLockSettings().setBoolean(secureSettingKey, enabled, userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -07001461 } catch (RemoteException re) {
1462 // What can we do?
1463 Log.e(TAG, "Couldn't write boolean " + secureSettingKey + re);
1464 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001465 }
1466
Geoffrey Borggaard987672d22014-07-18 16:47:18 -04001467 private long getLong(String secureSettingKey, long defaultValue, int userHandle) {
1468 try {
1469 return getLockSettings().getLong(secureSettingKey, defaultValue, userHandle);
1470 } catch (RemoteException re) {
1471 return defaultValue;
1472 }
1473 }
1474
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001475 private void setLong(String secureSettingKey, long value, int userHandle) {
Amith Yamasani52c489c2012-03-28 11:42:42 -07001476 try {
Kenny Guy0cf13702013-11-29 16:33:05 +00001477 getLockSettings().setLong(secureSettingKey, value, userHandle);
Amith Yamasani52c489c2012-03-28 11:42:42 -07001478 } catch (RemoteException re) {
1479 // What can we do?
1480 Log.e(TAG, "Couldn't write long " + secureSettingKey + re);
1481 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001482 }
1483
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001484 private String getString(String secureSettingKey, int userHandle) {
Amith Yamasani52c489c2012-03-28 11:42:42 -07001485 try {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001486 return getLockSettings().getString(secureSettingKey, null, userHandle);
Amith Yamasani52c489c2012-03-28 11:42:42 -07001487 } catch (RemoteException re) {
1488 return null;
1489 }
Konstantin Lopyrev863f22d2010-05-12 17:16:58 -07001490 }
1491
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001492 private void setString(String secureSettingKey, String value, int userHandle) {
Amith Yamasani52c489c2012-03-28 11:42:42 -07001493 try {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001494 getLockSettings().setString(secureSettingKey, value, userHandle);
Amith Yamasani52c489c2012-03-28 11:42:42 -07001495 } catch (RemoteException re) {
1496 // What can we do?
1497 Log.e(TAG, "Couldn't write string " + secureSettingKey + re);
1498 }
Konstantin Lopyrev863f22d2010-05-12 17:16:58 -07001499 }
1500
Adrian Roos8150d2a2015-04-16 17:11:20 -07001501 public void setPowerButtonInstantlyLocks(boolean enabled, int userId) {
1502 setBoolean(LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS, enabled, userId);
Jim Millera4edd152012-01-06 18:24:04 -08001503 }
1504
Adrian Roos8150d2a2015-04-16 17:11:20 -07001505 public boolean getPowerButtonInstantlyLocks(int userId) {
1506 return getBoolean(LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS, true, userId);
Adrian Roos82142c22014-03-27 14:56:59 +01001507 }
1508
Bryan Mawhinneye483b562017-05-15 14:46:05 +01001509 public boolean isPowerButtonInstantlyLocksEverChosen(int userId) {
1510 return getString(LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS, userId) != null;
1511 }
1512
Adrian Roos82142c22014-03-27 14:56:59 +01001513 public void setEnabledTrustAgents(Collection<ComponentName> activeTrustAgents, int userId) {
1514 StringBuilder sb = new StringBuilder();
1515 for (ComponentName cn : activeTrustAgents) {
1516 if (sb.length() > 0) {
1517 sb.append(',');
1518 }
1519 sb.append(cn.flattenToShortString());
1520 }
1521 setString(ENABLED_TRUST_AGENTS, sb.toString(), userId);
Adrian Roos8150d2a2015-04-16 17:11:20 -07001522 getTrustManager().reportEnabledTrustAgentsChanged(userId);
Adrian Roos82142c22014-03-27 14:56:59 +01001523 }
1524
1525 public List<ComponentName> getEnabledTrustAgents(int userId) {
1526 String serialized = getString(ENABLED_TRUST_AGENTS, userId);
1527 if (TextUtils.isEmpty(serialized)) {
1528 return null;
1529 }
1530 String[] split = serialized.split(",");
1531 ArrayList<ComponentName> activeTrustAgents = new ArrayList<ComponentName>(split.length);
1532 for (String s : split) {
1533 if (!TextUtils.isEmpty(s)) {
1534 activeTrustAgents.add(ComponentName.unflattenFromString(s));
1535 }
1536 }
1537 return activeTrustAgents;
1538 }
Adrian Roos2c12cfa2014-06-25 23:28:53 +02001539
1540 /**
Adrian Roosb5e47222015-08-14 15:53:06 -07001541 * Disable trust until credentials have been entered for user {@param userId}.
1542 *
1543 * Requires the {@link android.Manifest.permission#ACCESS_KEYGUARD_SECURE_STORAGE} permission.
1544 *
1545 * @param userId either an explicit user id or {@link android.os.UserHandle#USER_ALL}
Adrian Roos2c12cfa2014-06-25 23:28:53 +02001546 */
1547 public void requireCredentialEntry(int userId) {
Jorim Jaggi16093fe32015-09-09 23:29:17 +00001548 requireStrongAuth(StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST, userId);
Adrian Roosb5e47222015-08-14 15:53:06 -07001549 }
1550
1551 /**
1552 * Requests strong authentication for user {@param userId}.
1553 *
1554 * Requires the {@link android.Manifest.permission#ACCESS_KEYGUARD_SECURE_STORAGE} permission.
1555 *
1556 * @param strongAuthReason a combination of {@link StrongAuthTracker.StrongAuthFlags} indicating
1557 * the reason for and the strength of the requested authentication.
1558 * @param userId either an explicit user id or {@link android.os.UserHandle#USER_ALL}
1559 */
1560 public void requireStrongAuth(@StrongAuthTracker.StrongAuthFlags int strongAuthReason,
1561 int userId) {
1562 try {
1563 getLockSettings().requireStrongAuth(strongAuthReason, userId);
1564 } catch (RemoteException e) {
1565 Log.e(TAG, "Error while requesting strong auth: " + e);
1566 }
Adrian Roos2c12cfa2014-06-25 23:28:53 +02001567 }
Adrian Roos4b9e3242014-08-20 23:36:25 +02001568
Adrian Roosf8f56bc2014-11-20 23:55:34 +01001569 private void onAfterChangingPassword(int userHandle) {
1570 getTrustManager().reportEnabledTrustAgentsChanged(userHandle);
Adrian Roos4b9e3242014-08-20 23:36:25 +02001571 }
Jim Millerdd5de712014-10-16 19:50:18 -07001572
1573 public boolean isCredentialRequiredToDecrypt(boolean defaultValue) {
1574 final int value = Settings.Global.getInt(mContentResolver,
1575 Settings.Global.REQUIRE_PASSWORD_TO_DECRYPT, -1);
1576 return value == -1 ? defaultValue : (value != 0);
1577 }
1578
1579 public void setCredentialRequiredToDecrypt(boolean required) {
Robin Leed39113e2016-01-22 15:44:49 +00001580 if (!(getUserManager().isSystemUser() || getUserManager().isPrimaryUser())) {
1581 throw new IllegalStateException(
1582 "Only the system or primary user may call setCredentialRequiredForDecrypt()");
Jim Millerdd5de712014-10-16 19:50:18 -07001583 }
Paul Lawrence688af6c2015-05-15 11:26:17 -07001584
1585 if (isDeviceEncryptionEnabled()){
1586 Settings.Global.putInt(mContext.getContentResolver(),
1587 Settings.Global.REQUIRE_PASSWORD_TO_DECRYPT, required ? 1 : 0);
1588 }
Jim Millerdd5de712014-10-16 19:50:18 -07001589 }
Andrei Kapishnikov4eb6a362015-04-02 15:21:20 -04001590
1591 private boolean isDoNotAskCredentialsOnBootSet() {
Rubin Xu4929a5d2017-01-23 23:55:28 +00001592 return getDevicePolicyManager().getDoNotAskCredentialsOnBoot();
Andrei Kapishnikov4eb6a362015-04-02 15:21:20 -04001593 }
1594
1595 private boolean shouldEncryptWithCredentials(boolean defaultValue) {
1596 return isCredentialRequiredToDecrypt(defaultValue) && !isDoNotAskCredentialsOnBootSet();
1597 }
Xiyuan Xiaaa262942015-05-05 15:18:45 -07001598
1599 private void throwIfCalledOnMainThread() {
1600 if (Looper.getMainLooper().isCurrentThread()) {
1601 throw new IllegalStateException("should not be called from the main thread.");
1602 }
1603 }
Adrian Roosb5e47222015-08-14 15:53:06 -07001604
1605 public void registerStrongAuthTracker(final StrongAuthTracker strongAuthTracker) {
1606 try {
1607 getLockSettings().registerStrongAuthTracker(strongAuthTracker.mStub);
1608 } catch (RemoteException e) {
1609 throw new RuntimeException("Could not register StrongAuthTracker");
1610 }
1611 }
1612
1613 public void unregisterStrongAuthTracker(final StrongAuthTracker strongAuthTracker) {
1614 try {
1615 getLockSettings().unregisterStrongAuthTracker(strongAuthTracker.mStub);
1616 } catch (RemoteException e) {
1617 Log.e(TAG, "Could not unregister StrongAuthTracker", e);
1618 }
1619 }
1620
1621 /**
Victor Changa0940d32016-05-16 19:36:08 +01001622 * @see StrongAuthTracker#getStrongAuthForUser
1623 */
1624 public int getStrongAuthForUser(int userId) {
1625 try {
1626 return getLockSettings().getStrongAuthForUser(userId);
1627 } catch (RemoteException e) {
1628 Log.e(TAG, "Could not get StrongAuth", e);
1629 return StrongAuthTracker.getDefaultFlags(mContext);
1630 }
1631 }
1632
1633 /**
1634 * @see StrongAuthTracker#isTrustAllowedForUser
1635 */
1636 public boolean isTrustAllowedForUser(int userId) {
1637 return getStrongAuthForUser(userId) == StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED;
1638 }
1639
1640 /**
1641 * @see StrongAuthTracker#isFingerprintAllowedForUser
1642 */
Kevin Chynb17d4092018-10-01 19:07:03 -07001643 public boolean isBiometricAllowedForUser(int userId) {
Gilad Brettercb51b8b2018-03-22 17:04:51 +02001644 return (getStrongAuthForUser(userId) & ~StrongAuthTracker.ALLOWING_BIOMETRIC) == 0;
Victor Changa0940d32016-05-16 19:36:08 +01001645 }
1646
Chad Brubakerea8c5ef2018-03-15 16:37:43 -07001647 public boolean isUserInLockdown(int userId) {
1648 return getStrongAuthForUser(userId)
1649 == StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN;
1650 }
1651
Jorim Jaggie8fde5d2016-06-30 23:41:37 -07001652 private ICheckCredentialProgressCallback wrapCallback(
1653 final CheckCredentialProgressCallback callback) {
1654 if (callback == null) {
1655 return null;
1656 } else {
Adrian Roos7a3bf7c2016-07-12 15:31:55 -07001657 if (mHandler == null) {
1658 throw new IllegalStateException("Must construct LockPatternUtils on a looper thread"
1659 + " to use progress callbacks.");
1660 }
Jorim Jaggie8fde5d2016-06-30 23:41:37 -07001661 return new ICheckCredentialProgressCallback.Stub() {
1662
1663 @Override
1664 public void onCredentialVerified() throws RemoteException {
1665 mHandler.post(callback::onEarlyMatched);
1666 }
1667 };
1668 }
1669 }
1670
Rubin Xufcd49f92017-08-24 18:21:52 +01001671 private LockSettingsInternal getLockSettingsInternal() {
1672 LockSettingsInternal service = LocalServices.getService(LockSettingsInternal.class);
1673 if (service == null) {
1674 throw new SecurityException("Only available to system server itself");
1675 }
1676 return service;
1677 }
Jorim Jaggie8fde5d2016-06-30 23:41:37 -07001678 /**
Rubin Xuf095f832017-01-31 15:23:34 +00001679 * Create an escrow token for the current user, which can later be used to unlock FBE
1680 * or change user password.
1681 *
1682 * After adding, if the user currently has lockscreen password, he will need to perform a
1683 * confirm credential operation in order to activate the token for future use. If the user
1684 * has no secure lockscreen, then the token is activated immediately.
1685 *
Rubin Xufcd49f92017-08-24 18:21:52 +01001686 * <p>This method is only available to code running in the system server process itself.
1687 *
Rubin Xuf095f832017-01-31 15:23:34 +00001688 * @return a unique 64-bit token handle which is needed to refer to this token later.
1689 */
Ram Periathiruvadi32d53552019-02-19 13:25:46 -08001690 public long addEscrowToken(byte[] token, int userId,
1691 @Nullable EscrowTokenStateChangeCallback callback) {
1692 return getLockSettingsInternal().addEscrowToken(token, userId, callback);
1693 }
1694
1695 /**
1696 * Callback interface to notify when an added escrow token has been activated.
1697 */
1698 public interface EscrowTokenStateChangeCallback {
1699 /**
1700 * The method to be called when the token is activated.
1701 * @param handle 64 bit handle corresponding to the escrow token
1702 * @param userid user for whom the escrow token has been added
1703 */
1704 void onEscrowTokenActivated(long handle, int userid);
Rubin Xuf095f832017-01-31 15:23:34 +00001705 }
1706
1707 /**
1708 * Remove an escrow token.
Rubin Xufcd49f92017-08-24 18:21:52 +01001709 *
1710 * <p>This method is only available to code running in the system server process itself.
1711 *
Rubin Xuf095f832017-01-31 15:23:34 +00001712 * @return true if the given handle refers to a valid token previously returned from
1713 * {@link #addEscrowToken}, whether it's active or not. return false otherwise.
1714 */
1715 public boolean removeEscrowToken(long handle, int userId) {
Rubin Xufcd49f92017-08-24 18:21:52 +01001716 return getLockSettingsInternal().removeEscrowToken(handle, userId);
Rubin Xuf095f832017-01-31 15:23:34 +00001717 }
1718
1719 /**
1720 * Check if the given escrow token is active or not. Only active token can be used to call
1721 * {@link #setLockCredentialWithToken} and {@link #unlockUserWithToken}
Rubin Xufcd49f92017-08-24 18:21:52 +01001722 *
1723 * <p>This method is only available to code running in the system server process itself.
Rubin Xuf095f832017-01-31 15:23:34 +00001724 */
1725 public boolean isEscrowTokenActive(long handle, int userId) {
Rubin Xufcd49f92017-08-24 18:21:52 +01001726 return getLockSettingsInternal().isEscrowTokenActive(handle, userId);
Rubin Xuf095f832017-01-31 15:23:34 +00001727 }
1728
Rubin Xu7cf45092017-08-28 11:47:35 +01001729 /**
1730 * Change a user's lock credential with a pre-configured escrow token.
1731 *
Rubin Xufcd49f92017-08-24 18:21:52 +01001732 * <p>This method is only available to code running in the system server process itself.
1733 *
Rubin Xu7cf45092017-08-28 11:47:35 +01001734 * @param credential The new credential to be set
1735 * @param type Credential type: password / pattern / none.
1736 * @param requestedQuality the requested password quality by DevicePolicyManager.
1737 * See {@link DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
1738 * @param tokenHandle Handle of the escrow token
1739 * @param token Escrow token
1740 * @param userId The user who's lock credential to be changed
1741 * @return {@code true} if the operation is successful.
1742 */
Rich Canningsf64ec632019-02-21 12:40:36 -08001743 public boolean setLockCredentialWithToken(byte[] credential, int type, int requestedQuality,
Rubin Xu7cf45092017-08-28 11:47:35 +01001744 long tokenHandle, byte[] token, int userId) {
Lenka Trochtova66c492a2018-12-06 11:29:21 +01001745 if (!hasSecureLockScreen()) {
1746 throw new UnsupportedOperationException(
1747 "This operation requires the lock screen feature.");
1748 }
Rubin Xufcd49f92017-08-24 18:21:52 +01001749 LockSettingsInternal localService = getLockSettingsInternal();
1750 if (type != CREDENTIAL_TYPE_NONE) {
Rich Canningsf64ec632019-02-21 12:40:36 -08001751 if (credential == null || credential.length < MIN_LOCK_PASSWORD_SIZE) {
Rubin Xufcd49f92017-08-24 18:21:52 +01001752 throw new IllegalArgumentException("password must not be null and at least "
1753 + "of length " + MIN_LOCK_PASSWORD_SIZE);
Rubin Xuf095f832017-01-31 15:23:34 +00001754 }
Rubin Xufcd49f92017-08-24 18:21:52 +01001755 final int quality = computePasswordQuality(type, credential, requestedQuality);
Rich Canningsf64ec632019-02-21 12:40:36 -08001756 if (!localService.setLockCredentialWithToken(credential, type, tokenHandle, token,
1757 quality, userId)) {
Rubin Xufcd49f92017-08-24 18:21:52 +01001758 return false;
1759 }
Rubin Xu682d1672018-03-21 09:13:44 +00001760 setKeyguardStoredPasswordQuality(quality, userId);
Rubin Xufcd49f92017-08-24 18:21:52 +01001761
1762 updateEncryptionPasswordIfNeeded(credential, quality, userId);
1763 updatePasswordHistory(credential, userId);
Rubin Xuf01e9072018-03-30 20:59:28 +01001764 onAfterChangingPassword(userId);
Rubin Xufcd49f92017-08-24 18:21:52 +01001765 } else {
Rich Canningsf64ec632019-02-21 12:40:36 -08001766 if (!(credential == null || credential.length == 0)) {
Rubin Xufcd49f92017-08-24 18:21:52 +01001767 throw new IllegalArgumentException("password must be emtpy for NONE type");
1768 }
Rich Canningsf64ec632019-02-21 12:40:36 -08001769 if (!localService.setLockCredentialWithToken(null, CREDENTIAL_TYPE_NONE, tokenHandle,
1770 token, PASSWORD_QUALITY_UNSPECIFIED, userId)) {
Rubin Xufcd49f92017-08-24 18:21:52 +01001771 return false;
1772 }
Rubin Xu682d1672018-03-21 09:13:44 +00001773 setKeyguardStoredPasswordQuality(PASSWORD_QUALITY_UNSPECIFIED, userId);
Rubin Xufcd49f92017-08-24 18:21:52 +01001774
1775 if (userId == UserHandle.USER_SYSTEM) {
1776 // Set the encryption password to default.
1777 updateEncryptionPassword(StorageManager.CRYPT_TYPE_DEFAULT, null);
1778 setCredentialRequiredToDecrypt(false);
1779 }
Rubin Xuf095f832017-01-31 15:23:34 +00001780 }
Rubin Xufcd49f92017-08-24 18:21:52 +01001781 onAfterChangingPassword(userId);
1782 return true;
Rubin Xuf095f832017-01-31 15:23:34 +00001783 }
1784
Rubin Xufcd49f92017-08-24 18:21:52 +01001785 /**
1786 * Unlock the specified user by an pre-activated escrow token. This should have the same effect
1787 * on device encryption as the user entering his lockscreen credentials for the first time after
1788 * boot, this includes unlocking the user's credential-encrypted storage as well as the keystore
1789 *
1790 * <p>This method is only available to code running in the system server process itself.
1791 *
1792 * @return {@code true} if the supplied token is valid and unlock succeeds,
1793 * {@code false} otherwise.
1794 */
1795 public boolean unlockUserWithToken(long tokenHandle, byte[] token, int userId) {
1796 return getLockSettingsInternal().unlockUserWithToken(tokenHandle, token, userId);
Rubin Xuf095f832017-01-31 15:23:34 +00001797 }
1798
1799
1800 /**
Jorim Jaggie8fde5d2016-06-30 23:41:37 -07001801 * Callback to be notified about progress when checking credentials.
1802 */
1803 public interface CheckCredentialProgressCallback {
1804
1805 /**
1806 * Called as soon as possible when we know that the credentials match but the user hasn't
1807 * been fully unlocked.
1808 */
1809 void onEarlyMatched();
1810 }
1811
Victor Changa0940d32016-05-16 19:36:08 +01001812 /**
Adrian Roosb5e47222015-08-14 15:53:06 -07001813 * Tracks the global strong authentication state.
1814 */
1815 public static class StrongAuthTracker {
1816
1817 @IntDef(flag = true,
1818 value = { STRONG_AUTH_NOT_REQUIRED,
1819 STRONG_AUTH_REQUIRED_AFTER_BOOT,
1820 STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW,
Adrian Roos9d6fc922016-08-10 17:09:55 -07001821 SOME_AUTH_REQUIRED_AFTER_USER_REQUEST,
Michal Karpinskic52f8672016-11-18 11:32:45 +00001822 STRONG_AUTH_REQUIRED_AFTER_LOCKOUT,
Chad Brubaker4f28f0d2017-09-07 14:28:13 -07001823 STRONG_AUTH_REQUIRED_AFTER_TIMEOUT,
1824 STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN})
Adrian Roosb5e47222015-08-14 15:53:06 -07001825 @Retention(RetentionPolicy.SOURCE)
1826 public @interface StrongAuthFlags {}
1827
1828 /**
1829 * Strong authentication is not required.
1830 */
1831 public static final int STRONG_AUTH_NOT_REQUIRED = 0x0;
1832
1833 /**
1834 * Strong authentication is required because the user has not authenticated since boot.
1835 */
1836 public static final int STRONG_AUTH_REQUIRED_AFTER_BOOT = 0x1;
1837
1838 /**
Jorim Jaggi16093fe32015-09-09 23:29:17 +00001839 * Strong authentication is required because a device admin has requested it.
Adrian Roosb5e47222015-08-14 15:53:06 -07001840 */
1841 public static final int STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW = 0x2;
1842
1843 /**
Jorim Jaggi16093fe32015-09-09 23:29:17 +00001844 * Some authentication is required because the user has temporarily disabled trust.
Adrian Roosb5e47222015-08-14 15:53:06 -07001845 */
Jorim Jaggi16093fe32015-09-09 23:29:17 +00001846 public static final int SOME_AUTH_REQUIRED_AFTER_USER_REQUEST = 0x4;
Adrian Roosb5e47222015-08-14 15:53:06 -07001847
Adrian Roos873010d2015-08-25 15:59:00 -07001848 /**
1849 * Strong authentication is required because the user has been locked out after too many
1850 * attempts.
1851 */
1852 public static final int STRONG_AUTH_REQUIRED_AFTER_LOCKOUT = 0x8;
1853
Adrian Roosaf4ab3e2015-09-02 13:23:30 -07001854 /**
Michal Karpinskic52f8672016-11-18 11:32:45 +00001855 * Strong authentication is required because it hasn't been used for a time required by
1856 * a device admin.
1857 */
1858 public static final int STRONG_AUTH_REQUIRED_AFTER_TIMEOUT = 0x10;
1859
1860 /**
Chad Brubaker4f28f0d2017-09-07 14:28:13 -07001861 * Strong authentication is required because the user has triggered lockdown.
1862 */
1863 public static final int STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN = 0x20;
1864
1865 /**
Gilad Brettercb51b8b2018-03-22 17:04:51 +02001866 * Strong auth flags that do not prevent biometric methods from being accepted as auth.
1867 * If any other flags are set, biometric authentication is disabled.
Adrian Roosaf4ab3e2015-09-02 13:23:30 -07001868 */
Gilad Brettercb51b8b2018-03-22 17:04:51 +02001869 private static final int ALLOWING_BIOMETRIC = STRONG_AUTH_NOT_REQUIRED
Adrian Roos9d6fc922016-08-10 17:09:55 -07001870 | SOME_AUTH_REQUIRED_AFTER_USER_REQUEST;
Adrian Roosb5e47222015-08-14 15:53:06 -07001871
Adrian Roosaf4ab3e2015-09-02 13:23:30 -07001872 private final SparseIntArray mStrongAuthRequiredForUser = new SparseIntArray();
Adrian Roosb5e47222015-08-14 15:53:06 -07001873 private final H mHandler;
Rakesh Iyera7aa4d62016-01-19 17:27:23 -08001874 private final int mDefaultStrongAuthFlags;
Adrian Roosb5e47222015-08-14 15:53:06 -07001875
Rakesh Iyera7aa4d62016-01-19 17:27:23 -08001876 public StrongAuthTracker(Context context) {
1877 this(context, Looper.myLooper());
Adrian Roosb5e47222015-08-14 15:53:06 -07001878 }
1879
1880 /**
1881 * @param looper the looper on whose thread calls to {@link #onStrongAuthRequiredChanged}
1882 * will be scheduled.
Rakesh Iyera7aa4d62016-01-19 17:27:23 -08001883 * @param context the current {@link Context}
Adrian Roosb5e47222015-08-14 15:53:06 -07001884 */
Rakesh Iyera7aa4d62016-01-19 17:27:23 -08001885 public StrongAuthTracker(Context context, Looper looper) {
Adrian Roosb5e47222015-08-14 15:53:06 -07001886 mHandler = new H(looper);
Rakesh Iyera7aa4d62016-01-19 17:27:23 -08001887 mDefaultStrongAuthFlags = getDefaultFlags(context);
1888 }
1889
1890 public static @StrongAuthFlags int getDefaultFlags(Context context) {
1891 boolean strongAuthRequired = context.getResources().getBoolean(
1892 com.android.internal.R.bool.config_strongAuthRequiredOnBoot);
1893 return strongAuthRequired ? STRONG_AUTH_REQUIRED_AFTER_BOOT : STRONG_AUTH_NOT_REQUIRED;
Adrian Roosb5e47222015-08-14 15:53:06 -07001894 }
1895
1896 /**
1897 * Returns {@link #STRONG_AUTH_NOT_REQUIRED} if strong authentication is not required,
1898 * otherwise returns a combination of {@link StrongAuthFlags} indicating why strong
1899 * authentication is required.
1900 *
1901 * @param userId the user for whom the state is queried.
1902 */
1903 public @StrongAuthFlags int getStrongAuthForUser(int userId) {
Rakesh Iyera7aa4d62016-01-19 17:27:23 -08001904 return mStrongAuthRequiredForUser.get(userId, mDefaultStrongAuthFlags);
Adrian Roosb5e47222015-08-14 15:53:06 -07001905 }
1906
1907 /**
1908 * @return true if unlocking with trust alone is allowed for {@param userId} by the current
1909 * strong authentication requirements.
1910 */
1911 public boolean isTrustAllowedForUser(int userId) {
1912 return getStrongAuthForUser(userId) == STRONG_AUTH_NOT_REQUIRED;
1913 }
1914
1915 /**
Gilad Brettercb51b8b2018-03-22 17:04:51 +02001916 * @return true if unlocking with a biometric method alone is allowed for {@param userId}
1917 * by the current strong authentication requirements.
Adrian Roosb5e47222015-08-14 15:53:06 -07001918 */
Gilad Brettercb51b8b2018-03-22 17:04:51 +02001919 public boolean isBiometricAllowedForUser(int userId) {
1920 return (getStrongAuthForUser(userId) & ~ALLOWING_BIOMETRIC) == 0;
Adrian Roosb5e47222015-08-14 15:53:06 -07001921 }
1922
1923 /**
1924 * Called when the strong authentication requirements for {@param userId} changed.
1925 */
1926 public void onStrongAuthRequiredChanged(int userId) {
1927 }
1928
Victor Changa0940d32016-05-16 19:36:08 +01001929 protected void handleStrongAuthRequiredChanged(@StrongAuthFlags int strongAuthFlags,
Adrian Roosb5e47222015-08-14 15:53:06 -07001930 int userId) {
Adrian Roosb5e47222015-08-14 15:53:06 -07001931 int oldValue = getStrongAuthForUser(userId);
1932 if (strongAuthFlags != oldValue) {
Rakesh Iyera7aa4d62016-01-19 17:27:23 -08001933 if (strongAuthFlags == mDefaultStrongAuthFlags) {
Adrian Roosb5e47222015-08-14 15:53:06 -07001934 mStrongAuthRequiredForUser.delete(userId);
1935 } else {
1936 mStrongAuthRequiredForUser.put(userId, strongAuthFlags);
1937 }
1938 onStrongAuthRequiredChanged(userId);
1939 }
1940 }
1941
1942
Victor Changa0940d32016-05-16 19:36:08 +01001943 protected final IStrongAuthTracker.Stub mStub = new IStrongAuthTracker.Stub() {
Adrian Roosb5e47222015-08-14 15:53:06 -07001944 @Override
1945 public void onStrongAuthRequiredChanged(@StrongAuthFlags int strongAuthFlags,
1946 int userId) {
1947 mHandler.obtainMessage(H.MSG_ON_STRONG_AUTH_REQUIRED_CHANGED,
1948 strongAuthFlags, userId).sendToTarget();
1949 }
1950 };
1951
1952 private class H extends Handler {
1953 static final int MSG_ON_STRONG_AUTH_REQUIRED_CHANGED = 1;
1954
1955 public H(Looper looper) {
1956 super(looper);
1957 }
1958
1959 @Override
1960 public void handleMessage(Message msg) {
1961 switch (msg.what) {
1962 case MSG_ON_STRONG_AUTH_REQUIRED_CHANGED:
1963 handleStrongAuthRequiredChanged(msg.arg1, msg.arg2);
1964 break;
1965 }
1966 }
Rubin Xu3bf722a2016-12-15 16:07:38 +00001967 }
1968 }
1969
1970 public void enableSyntheticPassword() {
1971 setLong(SYNTHETIC_PASSWORD_ENABLED_KEY, 1L, UserHandle.USER_SYSTEM);
1972 }
1973
Paul Crowley7a0cc0a2017-05-31 22:12:57 +00001974 public void disableSyntheticPassword() {
1975 setLong(SYNTHETIC_PASSWORD_ENABLED_KEY, 0L, UserHandle.USER_SYSTEM);
1976 }
1977
Rubin Xu3bf722a2016-12-15 16:07:38 +00001978 public boolean isSyntheticPasswordEnabled() {
1979 return getLong(SYNTHETIC_PASSWORD_ENABLED_KEY, 0, UserHandle.USER_SYSTEM) != 0;
Adrian Roosb5e47222015-08-14 15:53:06 -07001980 }
Adrian Roos7374d3a2017-03-31 14:14:53 -07001981
Lenka Trochtova66c492a2018-12-06 11:29:21 +01001982 /**
1983 * Return true if the device supports the lock screen feature, false otherwise.
1984 */
1985 public boolean hasSecureLockScreen() {
1986 if (mHasSecureLockScreen == null) {
1987 mHasSecureLockScreen = Boolean.valueOf(mContext.getPackageManager()
1988 .hasSystemFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN));
1989 }
1990 return mHasSecureLockScreen.booleanValue();
1991 }
1992
Adrian Roos2adc2632017-09-05 17:01:42 +02001993 public static boolean userOwnsFrpCredential(Context context, UserInfo info) {
1994 return info != null && info.isPrimary() && info.isAdmin() && frpCredentialEnabled(context);
Adrian Roos7374d3a2017-03-31 14:14:53 -07001995 }
1996
Adrian Roos2adc2632017-09-05 17:01:42 +02001997 public static boolean frpCredentialEnabled(Context context) {
1998 return FRP_CREDENTIAL_ENABLED && context.getResources().getBoolean(
1999 com.android.internal.R.bool.config_enableCredentialFactoryResetProtection);
Adrian Roos7374d3a2017-03-31 14:14:53 -07002000 }
Rich Canningsf64ec632019-02-21 12:40:36 -08002001
2002 /**
2003 * Converts a CharSequence to a byte array without requiring a toString(), which creates an
2004 * additional copy.
2005 *
2006 * @param chars The CharSequence to convert
2007 * @return A byte array representing the input
2008 */
2009 public static byte[] charSequenceToByteArray(CharSequence chars) {
2010 if (chars == null) {
2011 return null;
2012 }
2013 byte[] bytes = new byte[chars.length()];
2014 for (int i = 0; i < chars.length(); i++) {
2015 bytes[i] = (byte) chars.charAt(i);
2016 }
2017 return bytes;
2018 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002019}