blob: d9b290267c96a16302024a4b0b487c4a40b1727d [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;
Rubin Xu682d1672018-03-21 09:13:44 +000020import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
21import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX;
22import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
23import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
24
Adrian Roosb5e47222015-08-14 15:53:06 -070025import android.annotation.IntDef;
Rubin Xua58125d2019-09-06 20:11:48 +010026import android.annotation.NonNull;
Jorim Jaggie8fde5d2016-06-30 23:41:37 -070027import android.annotation.Nullable;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -080028import android.app.admin.DevicePolicyManager;
Pavel Grafov6f334842019-08-06 14:37:06 +010029import android.app.admin.PasswordMetrics;
Adrian Roosb5e47222015-08-14 15:53:06 -070030import android.app.trust.IStrongAuthTracker;
Adrian Roos82142c22014-03-27 14:56:59 +010031import android.app.trust.TrustManager;
Artur Satayev00f8b532019-12-10 17:47:55 +000032import android.compat.annotation.UnsupportedAppUsage;
Adrian Roos82142c22014-03-27 14:56:59 +010033import android.content.ComponentName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034import android.content.ContentResolver;
Jim Miller31f90b62010-01-20 13:35:20 -080035import android.content.Context;
Clara Bayarria1771112015-12-18 16:29:18 +000036import android.content.pm.UserInfo;
Paul Lawrence3a5a0be2014-09-25 09:26:34 -070037import android.os.AsyncTask;
Adrian Roosb5e47222015-08-14 15:53:06 -070038import android.os.Handler;
Jason parksf7b3cd42011-01-27 09:28:25 -060039import android.os.IBinder;
Xiyuan Xiaaa262942015-05-05 15:18:45 -070040import android.os.Looper;
Adrian Roosb5e47222015-08-14 15:53:06 -070041import android.os.Message;
Jim Miller69ac9882010-02-24 15:35:05 -080042import android.os.RemoteException;
43import android.os.ServiceManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080044import android.os.SystemClock;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -070045import android.os.UserHandle;
Clara Bayarria1771112015-12-18 16:29:18 +000046import android.os.UserManager;
Sudheer Shanka2250d562016-11-07 15:41:02 -080047import android.os.storage.IStorageManager;
Paul Lawrence8e397362014-01-27 15:22:30 -080048import android.os.storage.StorageManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080049import android.provider.Settings;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080050import android.text.TextUtils;
51import android.util.Log;
Haining Chenc06c4812020-01-13 20:38:53 -080052import android.util.SparseBooleanArray;
Adrian Roosb5e47222015-08-14 15:53:06 -070053import android.util.SparseIntArray;
Kevin Chyna3e55822017-10-04 15:47:24 -070054import android.util.SparseLongArray;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080055
Rubin Xu0cbc19e2016-12-09 14:00:21 +000056import com.android.internal.annotations.VisibleForTesting;
Rubin Xufcd49f92017-08-24 18:21:52 +010057import com.android.server.LocalServices;
Kevin Chynb17d4092018-10-01 19:07:03 -070058
Artur Satayev00f8b532019-12-10 17:47:55 +000059import com.google.android.collect.Lists;
60
Rubin Xua3c71a12019-12-04 15:25:02 +000061import libcore.util.HexEncoding;
62
Adrian Roosb5e47222015-08-14 15:53:06 -070063import java.lang.annotation.Retention;
64import java.lang.annotation.RetentionPolicy;
Brian Carlstrom929a1c22011-02-01 21:54:09 -080065import java.security.MessageDigest;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080066import java.security.NoSuchAlgorithmException;
Jim Miller11b019d2010-01-20 16:34:45 -080067import java.security.SecureRandom;
Adrian Roos82142c22014-03-27 14:56:59 +010068import java.util.ArrayList;
Rich Canningsf64ec632019-02-21 12:40:36 -080069import java.util.Arrays;
Adrian Roos82142c22014-03-27 14:56:59 +010070import java.util.Collection;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080071import java.util.List;
Rubin Xuf01e9072018-03-30 20:59:28 +010072import java.util.StringJoiner;
Kevin Chynb17d4092018-10-01 19:07:03 -070073
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080074/**
Brian Carlstrom5cfee3f2011-05-31 01:00:15 -070075 * Utilities for the lock pattern and its settings.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080076 */
77public class LockPatternUtils {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080078 private static final String TAG = "LockPatternUtils";
Adrian Roos8370e472017-07-23 14:35:59 +020079 private static final boolean FRP_CREDENTIAL_ENABLED = true;
Jim Miller69aa4a92009-12-22 19:03:28 -080080
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080081 /**
Rubin Xu1de89b32016-11-30 20:03:13 +000082 * The key to identify when the lock pattern enabled flag is being accessed for legacy reasons.
Bryce Lee46145962015-12-14 14:39:10 -080083 */
84 public static final String LEGACY_LOCK_PATTERN_ENABLED = "legacy_lock_pattern_enabled";
85
86 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080087 * The interval of the countdown for showing progress of the lockout.
88 */
89 public static final long FAILED_ATTEMPT_COUNTDOWN_INTERVAL_MS = 1000L;
90
Jim Miller4f369952011-08-19 18:29:22 -070091 /**
92 * This dictates when we start telling the user that continued failed attempts will wipe
93 * their device.
94 */
95 public static final int FAILED_ATTEMPTS_BEFORE_WIPE_GRACE = 5;
96
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080097 /**
98 * The minimum number of dots in a valid pattern.
99 */
100 public static final int MIN_LOCK_PATTERN_SIZE = 4;
101
102 /**
Adrian Roosf80e66ce92015-01-15 23:27:24 +0100103 * The minimum size of a valid password.
104 */
105 public static final int MIN_LOCK_PASSWORD_SIZE = 4;
106
107 /**
Pavel Grafov19a4fb32019-03-15 12:55:12 +0000108 * The minimum number of dots the user must include in a wrong pattern attempt for it to be
109 * counted.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800110 */
Jim Miller4f369952011-08-19 18:29:22 -0700111 public static final int MIN_PATTERN_REGISTER_FAIL = MIN_LOCK_PATTERN_SIZE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800112
Pavel Grafov6f334842019-08-06 14:37:06 +0100113 // NOTE: When modifying this, make sure credential sufficiency validation logic is intact.
Rubin Xu1de89b32016-11-30 20:03:13 +0000114 public static final int CREDENTIAL_TYPE_NONE = -1;
Rubin Xu1de89b32016-11-30 20:03:13 +0000115 public static final int CREDENTIAL_TYPE_PATTERN = 1;
Rubin Xu5e891bc2019-10-14 10:22:23 +0100116 // This is the legacy value persisted on disk. Never return it to clients, but internally
117 // we still need it to handle upgrade cases.
118 public static final int CREDENTIAL_TYPE_PASSWORD_OR_PIN = 2;
119 public static final int CREDENTIAL_TYPE_PIN = 3;
120 public static final int CREDENTIAL_TYPE_PASSWORD = 4;
Rubin Xu1de89b32016-11-30 20:03:13 +0000121
Pavel Grafov19a4fb32019-03-15 12:55:12 +0000122 @Retention(RetentionPolicy.SOURCE)
123 @IntDef(prefix = {"CREDENTIAL_TYPE_"}, value = {
124 CREDENTIAL_TYPE_NONE,
125 CREDENTIAL_TYPE_PATTERN,
Rubin Xu5e891bc2019-10-14 10:22:23 +0100126 CREDENTIAL_TYPE_PASSWORD,
127 CREDENTIAL_TYPE_PIN,
128 // CREDENTIAL_TYPE_PASSWORD_OR_PIN is missing on purpose.
Pavel Grafov19a4fb32019-03-15 12:55:12 +0000129 })
130 public @interface CredentialType {}
131
Adrian Roos7374d3a2017-03-31 14:14:53 -0700132 /**
133 * Special user id for triggering the FRP verification flow.
134 */
135 public static final int USER_FRP = UserHandle.USER_NULL + 1;
136
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100137 @Deprecated
Jeff Sharkey7a96c392012-11-15 14:01:46 -0800138 public final static String LOCKOUT_PERMANENT_KEY = "lockscreen.lockedoutpermanently";
Jeff Sharkey7a96c392012-11-15 14:01:46 -0800139 public final static String PATTERN_EVER_CHOSEN_KEY = "lockscreen.patterneverchosen";
Jim Miller69aa4a92009-12-22 19:03:28 -0800140 public final static String PASSWORD_TYPE_KEY = "lockscreen.password_type";
Adrian Roos230635e2015-01-07 20:50:29 +0100141 @Deprecated
142 public final static String PASSWORD_TYPE_ALTERNATE_KEY = "lockscreen.password_type_alternate";
Jeff Sharkey7a96c392012-11-15 14:01:46 -0800143 public final static String LOCK_PASSWORD_SALT_KEY = "lockscreen.password_salt";
144 public final static String DISABLE_LOCKSCREEN_KEY = "lockscreen.disabled";
145 public final static String LOCKSCREEN_OPTIONS = "lockscreen.options";
Adrian Roos230635e2015-01-07 20:50:29 +0100146 @Deprecated
Jim Miller6edf2632011-09-05 16:03:14 -0700147 public final static String LOCKSCREEN_BIOMETRIC_WEAK_FALLBACK
148 = "lockscreen.biometric_weak_fallback";
Adrian Roos230635e2015-01-07 20:50:29 +0100149 @Deprecated
Danielle Millett7a072192011-10-03 17:36:01 -0400150 public final static String BIOMETRIC_WEAK_EVER_CHOSEN_KEY
151 = "lockscreen.biometricweakeverchosen";
Jim Millera4edd152012-01-06 18:24:04 -0800152 public final static String LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS
153 = "lockscreen.power_button_instantly_locks";
Adrian Roos230635e2015-01-07 20:50:29 +0100154 @Deprecated
Jim Millerf45bb402013-08-20 18:58:32 -0700155 public final static String LOCKSCREEN_WIDGETS_ENABLED = "lockscreen.widgets_enabled";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800156
Jeff Sharkey7a96c392012-11-15 14:01:46 -0800157 public final static String PASSWORD_HISTORY_KEY = "lockscreen.passwordhistory";
Konstantin Lopyrev863f22d2010-05-12 17:16:58 -0700158
Jim Miller187ec582013-04-15 18:27:54 -0700159 private static final String LOCK_SCREEN_OWNER_INFO = Settings.Secure.LOCK_SCREEN_OWNER_INFO;
160 private static final String LOCK_SCREEN_OWNER_INFO_ENABLED =
161 Settings.Secure.LOCK_SCREEN_OWNER_INFO_ENABLED;
162
Andrei Stingaceanu6644cd92015-11-10 13:03:31 +0000163 private static final String LOCK_SCREEN_DEVICE_OWNER_INFO = "lockscreen.device_owner_info";
164
Adrian Roos82142c22014-03-27 14:56:59 +0100165 private static final String ENABLED_TRUST_AGENTS = "lockscreen.enabledtrustagents";
Adrian Roosc13723f2016-01-12 20:29:03 +0100166 private static final String IS_TRUST_USUALLY_MANAGED = "lockscreen.istrustusuallymanaged";
Adrian Roos82142c22014-03-27 14:56:59 +0100167
Ricky Waid3982442016-05-24 19:27:08 +0100168 public static final String PROFILE_KEY_NAME_ENCRYPT = "profile_key_name_encrypt_";
169 public static final String PROFILE_KEY_NAME_DECRYPT = "profile_key_name_decrypt_";
Rubin Xu3bf722a2016-12-15 16:07:38 +0000170 public static final String SYNTHETIC_PASSWORD_KEY_PREFIX = "synthetic_password_";
171
172 public static final String SYNTHETIC_PASSWORD_HANDLE_KEY = "sp-handle";
173 public static final String SYNTHETIC_PASSWORD_ENABLED_KEY = "enable-sp";
Rubin Xu5e891bc2019-10-14 10:22:23 +0100174 public static final int SYNTHETIC_PASSWORD_ENABLED_BY_DEFAULT = 1;
Rubin Xuf01e9072018-03-30 20:59:28 +0100175 private static final String HISTORY_DELIMITER = ",";
Ricky Waid3982442016-05-24 19:27:08 +0100176
Andrei Onea15884392019-03-22 17:28:11 +0000177 @UnsupportedAppUsage
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800178 private final Context mContext;
Andrei Onea15884392019-03-22 17:28:11 +0000179 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800180 private final ContentResolver mContentResolver;
Jim Miller31f90b62010-01-20 13:35:20 -0800181 private DevicePolicyManager mDevicePolicyManager;
Amith Yamasani52c489c2012-03-28 11:42:42 -0700182 private ILockSettings mLockSettingsService;
Clara Bayarria1771112015-12-18 16:29:18 +0000183 private UserManager mUserManager;
Adrian Roos7a3bf7c2016-07-12 15:31:55 -0700184 private final Handler mHandler;
Kevin Chyna3e55822017-10-04 15:47:24 -0700185 private final SparseLongArray mLockoutDeadlines = new SparseLongArray();
Lenka Trochtova66c492a2018-12-06 11:29:21 +0100186 private Boolean mHasSecureLockScreen;
Jim Milleree82f8f2012-10-01 16:26:18 -0700187
Adrian Roosc13723f2016-01-12 20:29:03 +0100188 /**
189 * Use {@link TrustManager#isTrustUsuallyManaged(int)}.
190 *
191 * This returns the lazily-peristed value and should only be used by TrustManagerService.
192 */
193 public boolean isTrustUsuallyManaged(int userId) {
194 if (!(mLockSettingsService instanceof ILockSettings.Stub)) {
195 throw new IllegalStateException("May only be called by TrustManagerService. "
196 + "Use TrustManager.isTrustUsuallyManaged()");
197 }
198 try {
199 return getLockSettings().getBoolean(IS_TRUST_USUALLY_MANAGED, false, userId);
200 } catch (RemoteException e) {
201 return false;
202 }
203 }
204
205 public void setTrustUsuallyManaged(boolean managed, int userId) {
206 try {
207 getLockSettings().setBoolean(IS_TRUST_USUALLY_MANAGED, managed, userId);
208 } catch (RemoteException e) {
209 // System dead.
210 }
211 }
Andres Morales23974272015-05-14 22:42:26 -0700212
Adrian Roos4ab7e592016-04-13 15:38:13 -0700213 public void userPresent(int userId) {
214 try {
215 getLockSettings().userPresent(userId);
216 } catch (RemoteException e) {
217 throw e.rethrowFromSystemServer();
218 }
219 }
220
Andres Morales23974272015-05-14 22:42:26 -0700221 public static final class RequestThrottledException extends Exception {
222 private int mTimeoutMs;
Andrei Onea15884392019-03-22 17:28:11 +0000223 @UnsupportedAppUsage
Andres Morales23974272015-05-14 22:42:26 -0700224 public RequestThrottledException(int timeoutMs) {
225 mTimeoutMs = timeoutMs;
226 }
227
228 /**
229 * @return The amount of time in ms before another request may
230 * be executed
231 */
Andrei Onea15884392019-03-22 17:28:11 +0000232 @UnsupportedAppUsage
Andres Morales23974272015-05-14 22:42:26 -0700233 public int getTimeoutMs() {
234 return mTimeoutMs;
235 }
236
237 }
238
Andrei Onea15884392019-03-22 17:28:11 +0000239 @UnsupportedAppUsage
Jim Millercd709882010-03-25 18:24:02 -0700240 public DevicePolicyManager getDevicePolicyManager() {
Jim Miller5b0fb3a2010-02-23 13:46:35 -0800241 if (mDevicePolicyManager == null) {
242 mDevicePolicyManager =
243 (DevicePolicyManager)mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
244 if (mDevicePolicyManager == null) {
245 Log.e(TAG, "Can't get DevicePolicyManagerService: is it running?",
246 new IllegalStateException("Stack trace:"));
247 }
248 }
249 return mDevicePolicyManager;
250 }
Amith Yamasani52c489c2012-03-28 11:42:42 -0700251
Clara Bayarria1771112015-12-18 16:29:18 +0000252 private UserManager getUserManager() {
253 if (mUserManager == null) {
254 mUserManager = UserManager.get(mContext);
255 }
256 return mUserManager;
257 }
258
Adrian Roos82142c22014-03-27 14:56:59 +0100259 private TrustManager getTrustManager() {
260 TrustManager trust = (TrustManager) mContext.getSystemService(Context.TRUST_SERVICE);
261 if (trust == null) {
262 Log.e(TAG, "Can't get TrustManagerService: is it running?",
263 new IllegalStateException("Stack trace:"));
264 }
265 return trust;
266 }
267
Andrei Onea15884392019-03-22 17:28:11 +0000268 @UnsupportedAppUsage
Jim Miller31f90b62010-01-20 13:35:20 -0800269 public LockPatternUtils(Context context) {
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800270 mContext = context;
Jim Miller31f90b62010-01-20 13:35:20 -0800271 mContentResolver = context.getContentResolver();
Adrian Roos7a3bf7c2016-07-12 15:31:55 -0700272
273 Looper looper = Looper.myLooper();
274 mHandler = looper != null ? new Handler(looper) : null;
Amith Yamasani52c489c2012-03-28 11:42:42 -0700275 }
Jim Miller69aa4a92009-12-22 19:03:28 -0800276
Andrei Onea15884392019-03-22 17:28:11 +0000277 @UnsupportedAppUsage
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000278 @VisibleForTesting
279 public ILockSettings getLockSettings() {
Amith Yamasani52c489c2012-03-28 11:42:42 -0700280 if (mLockSettingsService == null) {
Adrian Roos450ce9f2014-10-29 14:30:37 +0100281 ILockSettings service = ILockSettings.Stub.asInterface(
282 ServiceManager.getService("lock_settings"));
Adrian Roos138b8332014-11-11 13:51:07 +0100283 mLockSettingsService = service;
Brad Fitzpatrick90881002010-08-23 18:30:08 -0700284 }
Amith Yamasani52c489c2012-03-28 11:42:42 -0700285 return mLockSettingsService;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800286 }
287
Adrian Roos8150d2a2015-04-16 17:11:20 -0700288 public int getRequestedMinimumPasswordLength(int userId) {
289 return getDevicePolicyManager().getPasswordMinimumLength(null, userId);
Jim Miller31f90b62010-01-20 13:35:20 -0800290 }
291
Pavel Grafov2e7929e2018-05-04 17:29:36 +0100292 public int getMaximumPasswordLength(int quality) {
293 return getDevicePolicyManager().getPasswordMaximumLength(quality);
294 }
295
Pavel Grafov6f334842019-08-06 14:37:06 +0100296 public PasswordMetrics getRequestedPasswordMetrics(int userId) {
297 return getDevicePolicyManager().getPasswordMinimumMetrics(userId);
298 }
299
Adrian Roos8150d2a2015-04-16 17:11:20 -0700300 public int getRequestedPasswordQuality(int userId) {
301 return getDevicePolicyManager().getPasswordQuality(null, userId);
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100302 }
303
304 private int getRequestedPasswordHistoryLength(int userId) {
305 return getDevicePolicyManager().getPasswordHistoryLength(null, userId);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700306 }
307
Adrian Roos8150d2a2015-04-16 17:11:20 -0700308 public int getRequestedPasswordMinimumLetters(int userId) {
309 return getDevicePolicyManager().getPasswordMinimumLetters(null, userId);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700310 }
311
Adrian Roos8150d2a2015-04-16 17:11:20 -0700312 public int getRequestedPasswordMinimumUpperCase(int userId) {
313 return getDevicePolicyManager().getPasswordMinimumUpperCase(null, userId);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700314 }
315
Adrian Roos8150d2a2015-04-16 17:11:20 -0700316 public int getRequestedPasswordMinimumLowerCase(int userId) {
317 return getDevicePolicyManager().getPasswordMinimumLowerCase(null, userId);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700318 }
319
Adrian Roos8150d2a2015-04-16 17:11:20 -0700320 public int getRequestedPasswordMinimumNumeric(int userId) {
321 return getDevicePolicyManager().getPasswordMinimumNumeric(null, userId);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700322 }
323
Adrian Roos8150d2a2015-04-16 17:11:20 -0700324 public int getRequestedPasswordMinimumSymbols(int userId) {
325 return getDevicePolicyManager().getPasswordMinimumSymbols(null, userId);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700326 }
327
Adrian Roos8150d2a2015-04-16 17:11:20 -0700328 public int getRequestedPasswordMinimumNonLetter(int userId) {
329 return getDevicePolicyManager().getPasswordMinimumNonLetter(null, userId);
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700330 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700331
Andrei Onea15884392019-03-22 17:28:11 +0000332 @UnsupportedAppUsage
Adrian Roos8150d2a2015-04-16 17:11:20 -0700333 public void reportFailedPasswordAttempt(int userId) {
Adrian Roos2adc2632017-09-05 17:01:42 +0200334 if (userId == USER_FRP && frpCredentialEnabled(mContext)) {
Adrian Roos7374d3a2017-03-31 14:14:53 -0700335 return;
336 }
Adrian Roos4f994eb2014-07-23 15:45:05 +0200337 getDevicePolicyManager().reportFailedPasswordAttempt(userId);
338 getTrustManager().reportUnlockAttempt(false /* authenticated */, userId);
Jim Miller31f90b62010-01-20 13:35:20 -0800339 }
340
Andrei Onea15884392019-03-22 17:28:11 +0000341 @UnsupportedAppUsage
Adrian Roos8150d2a2015-04-16 17:11:20 -0700342 public void reportSuccessfulPasswordAttempt(int userId) {
Adrian Roos2adc2632017-09-05 17:01:42 +0200343 if (userId == USER_FRP && frpCredentialEnabled(mContext)) {
Adrian Roos7374d3a2017-03-31 14:14:53 -0700344 return;
345 }
Adrian Roos8150d2a2015-04-16 17:11:20 -0700346 getDevicePolicyManager().reportSuccessfulPasswordAttempt(userId);
347 getTrustManager().reportUnlockAttempt(true /* authenticated */, userId);
Jim Miller31f90b62010-01-20 13:35:20 -0800348 }
349
Zachary Iqbal327323d2017-01-12 14:41:13 -0800350 public void reportPasswordLockout(int timeoutMs, int userId) {
Adrian Roos2adc2632017-09-05 17:01:42 +0200351 if (userId == USER_FRP && frpCredentialEnabled(mContext)) {
Adrian Roos7374d3a2017-03-31 14:14:53 -0700352 return;
353 }
Zachary Iqbal327323d2017-01-12 14:41:13 -0800354 getTrustManager().reportUnlockLockout(timeoutMs, userId);
355 }
356
Clara Bayarri51e41ad2016-02-11 17:48:53 +0000357 public int getCurrentFailedPasswordAttempts(int userId) {
Adrian Roos2adc2632017-09-05 17:01:42 +0200358 if (userId == USER_FRP && frpCredentialEnabled(mContext)) {
Adrian Roos7374d3a2017-03-31 14:14:53 -0700359 return 0;
360 }
Clara Bayarri51e41ad2016-02-11 17:48:53 +0000361 return getDevicePolicyManager().getCurrentFailedPasswordAttempts(userId);
362 }
363
364 public int getMaximumFailedPasswordsForWipe(int userId) {
Adrian Roos2adc2632017-09-05 17:01:42 +0200365 if (userId == USER_FRP && frpCredentialEnabled(mContext)) {
Adrian Roos7374d3a2017-03-31 14:14:53 -0700366 return 0;
367 }
Clara Bayarri51e41ad2016-02-11 17:48:53 +0000368 return getDevicePolicyManager().getMaximumFailedPasswordsForWipe(
369 null /* componentName */, userId);
370 }
371
Rubin Xua58125d2019-09-06 20:11:48 +0100372 /**
373 * Check to see if a credential matches the saved one.
374 * If credential matches, return an opaque attestation that the challenge was verified.
375 *
376 * @param credential The credential to check.
377 * @param challenge The challenge to verify against the credential
Rubin Xua58125d2019-09-06 20:11:48 +0100378 * @param userId The user whose credential is being verified
Rubin Xu5e891bc2019-10-14 10:22:23 +0100379 * @return the attestation that the challenge was verified, or null
Rubin Xua58125d2019-09-06 20:11:48 +0100380 * @throws RequestThrottledException if credential verification is being throttled due to
381 * to many incorrect attempts.
382 * @throws IllegalStateException if called on the main thread.
383 */
384 public byte[] verifyCredential(@NonNull LockscreenCredential credential, long challenge,
385 int userId) throws RequestThrottledException {
386 throwIfCalledOnMainThread();
Rubin Xu1de89b32016-11-30 20:03:13 +0000387 try {
Rubin Xua58125d2019-09-06 20:11:48 +0100388 VerifyCredentialResponse response = getLockSettings().verifyCredential(
Rubin Xubb883202019-10-09 11:22:53 +0100389 credential, challenge, userId);
Rubin Xu1de89b32016-11-30 20:03:13 +0000390 if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
391 return response.getPayload();
392 } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {
393 throw new RequestThrottledException(response.getTimeout());
394 } else {
395 return null;
396 }
397 } catch (RemoteException re) {
Rubin Xu5e891bc2019-10-14 10:22:23 +0100398 Log.e(TAG, "failed to verify credential", re);
Rubin Xu1de89b32016-11-30 20:03:13 +0000399 return null;
400 }
401 }
402
Rubin Xua58125d2019-09-06 20:11:48 +0100403 /**
404 * Check to see if a credential matches the saved one.
405 *
406 * @param credential The credential to check.
407 * @param userId The user whose credential is being checked
408 * @param progressCallback callback to deliver early signal that the credential matches
409 * @return {@code true} if credential matches, {@code false} otherwise
410 * @throws RequestThrottledException if credential verification is being throttled due to
411 * to many incorrect attempts.
412 * @throws IllegalStateException if called on the main thread.
413 */
414 public boolean checkCredential(@NonNull LockscreenCredential credential, int userId,
Rubin Xu1de89b32016-11-30 20:03:13 +0000415 @Nullable CheckCredentialProgressCallback progressCallback)
416 throws RequestThrottledException {
Rubin Xua58125d2019-09-06 20:11:48 +0100417 throwIfCalledOnMainThread();
Rubin Xu1de89b32016-11-30 20:03:13 +0000418 try {
Rubin Xua58125d2019-09-06 20:11:48 +0100419 VerifyCredentialResponse response = getLockSettings().checkCredential(
Rubin Xubb883202019-10-09 11:22:53 +0100420 credential, userId, wrapCallback(progressCallback));
Rubin Xu1de89b32016-11-30 20:03:13 +0000421
422 if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
423 return true;
424 } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {
425 throw new RequestThrottledException(response.getTimeout());
426 } else {
427 return false;
428 }
429 } catch (RemoteException re) {
Rubin Xu5e891bc2019-10-14 10:22:23 +0100430 Log.e(TAG, "failed to check credential", re);
Rubin Xu1de89b32016-11-30 20:03:13 +0000431 return false;
432 }
433 }
434
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800435 /**
Rubin Xua58125d2019-09-06 20:11:48 +0100436 * Check if the credential of a managed profile with unified challenge matches. In this context,
437 * The credential should be the parent user's lockscreen password. If credential matches,
438 * return an opaque attestation associated with the managed profile that the challenge was
439 * verified.
Andres Moralesd9fc85a2015-04-09 19:14:42 -0700440 *
Rubin Xua58125d2019-09-06 20:11:48 +0100441 * @param credential The parent user's credential to check.
442 * @param challenge The challenge to verify against the credential
443 * @return the attestation that the challenge was verified, or null
444 * @param userId The managed profile user id
445 * @throws RequestThrottledException if credential verification is being throttled due to
446 * to many incorrect attempts.
447 * @throws IllegalStateException if called on the main thread.
Andres Moralesd9fc85a2015-04-09 19:14:42 -0700448 */
Rubin Xua58125d2019-09-06 20:11:48 +0100449 public byte[] verifyTiedProfileChallenge(@NonNull LockscreenCredential credential,
450 long challenge, int userId) throws RequestThrottledException {
Ricky Wai53940d42016-04-05 15:29:24 +0100451 throwIfCalledOnMainThread();
452 try {
453 VerifyCredentialResponse response =
Rubin Xubb883202019-10-09 11:22:53 +0100454 getLockSettings().verifyTiedProfileChallenge(credential, challenge, userId);
Ricky Wai53940d42016-04-05 15:29:24 +0100455
456 if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
457 return response.getPayload();
458 } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {
459 throw new RequestThrottledException(response.getTimeout());
460 } else {
461 return null;
462 }
463 } catch (RemoteException re) {
Rubin Xu5e891bc2019-10-14 10:22:23 +0100464 Log.e(TAG, "failed to verify tied profile credential", re);
Ricky Wai53940d42016-04-05 15:29:24 +0100465 return null;
466 }
467 }
468
Andres Moralesd9fc85a2015-04-09 19:14:42 -0700469 /**
Paul Lawrence945490c2014-03-27 16:37:28 +0000470 * Check to see if vold already has the password.
471 * Note that this also clears vold's copy of the password.
472 * @return Whether the vold password matches or not.
473 */
Adrian Roos8150d2a2015-04-16 17:11:20 -0700474 public boolean checkVoldPassword(int userId) {
Paul Lawrence945490c2014-03-27 16:37:28 +0000475 try {
476 return getLockSettings().checkVoldPassword(userId);
477 } catch (RemoteException re) {
Rubin Xu5e891bc2019-10-14 10:22:23 +0100478 Log.e(TAG, "failed to check vold password", re);
Paul Lawrence945490c2014-03-27 16:37:28 +0000479 return false;
480 }
481 }
482
483 /**
Rubin Xuf01e9072018-03-30 20:59:28 +0100484 * Returns the password history hash factor, needed to check new password against password
Rubin Xu7959e2a2019-07-31 11:26:53 +0100485 * history with {@link #checkPasswordHistory(byte[], byte[], int)}
Rubin Xuf01e9072018-03-30 20:59:28 +0100486 */
Rubin Xua58125d2019-09-06 20:11:48 +0100487 public byte[] getPasswordHistoryHashFactor(@NonNull LockscreenCredential currentPassword,
488 int userId) {
Rubin Xuf01e9072018-03-30 20:59:28 +0100489 try {
Rubin Xubb883202019-10-09 11:22:53 +0100490 return getLockSettings().getHashFactor(currentPassword, userId);
Rubin Xuf01e9072018-03-30 20:59:28 +0100491 } catch (RemoteException e) {
492 Log.e(TAG, "failed to get hash factor", e);
493 return null;
494 }
495 }
496
497 /**
Konstantin Lopyrev863f22d2010-05-12 17:16:58 -0700498 * Check to see if a password matches any of the passwords stored in the
499 * password history.
500 *
Rubin Xuf01e9072018-03-30 20:59:28 +0100501 * @param passwordToCheck The password to check.
502 * @param hashFactor Hash factor of the current user returned from
503 * {@link ILockSettings#getHashFactor}
Konstantin Lopyrev863f22d2010-05-12 17:16:58 -0700504 * @return Whether the password matches any in the history.
505 */
Rich Canningsf64ec632019-02-21 12:40:36 -0800506 public boolean checkPasswordHistory(byte[] passwordToCheck, byte[] hashFactor, int userId) {
507 if (passwordToCheck == null || passwordToCheck.length == 0) {
Rubin Xuf01e9072018-03-30 20:59:28 +0100508 Log.e(TAG, "checkPasswordHistory: empty password");
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700509 return false;
510 }
Rubin Xuf01e9072018-03-30 20:59:28 +0100511 String passwordHistory = getString(PASSWORD_HISTORY_KEY, userId);
512 if (TextUtils.isEmpty(passwordHistory)) {
513 return false;
514 }
Adrian Roos8150d2a2015-04-16 17:11:20 -0700515 int passwordHistoryLength = getRequestedPasswordHistoryLength(userId);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700516 if(passwordHistoryLength == 0) {
517 return false;
518 }
Rubin Xuf01e9072018-03-30 20:59:28 +0100519 String legacyHash = legacyPasswordToHash(passwordToCheck, userId);
520 String passwordHash = passwordToHistoryHash(passwordToCheck, hashFactor, userId);
521 String[] history = passwordHistory.split(HISTORY_DELIMITER);
522 // Password History may be too long...
523 for (int i = 0; i < Math.min(passwordHistoryLength, history.length); i++) {
524 if (history[i].equals(legacyHash) || history[i].equals(passwordHash)) {
525 return true;
526 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700527 }
Rubin Xuf01e9072018-03-30 20:59:28 +0100528 return false;
Konstantin Lopyrev863f22d2010-05-12 17:16:58 -0700529 }
530
531 /**
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -0700532 * Return true if the user has ever chosen a pattern. This is true even if the pattern is
533 * currently cleared.
534 *
535 * @return True if the user has ever chosen a pattern.
536 */
Adrian Roos8150d2a2015-04-16 17:11:20 -0700537 public boolean isPatternEverChosen(int userId) {
538 return getBoolean(PATTERN_EVER_CHOSEN_KEY, false, userId);
Adrian Roosdce01222015-01-07 22:39:01 +0100539 }
540
541 /**
Bryan Mawhinneye483b562017-05-15 14:46:05 +0100542 * Records that the user has chosen a pattern at some time, even if the pattern is
543 * currently cleared.
544 */
545 public void reportPatternWasChosen(int userId) {
546 setBoolean(PATTERN_EVER_CHOSEN_KEY, true, userId);
547 }
548
549 /**
Adrian Roosdce01222015-01-07 22:39:01 +0100550 * Used by device policy manager to validate the current password
551 * information it has.
Rubin Xu5e891bc2019-10-14 10:22:23 +0100552 * @Deprecated use {@link #getKeyguardStoredPasswordQuality}
Adrian Roosdce01222015-01-07 22:39:01 +0100553 */
Andrei Onea15884392019-03-22 17:28:11 +0000554 @UnsupportedAppUsage
Adrian Roosdce01222015-01-07 22:39:01 +0100555 public int getActivePasswordQuality(int userId) {
Rubin Xu5e891bc2019-10-14 10:22:23 +0100556 return getKeyguardStoredPasswordQuality(userId);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700557 }
Jim Millercd709882010-03-25 18:24:02 -0700558
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700559 /**
Ricky Wai4613fe42016-05-24 11:11:42 +0100560 * Use it to reset keystore without wiping work profile
561 */
562 public void resetKeyStore(int userId) {
563 try {
564 getLockSettings().resetKeyStore(userId);
565 } catch (RemoteException e) {
566 // It should not happen
567 Log.e(TAG, "Couldn't reset keystore " + e);
568 }
569 }
570
571 /**
Benjamin Franz51ed7942015-04-07 16:34:56 +0100572 * Disable showing lock screen at all for a given user.
573 * This is only meaningful if pattern, pin or password are not set.
Jim Miller2a98a4c2010-11-19 18:49:26 -0800574 *
Benjamin Franz51ed7942015-04-07 16:34:56 +0100575 * @param disable Disables lock screen when true
576 * @param userId User ID of the user this has effect on
577 */
578 public void setLockScreenDisabled(boolean disable, int userId) {
579 setBoolean(DISABLE_LOCKSCREEN_KEY, disable, userId);
580 }
581
582 /**
583 * Determine if LockScreen is disabled for the current user. This is used to decide whether
584 * LockScreen is shown after reboot or after screen timeout / short press on power.
585 *
586 * @return true if lock screen is disabled
Jim Miller2a98a4c2010-11-19 18:49:26 -0800587 */
Andrei Onea15884392019-03-22 17:28:11 +0000588 @UnsupportedAppUsage
Adrian Roos8150d2a2015-04-16 17:11:20 -0700589 public boolean isLockScreenDisabled(int userId) {
Evan Rosky2eff7452016-06-09 12:32:33 -0700590 if (isSecure(userId)) {
591 return false;
592 }
593 boolean disabledByDefault = mContext.getResources().getBoolean(
594 com.android.internal.R.bool.config_disableLockscreenByDefault);
595 boolean isSystemUser = UserManager.isSplitSystemUser() && userId == UserHandle.USER_SYSTEM;
Christine Franks5856be82017-06-23 18:12:46 -0700596 UserInfo userInfo = getUserManager().getUserInfo(userId);
597 boolean isDemoUser = UserManager.isDeviceInDemoMode(mContext) && userInfo != null
598 && userInfo.isDemo();
Evan Rosky2eff7452016-06-09 12:32:33 -0700599 return getBoolean(DISABLE_LOCKSCREEN_KEY, false, userId)
Christine Franks5856be82017-06-23 18:12:46 -0700600 || (disabledByDefault && !isSystemUser)
601 || isDemoUser;
Jim Miller2a98a4c2010-11-19 18:49:26 -0800602 }
603
Rubin Xua58125d2019-09-06 20:11:48 +0100604 /** Returns if the given quality maps to an alphabetic password */
605 public static boolean isQualityAlphabeticPassword(int quality) {
606 return quality >= PASSWORD_QUALITY_ALPHABETIC;
607 }
608
609 /** Returns if the given quality maps to an numeric pin */
610 public static boolean isQualityNumericPin(int quality) {
611 return quality == PASSWORD_QUALITY_NUMERIC || quality == PASSWORD_QUALITY_NUMERIC_COMPLEX;
612 }
613
Rubin Xu5e891bc2019-10-14 10:22:23 +0100614 /** Returns the canonical password quality corresponding to the given credential type. */
615 public static int credentialTypeToPasswordQuality(int credentialType) {
616 switch (credentialType) {
617 case CREDENTIAL_TYPE_NONE:
618 return PASSWORD_QUALITY_UNSPECIFIED;
619 case CREDENTIAL_TYPE_PATTERN:
620 return PASSWORD_QUALITY_SOMETHING;
621 case CREDENTIAL_TYPE_PIN:
622 return PASSWORD_QUALITY_NUMERIC;
623 case CREDENTIAL_TYPE_PASSWORD:
624 return PASSWORD_QUALITY_ALPHABETIC;
625 default:
626 throw new IllegalStateException("Unknown type: " + credentialType);
627 }
628 }
629
Jim Miller2a98a4c2010-11-19 18:49:26 -0800630 /**
Rubin Xua58125d2019-09-06 20:11:48 +0100631 * Save a new lockscreen credential.
Rubin Xu6a7303d2019-08-16 13:19:56 +0100632 *
Rubin Xua58125d2019-09-06 20:11:48 +0100633 * <p> This method will fail (returning {@code false}) if the previously saved credential
634 * provided is incorrect, or if the lockscreen verification is still being throttled.
Rubin Xu6a7303d2019-08-16 13:19:56 +0100635 *
Rubin Xua58125d2019-09-06 20:11:48 +0100636 * @param newCredential The new credential to save
637 * @param savedCredential The current credential
Rubin Xud9522402019-11-06 13:54:27 +0000638 * @param userHandle the user whose lockscreen credential is to be changed
Rubin Xua58125d2019-09-06 20:11:48 +0100639 *
640 * @return whether this method saved the new password successfully or not. This flow will fail
641 * and return false if the given credential is wrong.
Rubin Xu6a7303d2019-08-16 13:19:56 +0100642 * @throws RuntimeException if password change encountered an unrecoverable error.
Rubin Xud9522402019-11-06 13:54:27 +0000643 * @throws UnsupportedOperationException secure lockscreen is not supported on this device.
644 * @throws IllegalArgumentException if new credential is too short.
Danielle Millett2364a222011-12-21 17:02:32 -0500645 */
Rubin Xua58125d2019-09-06 20:11:48 +0100646 public boolean setLockCredential(@NonNull LockscreenCredential newCredential,
Rubin Xud9522402019-11-06 13:54:27 +0000647 @NonNull LockscreenCredential savedCredential, int userHandle) {
Lenka Trochtova66c492a2018-12-06 11:29:21 +0100648 if (!hasSecureLockScreen()) {
649 throw new UnsupportedOperationException(
650 "This operation requires the lock screen feature.");
651 }
Rubin Xu6232a4c2019-10-08 16:58:54 +0100652 newCredential.checkLength();
Rubin Xu682d1672018-03-21 09:13:44 +0000653
Rubin Xu682d1672018-03-21 09:13:44 +0000654 try {
Rubin Xud9522402019-11-06 13:54:27 +0000655 if (!getLockSettings().setLockCredential(newCredential, savedCredential, userHandle)) {
Rubin Xu6a7303d2019-08-16 13:19:56 +0100656 return false;
657 }
Rubin Xu5e891bc2019-10-14 10:22:23 +0100658 } catch (RemoteException e) {
Rubin Xu6232a4c2019-10-08 16:58:54 +0100659 throw new RuntimeException("Unable to save lock password", e);
Rubin Xu682d1672018-03-21 09:13:44 +0000660 }
661
Rubin Xu6232a4c2019-10-08 16:58:54 +0100662 onPostPasswordChanged(newCredential, userHandle);
Irina Dumitrescuc90674d2019-02-28 17:34:19 +0000663 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800664 }
665
Rubin Xu6232a4c2019-10-08 16:58:54 +0100666 private void onPostPasswordChanged(LockscreenCredential newCredential, int userHandle) {
667 updateEncryptionPasswordIfNeeded(newCredential, userHandle);
668 if (newCredential.isPattern()) {
669 reportPatternWasChosen(userHandle);
670 }
671 updatePasswordHistory(newCredential, userHandle);
672 reportEnabledTrustAgentsChanged(userHandle);
673 }
674
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100675 private void updateCryptoUserInfo(int userId) {
Xiaohui Chen86c69dd2015-08-27 15:44:02 -0700676 if (userId != UserHandle.USER_SYSTEM) {
Paul Lawrencee51dcf92014-03-18 10:56:00 -0700677 return;
678 }
679
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100680 final String ownerInfo = isOwnerInfoEnabled(userId) ? getOwnerInfo(userId) : "";
Paul Lawrencee51dcf92014-03-18 10:56:00 -0700681
682 IBinder service = ServiceManager.getService("mount");
683 if (service == null) {
684 Log.e(TAG, "Could not find the mount service to update the user info");
685 return;
686 }
687
Sudheer Shanka2250d562016-11-07 15:41:02 -0800688 IStorageManager storageManager = IStorageManager.Stub.asInterface(service);
Paul Lawrencee51dcf92014-03-18 10:56:00 -0700689 try {
690 Log.d(TAG, "Setting owner info");
Sudheer Shanka2250d562016-11-07 15:41:02 -0800691 storageManager.setField(StorageManager.OWNER_INFO_KEY, ownerInfo);
Paul Lawrencee51dcf92014-03-18 10:56:00 -0700692 } catch (RemoteException e) {
693 Log.e(TAG, "Error changing user info", e);
694 }
695 }
696
Andrei Onea15884392019-03-22 17:28:11 +0000697 @UnsupportedAppUsage
Jim Miller187ec582013-04-15 18:27:54 -0700698 public void setOwnerInfo(String info, int userId) {
699 setString(LOCK_SCREEN_OWNER_INFO, info, userId);
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100700 updateCryptoUserInfo(userId);
Jim Miller187ec582013-04-15 18:27:54 -0700701 }
702
Andrei Onea15884392019-03-22 17:28:11 +0000703 @UnsupportedAppUsage
Adrian Roos8150d2a2015-04-16 17:11:20 -0700704 public void setOwnerInfoEnabled(boolean enabled, int userId) {
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100705 setBoolean(LOCK_SCREEN_OWNER_INFO_ENABLED, enabled, userId);
706 updateCryptoUserInfo(userId);
Jim Miller187ec582013-04-15 18:27:54 -0700707 }
708
Andrei Onea15884392019-03-22 17:28:11 +0000709 @UnsupportedAppUsage
Jim Miller187ec582013-04-15 18:27:54 -0700710 public String getOwnerInfo(int userId) {
Adrian Roosdce01222015-01-07 22:39:01 +0100711 return getString(LOCK_SCREEN_OWNER_INFO, userId);
Jim Miller187ec582013-04-15 18:27:54 -0700712 }
713
Adrian Roos8150d2a2015-04-16 17:11:20 -0700714 public boolean isOwnerInfoEnabled(int userId) {
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100715 return getBoolean(LOCK_SCREEN_OWNER_INFO_ENABLED, false, userId);
Jim Miller187ec582013-04-15 18:27:54 -0700716 }
717
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800718 /**
Andrei Stingaceanu6644cd92015-11-10 13:03:31 +0000719 * Sets the device owner information. If the information is {@code null} or empty then the
720 * device owner info is cleared.
721 *
722 * @param info Device owner information which will be displayed instead of the user
723 * owner info.
724 */
725 public void setDeviceOwnerInfo(String info) {
726 if (info != null && info.isEmpty()) {
727 info = null;
728 }
729
730 setString(LOCK_SCREEN_DEVICE_OWNER_INFO, info, UserHandle.USER_SYSTEM);
731 }
732
733 public String getDeviceOwnerInfo() {
734 return getString(LOCK_SCREEN_DEVICE_OWNER_INFO, UserHandle.USER_SYSTEM);
735 }
736
737 public boolean isDeviceOwnerInfoEnabled() {
738 return getDeviceOwnerInfo() != null;
739 }
740
Jason parksf7b3cd42011-01-27 09:28:25 -0600741 /** Update the encryption password if it is enabled **/
Rich Canningsf64ec632019-02-21 12:40:36 -0800742 private void updateEncryptionPassword(final int type, final byte[] password) {
Lenka Trochtova66c492a2018-12-06 11:29:21 +0100743 if (!hasSecureLockScreen()) {
744 throw new UnsupportedOperationException(
745 "This operation requires the lock screen feature.");
746 }
Amith Yamasanicd410ba2014-10-17 11:16:58 -0700747 if (!isDeviceEncryptionEnabled()) {
Jason parksf7b3cd42011-01-27 09:28:25 -0600748 return;
749 }
Paul Lawrence3a5a0be2014-09-25 09:26:34 -0700750 final IBinder service = ServiceManager.getService("mount");
Jason parksf7b3cd42011-01-27 09:28:25 -0600751 if (service == null) {
752 Log.e(TAG, "Could not find the mount service to update the encryption password");
753 return;
754 }
755
Paul Crowleya9f354622019-06-03 11:22:38 -0700756 // TODO(b/120484642): This is a location where we still use a String for vold
757 String passwordString = password != null ? new String(password) : null;
Paul Lawrence3a5a0be2014-09-25 09:26:34 -0700758 new AsyncTask<Void, Void, Void>() {
759 @Override
760 protected Void doInBackground(Void... dummy) {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800761 IStorageManager storageManager = IStorageManager.Stub.asInterface(service);
Paul Lawrence3a5a0be2014-09-25 09:26:34 -0700762 try {
Rich Canningsf64ec632019-02-21 12:40:36 -0800763 storageManager.changeEncryptionPassword(type, passwordString);
Paul Lawrence3a5a0be2014-09-25 09:26:34 -0700764 } catch (RemoteException e) {
765 Log.e(TAG, "Error changing encryption password", e);
766 }
767 return null;
768 }
769 }.execute();
Jason parksf7b3cd42011-01-27 09:28:25 -0600770 }
771
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800772 /**
Rubin Xuf095f832017-01-31 15:23:34 +0000773 * Update device encryption password if calling user is USER_SYSTEM and device supports
774 * encryption.
775 */
Rubin Xu6232a4c2019-10-08 16:58:54 +0100776 private void updateEncryptionPasswordIfNeeded(LockscreenCredential credential, int userHandle) {
Rubin Xua55b1682017-01-31 10:06:56 +0000777 // Update the device encryption password.
Rubin Xu6232a4c2019-10-08 16:58:54 +0100778 if (userHandle != UserHandle.USER_SYSTEM || !isDeviceEncryptionEnabled()) {
779 return;
Rubin Xua55b1682017-01-31 10:06:56 +0000780 }
Rubin Xu6232a4c2019-10-08 16:58:54 +0100781 if (!shouldEncryptWithCredentials(true)) {
782 updateEncryptionPassword(StorageManager.CRYPT_TYPE_DEFAULT, null);
783 return;
784 }
785 if (credential.isNone()) {
786 // Set the encryption password to default.
787 setCredentialRequiredToDecrypt(false);
788 }
789 updateEncryptionPassword(credential.getStorageCryptType(), credential.getCredential());
Rubin Xua55b1682017-01-31 10:06:56 +0000790 }
791
Rubin Xuf01e9072018-03-30 20:59:28 +0100792 /**
793 * Store the hash of the *current* password in the password history list, if device policy
794 * enforces password history requirement.
795 */
Rubin Xua58125d2019-09-06 20:11:48 +0100796 private void updatePasswordHistory(LockscreenCredential password, int userHandle) {
797 if (password.isNone()) {
Rubin Xu6232a4c2019-10-08 16:58:54 +0100798 return;
799 }
800 if (password.isPattern()) {
801 // Do not keep track of historical patterns
Rubin Xuf01e9072018-03-30 20:59:28 +0100802 return;
803 }
Rubin Xua55b1682017-01-31 10:06:56 +0000804 // Add the password to the password history. We assume all
805 // password hashes have the same length for simplicity of implementation.
806 String passwordHistory = getString(PASSWORD_HISTORY_KEY, userHandle);
807 if (passwordHistory == null) {
808 passwordHistory = "";
809 }
810 int passwordHistoryLength = getRequestedPasswordHistoryLength(userHandle);
811 if (passwordHistoryLength == 0) {
812 passwordHistory = "";
813 } else {
Rubin Xuf01e9072018-03-30 20:59:28 +0100814 final byte[] hashFactor = getPasswordHistoryHashFactor(password, userHandle);
Rubin Xua58125d2019-09-06 20:11:48 +0100815 String hash = passwordToHistoryHash(password.getCredential(), hashFactor, userHandle);
Rubin Xuf01e9072018-03-30 20:59:28 +0100816 if (hash == null) {
817 Log.e(TAG, "Compute new style password hash failed, fallback to legacy style");
Rubin Xua58125d2019-09-06 20:11:48 +0100818 hash = legacyPasswordToHash(password.getCredential(), userHandle);
Rubin Xuf01e9072018-03-30 20:59:28 +0100819 }
820 if (TextUtils.isEmpty(passwordHistory)) {
821 passwordHistory = hash;
822 } else {
823 String[] history = passwordHistory.split(HISTORY_DELIMITER);
824 StringJoiner joiner = new StringJoiner(HISTORY_DELIMITER);
825 joiner.add(hash);
826 for (int i = 0; i < passwordHistoryLength - 1 && i < history.length; i++) {
827 joiner.add(history[i]);
828 }
829 passwordHistory = joiner.toString();
830 }
Rubin Xua55b1682017-01-31 10:06:56 +0000831 }
832 setString(PASSWORD_HISTORY_KEY, passwordHistory, userHandle);
Rubin Xua55b1682017-01-31 10:06:56 +0000833 }
834
Jim Millercd709882010-03-25 18:24:02 -0700835 /**
Jim Miller6848dc82014-10-13 18:51:53 -0700836 * Determine if the device supports encryption, even if it's set to default. This
837 * differs from isDeviceEncrypted() in that it returns true even if the device is
838 * encrypted with the default password.
839 * @return true if device encryption is enabled
840 */
Andrei Onea15884392019-03-22 17:28:11 +0000841 @UnsupportedAppUsage
Jim Miller6848dc82014-10-13 18:51:53 -0700842 public static boolean isDeviceEncryptionEnabled() {
Paul Lawrence20be5d62016-02-26 13:51:17 -0800843 return StorageManager.isEncrypted();
Jim Miller6848dc82014-10-13 18:51:53 -0700844 }
845
846 /**
Paul Lawrence5c21c702016-01-29 13:26:19 -0800847 * Determine if the device is file encrypted
848 * @return true if device is file encrypted
849 */
850 public static boolean isFileEncryptionEnabled() {
Paul Lawrence20be5d62016-02-26 13:51:17 -0800851 return StorageManager.isFileEncryptedNativeOrEmulated();
Paul Lawrence5c21c702016-01-29 13:26:19 -0800852 }
853
854 /**
Svetoslav16e4a1a2014-09-29 18:16:20 -0700855 * Clears the encryption password.
856 */
857 public void clearEncryptionPassword() {
858 updateEncryptionPassword(StorageManager.CRYPT_TYPE_DEFAULT, null);
859 }
860
861 /**
Rubin Xua58125d2019-09-06 20:11:48 +0100862 * Retrieves the quality mode for {@code userHandle}.
863 * @see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)
Adrian Roos1572ee32014-09-01 16:24:32 +0200864 *
865 * @return stored password quality
Rubin Xu5e891bc2019-10-14 10:22:23 +0100866 * @deprecated use {@link #getCredentialTypeForUser(int)} instead
Adrian Roos1572ee32014-09-01 16:24:32 +0200867 */
Andrei Onea15884392019-03-22 17:28:11 +0000868 @UnsupportedAppUsage
Rubin Xu5e891bc2019-10-14 10:22:23 +0100869 @Deprecated
Adrian Roos1572ee32014-09-01 16:24:32 +0200870 public int getKeyguardStoredPasswordQuality(int userHandle) {
Rubin Xu5e891bc2019-10-14 10:22:23 +0100871 return credentialTypeToPasswordQuality(getCredentialTypeForUser(userHandle));
Jim Miller6edf2632011-09-05 16:03:14 -0700872 }
873
Danielle Millett58396982011-09-30 13:55:07 -0400874 /**
Rubin Xua58125d2019-09-06 20:11:48 +0100875 * Enables/disables the Separate Profile Challenge for this {@code userHandle}. This is a no-op
Clara Bayarria1771112015-12-18 16:29:18 +0000876 * for user handles that do not belong to a managed profile.
Ricky Waidc283a82016-03-24 19:55:08 +0000877 *
878 * @param userHandle Managed profile user id
879 * @param enabled True if separate challenge is enabled
Rubin Xubb883202019-10-09 11:22:53 +0100880 * @param profilePassword Managed profile previous password. Null when {@code enabled} is
Ricky Waidc283a82016-03-24 19:55:08 +0000881 * true
Clara Bayarria1771112015-12-18 16:29:18 +0000882 */
Ricky Waidc283a82016-03-24 19:55:08 +0000883 public void setSeparateProfileChallengeEnabled(int userHandle, boolean enabled,
Rubin Xubb883202019-10-09 11:22:53 +0100884 LockscreenCredential profilePassword) {
Pavel Grafovb3191252017-07-14 12:30:31 +0100885 if (!isManagedProfile(userHandle)) {
886 return;
887 }
888 try {
889 getLockSettings().setSeparateProfileChallengeEnabled(userHandle, enabled,
Rubin Xubb883202019-10-09 11:22:53 +0100890 profilePassword);
Rubin Xu6232a4c2019-10-08 16:58:54 +0100891 reportEnabledTrustAgentsChanged(userHandle);
Pavel Grafovb3191252017-07-14 12:30:31 +0100892 } catch (RemoteException e) {
893 Log.e(TAG, "Couldn't update work profile challenge enabled");
Clara Bayarria1771112015-12-18 16:29:18 +0000894 }
895 }
896
897 /**
Rubin Xua58125d2019-09-06 20:11:48 +0100898 * Returns true if {@code userHandle} is a managed profile with separate challenge.
Clara Bayarria1771112015-12-18 16:29:18 +0000899 */
900 public boolean isSeparateProfileChallengeEnabled(int userHandle) {
Pavel Grafovb3191252017-07-14 12:30:31 +0100901 return isManagedProfile(userHandle) && hasSeparateChallenge(userHandle);
902 }
903
904 /**
Rubin Xua58125d2019-09-06 20:11:48 +0100905 * Returns true if {@code userHandle} is a managed profile with unified challenge.
Pavel Grafovb3191252017-07-14 12:30:31 +0100906 */
907 public boolean isManagedProfileWithUnifiedChallenge(int userHandle) {
908 return isManagedProfile(userHandle) && !hasSeparateChallenge(userHandle);
909 }
910
911 /**
912 * Retrieves whether the current DPM allows use of the Profile Challenge.
913 */
914 public boolean isSeparateProfileChallengeAllowed(int userHandle) {
915 return isManagedProfile(userHandle)
916 && getDevicePolicyManager().isSeparateProfileChallengeAllowed(userHandle);
917 }
918
919 /**
920 * Retrieves whether the current profile and device locks can be unified.
Pavel Grafovc4f87e92017-10-26 16:34:25 +0100921 * @param userHandle profile user handle.
Pavel Grafovb3191252017-07-14 12:30:31 +0100922 */
923 public boolean isSeparateProfileChallengeAllowedToUnify(int userHandle) {
Pavel Grafovc4f87e92017-10-26 16:34:25 +0100924 return getDevicePolicyManager().isProfileActivePasswordSufficientForParent(userHandle)
925 && !getUserManager().hasUserRestriction(
926 UserManager.DISALLOW_UNIFIED_PASSWORD, UserHandle.of(userHandle));
Pavel Grafovb3191252017-07-14 12:30:31 +0100927 }
928
929 private boolean hasSeparateChallenge(int userHandle) {
Ricky Waidc283a82016-03-24 19:55:08 +0000930 try {
931 return getLockSettings().getSeparateProfileChallengeEnabled(userHandle);
932 } catch (RemoteException e) {
933 Log.e(TAG, "Couldn't get separate profile challenge enabled");
934 // Default value is false
935 return false;
936 }
Clara Bayarria1771112015-12-18 16:29:18 +0000937 }
938
Pavel Grafovb3191252017-07-14 12:30:31 +0100939 private boolean isManagedProfile(int userHandle) {
940 final UserInfo info = getUserManager().getUserInfo(userHandle);
941 return info != null && info.isManagedProfile();
Clara Bayarrid7693912016-01-22 17:26:31 +0000942 }
943
944 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800945 * Deserialize a pattern.
Rich Canningsf64ec632019-02-21 12:40:36 -0800946 * @param bytes The pattern serialized with {@link #patternToByteArray}
947 * @return The pattern.
948 */
949 public static List<LockPatternView.Cell> byteArrayToPattern(byte[] bytes) {
950 if (bytes == null) {
951 return null;
952 }
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100953
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800954 List<LockPatternView.Cell> result = Lists.newArrayList();
955
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800956 for (int i = 0; i < bytes.length; i++) {
Andres Moralese40bad82015-05-28 14:21:36 -0700957 byte b = (byte) (bytes[i] - '1');
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800958 result.add(LockPatternView.Cell.of(b / 3, b % 3));
959 }
960 return result;
961 }
962
963 /**
964 * Serialize a pattern.
965 * @param pattern The pattern.
Rich Canningsf64ec632019-02-21 12:40:36 -0800966 * @return The pattern in byte array form.
967 */
968 public static byte[] patternToByteArray(List<LockPatternView.Cell> pattern) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800969 if (pattern == null) {
Rich Canningsf64ec632019-02-21 12:40:36 -0800970 return new byte[0];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800971 }
972 final int patternSize = pattern.size();
973
974 byte[] res = new byte[patternSize];
975 for (int i = 0; i < patternSize; i++) {
976 LockPatternView.Cell cell = pattern.get(i);
Andres Moralese40bad82015-05-28 14:21:36 -0700977 res[i] = (byte) (cell.getRow() * 3 + cell.getColumn() + '1');
978 }
Rich Canningsf64ec632019-02-21 12:40:36 -0800979 return res;
Andres Moralese40bad82015-05-28 14:21:36 -0700980 }
981
Geoffrey Borggaard987672d22014-07-18 16:47:18 -0400982 private String getSalt(int userId) {
983 long salt = getLong(LOCK_PASSWORD_SALT_KEY, 0, userId);
Jim Miller11b019d2010-01-20 16:34:45 -0800984 if (salt == 0) {
985 try {
986 salt = SecureRandom.getInstance("SHA1PRNG").nextLong();
Geoffrey Borggaard987672d22014-07-18 16:47:18 -0400987 setLong(LOCK_PASSWORD_SALT_KEY, salt, userId);
988 Log.v(TAG, "Initialized lock password salt for user: " + userId);
Jim Miller11b019d2010-01-20 16:34:45 -0800989 } catch (NoSuchAlgorithmException e) {
990 // Throw an exception rather than storing a password we'll never be able to recover
991 throw new IllegalStateException("Couldn't get SecureRandom number", e);
992 }
993 }
994 return Long.toHexString(salt);
995 }
996
Rubin Xuf01e9072018-03-30 20:59:28 +0100997 /**
Jim Miller69aa4a92009-12-22 19:03:28 -0800998 * Generate a hash for the given password. To avoid brute force attacks, we use a salted hash.
999 * Not the most secure, but it is at least a second level of protection. First level is that
1000 * the file is in a location only readable by the system process.
Narayan Kamath78108a32014-12-16 12:56:23 +00001001 *
Jim Miller69aa4a92009-12-22 19:03:28 -08001002 * @param password the gesture pattern.
Narayan Kamath78108a32014-12-16 12:56:23 +00001003 *
Jim Miller69aa4a92009-12-22 19:03:28 -08001004 * @return the hash of the pattern in a byte array.
Rubin Xua58125d2019-09-06 20:11:48 +01001005 * TODO: move to LockscreenCredential class
Jim Miller69aa4a92009-12-22 19:03:28 -08001006 */
Rich Canningsf64ec632019-02-21 12:40:36 -08001007 public String legacyPasswordToHash(byte[] password, int userId) {
1008 if (password == null || password.length == 0) {
Jim Miller69aa4a92009-12-22 19:03:28 -08001009 return null;
1010 }
Narayan Kamath78108a32014-12-16 12:56:23 +00001011
Jim Miller69aa4a92009-12-22 19:03:28 -08001012 try {
Rich Canningsf64ec632019-02-21 12:40:36 -08001013 // Previously the password was passed as a String with the following code:
1014 // byte[] saltedPassword = (password + getSalt(userId)).getBytes();
1015 // The code below creates the identical digest preimage using byte arrays:
1016 byte[] salt = getSalt(userId).getBytes();
1017 byte[] saltedPassword = Arrays.copyOf(password, password.length + salt.length);
1018 System.arraycopy(salt, 0, saltedPassword, password.length, salt.length);
Narayan Kamath78108a32014-12-16 12:56:23 +00001019 byte[] sha1 = MessageDigest.getInstance("SHA-1").digest(saltedPassword);
1020 byte[] md5 = MessageDigest.getInstance("MD5").digest(saltedPassword);
Jim Miller69aa4a92009-12-22 19:03:28 -08001021
Narayan Kamath78108a32014-12-16 12:56:23 +00001022 byte[] combined = new byte[sha1.length + md5.length];
1023 System.arraycopy(sha1, 0, combined, 0, sha1.length);
1024 System.arraycopy(md5, 0, combined, sha1.length, md5.length);
1025
1026 final char[] hexEncoded = HexEncoding.encode(combined);
Rich Canningsf64ec632019-02-21 12:40:36 -08001027 Arrays.fill(saltedPassword, (byte) 0);
Rubin Xuf01e9072018-03-30 20:59:28 +01001028 return new String(hexEncoded);
1029 } catch (NoSuchAlgorithmException e) {
1030 throw new AssertionError("Missing digest algorithm: ", e);
1031 }
1032 }
1033
1034 /**
1035 * Hash the password for password history check purpose.
Rubin Xua58125d2019-09-06 20:11:48 +01001036 * TODO: move to LockscreenCredential class
Rubin Xuf01e9072018-03-30 20:59:28 +01001037 */
Rich Canningsf64ec632019-02-21 12:40:36 -08001038 private String passwordToHistoryHash(byte[] passwordToHash, byte[] hashFactor, int userId) {
1039 if (passwordToHash == null || passwordToHash.length == 0 || hashFactor == null) {
Rubin Xuf01e9072018-03-30 20:59:28 +01001040 return null;
1041 }
1042 try {
1043 MessageDigest sha256 = MessageDigest.getInstance("SHA-256");
1044 sha256.update(hashFactor);
Rich Canningsf64ec632019-02-21 12:40:36 -08001045 byte[] salt = getSalt(userId).getBytes();
1046 byte[] saltedPassword = Arrays.copyOf(passwordToHash, passwordToHash.length
1047 + salt.length);
1048 System.arraycopy(salt, 0, saltedPassword, passwordToHash.length, salt.length);
1049 sha256.update(saltedPassword);
1050 Arrays.fill(saltedPassword, (byte) 0);
Rubin Xuf01e9072018-03-30 20:59:28 +01001051 return new String(HexEncoding.encode(sha256.digest()));
Narayan Kamath78108a32014-12-16 12:56:23 +00001052 } catch (NoSuchAlgorithmException e) {
1053 throw new AssertionError("Missing digest algorithm: ", e);
Jim Miller69aa4a92009-12-22 19:03:28 -08001054 }
Jim Miller69aa4a92009-12-22 19:03:28 -08001055 }
1056
1057 /**
Rubin Xu5e891bc2019-10-14 10:22:23 +01001058 * Returns the credential type of the user, can be one of {@link #CREDENTIAL_TYPE_NONE},
1059 * {@link #CREDENTIAL_TYPE_PATTERN}, {@link #CREDENTIAL_TYPE_PIN} and
1060 * {@link #CREDENTIAL_TYPE_PASSWORD}
1061 */
1062 public @CredentialType int getCredentialTypeForUser(int userHandle) {
1063 try {
1064 return getLockSettings().getCredentialType(userHandle);
1065 } catch (RemoteException re) {
1066 Log.e(TAG, "failed to get credential type", re);
1067 return CREDENTIAL_TYPE_NONE;
1068 }
1069 }
1070
1071 /**
Adrian Roos9dd16eb2015-01-08 16:20:49 +01001072 * @param userId the user for which to report the value
1073 * @return Whether the lock screen is secured.
1074 */
Andrei Onea15884392019-03-22 17:28:11 +00001075 @UnsupportedAppUsage
Adrian Roos9dd16eb2015-01-08 16:20:49 +01001076 public boolean isSecure(int userId) {
Rubin Xu5e891bc2019-10-14 10:22:23 +01001077 int type = getCredentialTypeForUser(userId);
1078 return type != CREDENTIAL_TYPE_NONE;
Adrian Roos9dd16eb2015-01-08 16:20:49 +01001079 }
1080
Andrei Onea15884392019-03-22 17:28:11 +00001081 @UnsupportedAppUsage
Adrian Roosdce01222015-01-07 22:39:01 +01001082 public boolean isLockPasswordEnabled(int userId) {
Rubin Xu5e891bc2019-10-14 10:22:23 +01001083 int type = getCredentialTypeForUser(userId);
1084 return type == CREDENTIAL_TYPE_PASSWORD || type == CREDENTIAL_TYPE_PIN;
Jim Miller69aa4a92009-12-22 19:03:28 -08001085 }
1086
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001087 /**
Adrian Roos230635e2015-01-07 20:50:29 +01001088 * @return Whether the lock pattern is enabled
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001089 */
Andrei Onea15884392019-03-22 17:28:11 +00001090 @UnsupportedAppUsage
Adrian Roos50bfeec2014-11-20 16:21:11 +01001091 public boolean isLockPatternEnabled(int userId) {
Rubin Xu5e891bc2019-10-14 10:22:23 +01001092 int type = getCredentialTypeForUser(userId);
1093 return type == CREDENTIAL_TYPE_PATTERN;
Danielle Millett925a7d82012-03-19 18:02:20 -04001094 }
1095
Bryce Lee46145962015-12-14 14:39:10 -08001096 @Deprecated
1097 public boolean isLegacyLockPatternEnabled(int userId) {
1098 // Note: this value should default to {@code true} to avoid any reset that might result.
1099 // We must use a special key to read this value, since it will by default return the value
1100 // based on the new logic.
1101 return getBoolean(LEGACY_LOCK_PATTERN_ENABLED, true, userId);
1102 }
1103
1104 @Deprecated
1105 public void setLegacyLockPatternEnabled(int userId) {
1106 setBoolean(Settings.Secure.LOCK_PATTERN_ENABLED, true, userId);
1107 }
1108
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001109 /**
1110 * @return Whether the visible pattern is enabled.
1111 */
Andrei Onea15884392019-03-22 17:28:11 +00001112 @UnsupportedAppUsage
Adrian Roos8150d2a2015-04-16 17:11:20 -07001113 public boolean isVisiblePatternEnabled(int userId) {
1114 return getBoolean(Settings.Secure.LOCK_PATTERN_VISIBLE, false, userId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001115 }
1116
1117 /**
1118 * Set whether the visible pattern is enabled.
1119 */
Adrian Roos8150d2a2015-04-16 17:11:20 -07001120 public void setVisiblePatternEnabled(boolean enabled, int userId) {
Adrian Roosdce01222015-01-07 22:39:01 +01001121 setBoolean(Settings.Secure.LOCK_PATTERN_VISIBLE, enabled, userId);
Paul Lawrence878ba0a2014-08-20 13:08:01 -07001122
1123 // Update for crypto if owner
Xiaohui Chen86c69dd2015-08-27 15:44:02 -07001124 if (userId != UserHandle.USER_SYSTEM) {
Paul Lawrence878ba0a2014-08-20 13:08:01 -07001125 return;
1126 }
1127
1128 IBinder service = ServiceManager.getService("mount");
1129 if (service == null) {
1130 Log.e(TAG, "Could not find the mount service to update the user info");
1131 return;
1132 }
1133
Sudheer Shanka2250d562016-11-07 15:41:02 -08001134 IStorageManager storageManager = IStorageManager.Stub.asInterface(service);
Paul Lawrence878ba0a2014-08-20 13:08:01 -07001135 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -08001136 storageManager.setField(StorageManager.PATTERN_VISIBLE_KEY, enabled ? "1" : "0");
Paul Lawrence878ba0a2014-08-20 13:08:01 -07001137 } catch (RemoteException e) {
1138 Log.e(TAG, "Error changing pattern visible state", e);
1139 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001140 }
1141
Bryan Mawhinneye483b562017-05-15 14:46:05 +01001142 public boolean isVisiblePatternEverChosen(int userId) {
1143 return getString(Settings.Secure.LOCK_PATTERN_VISIBLE, userId) != null;
1144 }
1145
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001146 /**
Paul Lawrenced8fdb332015-05-18 13:26:11 -07001147 * Set whether the visible password is enabled for cryptkeeper screen.
1148 */
1149 public void setVisiblePasswordEnabled(boolean enabled, int userId) {
1150 // Update for crypto if owner
Xiaohui Chen86c69dd2015-08-27 15:44:02 -07001151 if (userId != UserHandle.USER_SYSTEM) {
Paul Lawrenced8fdb332015-05-18 13:26:11 -07001152 return;
1153 }
1154
1155 IBinder service = ServiceManager.getService("mount");
1156 if (service == null) {
1157 Log.e(TAG, "Could not find the mount service to update the user info");
1158 return;
1159 }
1160
Sudheer Shanka2250d562016-11-07 15:41:02 -08001161 IStorageManager storageManager = IStorageManager.Stub.asInterface(service);
Paul Lawrenced8fdb332015-05-18 13:26:11 -07001162 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -08001163 storageManager.setField(StorageManager.PASSWORD_VISIBLE_KEY, enabled ? "1" : "0");
Paul Lawrenced8fdb332015-05-18 13:26:11 -07001164 } catch (RemoteException e) {
1165 Log.e(TAG, "Error changing password visible state", e);
1166 }
1167 }
1168
1169 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001170 * @return Whether tactile feedback for the pattern is enabled.
1171 */
Andrei Onea15884392019-03-22 17:28:11 +00001172 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001173 public boolean isTactileFeedbackEnabled() {
Jeff Sharkey5ed9d682012-10-10 14:28:27 -07001174 return Settings.System.getIntForUser(mContentResolver,
1175 Settings.System.HAPTIC_FEEDBACK_ENABLED, 1, UserHandle.USER_CURRENT) != 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001176 }
1177
1178 /**
1179 * Set and store the lockout deadline, meaning the user can't attempt his/her unlock
1180 * pattern until the deadline has passed.
1181 * @return the chosen deadline.
1182 */
Andrei Onea15884392019-03-22 17:28:11 +00001183 @UnsupportedAppUsage
Andres Morales23974272015-05-14 22:42:26 -07001184 public long setLockoutAttemptDeadline(int userId, int timeoutMs) {
1185 final long deadline = SystemClock.elapsedRealtime() + timeoutMs;
Adrian Roosb7d81d92017-08-08 13:08:01 +02001186 if (userId == USER_FRP) {
1187 // For secure password storage (that is required for FRP), the underlying storage also
1188 // enforces the deadline. Since we cannot store settings for the FRP user, don't.
1189 return deadline;
1190 }
Kevin Chyna3e55822017-10-04 15:47:24 -07001191 mLockoutDeadlines.put(userId, deadline);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001192 return deadline;
1193 }
1194
1195 /**
1196 * @return The elapsed time in millis in the future when the user is allowed to
1197 * attempt to enter his/her lock pattern, or 0 if the user is welcome to
1198 * enter a pattern.
1199 */
Adrian Roos8150d2a2015-04-16 17:11:20 -07001200 public long getLockoutAttemptDeadline(int userId) {
Kevin Chyna3e55822017-10-04 15:47:24 -07001201 final long deadline = mLockoutDeadlines.get(userId, 0L);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001202 final long now = SystemClock.elapsedRealtime();
Jorim Jaggie3e6d562015-09-28 13:57:37 -07001203 if (deadline < now && deadline != 0) {
Andres Moralesa4e23372015-09-08 13:17:37 -07001204 // timeout expired
Kevin Chyna3e55822017-10-04 15:47:24 -07001205 mLockoutDeadlines.put(userId, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001206 return 0L;
1207 }
1208 return deadline;
1209 }
1210
Jim Millerf45bb402013-08-20 18:58:32 -07001211 private boolean getBoolean(String secureSettingKey, boolean defaultValue, int userId) {
Amith Yamasani52c489c2012-03-28 11:42:42 -07001212 try {
Jim Millerf45bb402013-08-20 18:58:32 -07001213 return getLockSettings().getBoolean(secureSettingKey, defaultValue, userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -07001214 } catch (RemoteException re) {
1215 return defaultValue;
1216 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001217 }
1218
Jim Millerf45bb402013-08-20 18:58:32 -07001219 private void setBoolean(String secureSettingKey, boolean enabled, int userId) {
Amith Yamasani52c489c2012-03-28 11:42:42 -07001220 try {
Jim Millerf45bb402013-08-20 18:58:32 -07001221 getLockSettings().setBoolean(secureSettingKey, enabled, userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -07001222 } catch (RemoteException re) {
1223 // What can we do?
1224 Log.e(TAG, "Couldn't write boolean " + secureSettingKey + re);
1225 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001226 }
1227
Geoffrey Borggaard987672d22014-07-18 16:47:18 -04001228 private long getLong(String secureSettingKey, long defaultValue, int userHandle) {
1229 try {
1230 return getLockSettings().getLong(secureSettingKey, defaultValue, userHandle);
1231 } catch (RemoteException re) {
1232 return defaultValue;
1233 }
1234 }
1235
Andrei Onea15884392019-03-22 17:28:11 +00001236 @UnsupportedAppUsage
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001237 private void setLong(String secureSettingKey, long value, int userHandle) {
Amith Yamasani52c489c2012-03-28 11:42:42 -07001238 try {
Kenny Guy0cf13702013-11-29 16:33:05 +00001239 getLockSettings().setLong(secureSettingKey, value, userHandle);
Amith Yamasani52c489c2012-03-28 11:42:42 -07001240 } catch (RemoteException re) {
1241 // What can we do?
1242 Log.e(TAG, "Couldn't write long " + secureSettingKey + re);
1243 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001244 }
1245
Andrei Onea15884392019-03-22 17:28:11 +00001246 @UnsupportedAppUsage
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001247 private String getString(String secureSettingKey, int userHandle) {
Amith Yamasani52c489c2012-03-28 11:42:42 -07001248 try {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001249 return getLockSettings().getString(secureSettingKey, null, userHandle);
Amith Yamasani52c489c2012-03-28 11:42:42 -07001250 } catch (RemoteException re) {
1251 return null;
1252 }
Konstantin Lopyrev863f22d2010-05-12 17:16:58 -07001253 }
1254
Andrei Onea15884392019-03-22 17:28:11 +00001255 @UnsupportedAppUsage
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001256 private void setString(String secureSettingKey, String value, int userHandle) {
Amith Yamasani52c489c2012-03-28 11:42:42 -07001257 try {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001258 getLockSettings().setString(secureSettingKey, value, userHandle);
Amith Yamasani52c489c2012-03-28 11:42:42 -07001259 } catch (RemoteException re) {
1260 // What can we do?
1261 Log.e(TAG, "Couldn't write string " + secureSettingKey + re);
1262 }
Konstantin Lopyrev863f22d2010-05-12 17:16:58 -07001263 }
1264
Adrian Roos8150d2a2015-04-16 17:11:20 -07001265 public void setPowerButtonInstantlyLocks(boolean enabled, int userId) {
1266 setBoolean(LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS, enabled, userId);
Jim Millera4edd152012-01-06 18:24:04 -08001267 }
1268
Andrei Onea15884392019-03-22 17:28:11 +00001269 @UnsupportedAppUsage
Adrian Roos8150d2a2015-04-16 17:11:20 -07001270 public boolean getPowerButtonInstantlyLocks(int userId) {
1271 return getBoolean(LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS, true, userId);
Adrian Roos82142c22014-03-27 14:56:59 +01001272 }
1273
Bryan Mawhinneye483b562017-05-15 14:46:05 +01001274 public boolean isPowerButtonInstantlyLocksEverChosen(int userId) {
1275 return getString(LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS, userId) != null;
1276 }
1277
Adrian Roos82142c22014-03-27 14:56:59 +01001278 public void setEnabledTrustAgents(Collection<ComponentName> activeTrustAgents, int userId) {
1279 StringBuilder sb = new StringBuilder();
1280 for (ComponentName cn : activeTrustAgents) {
1281 if (sb.length() > 0) {
1282 sb.append(',');
1283 }
1284 sb.append(cn.flattenToShortString());
1285 }
1286 setString(ENABLED_TRUST_AGENTS, sb.toString(), userId);
Adrian Roos8150d2a2015-04-16 17:11:20 -07001287 getTrustManager().reportEnabledTrustAgentsChanged(userId);
Adrian Roos82142c22014-03-27 14:56:59 +01001288 }
1289
1290 public List<ComponentName> getEnabledTrustAgents(int userId) {
1291 String serialized = getString(ENABLED_TRUST_AGENTS, userId);
1292 if (TextUtils.isEmpty(serialized)) {
1293 return null;
1294 }
1295 String[] split = serialized.split(",");
1296 ArrayList<ComponentName> activeTrustAgents = new ArrayList<ComponentName>(split.length);
1297 for (String s : split) {
1298 if (!TextUtils.isEmpty(s)) {
1299 activeTrustAgents.add(ComponentName.unflattenFromString(s));
1300 }
1301 }
1302 return activeTrustAgents;
1303 }
Adrian Roos2c12cfa2014-06-25 23:28:53 +02001304
1305 /**
Rubin Xua58125d2019-09-06 20:11:48 +01001306 * Disable trust until credentials have been entered for user {@code userId}.
Adrian Roosb5e47222015-08-14 15:53:06 -07001307 *
1308 * Requires the {@link android.Manifest.permission#ACCESS_KEYGUARD_SECURE_STORAGE} permission.
1309 *
1310 * @param userId either an explicit user id or {@link android.os.UserHandle#USER_ALL}
Adrian Roos2c12cfa2014-06-25 23:28:53 +02001311 */
1312 public void requireCredentialEntry(int userId) {
Jorim Jaggi16093fe32015-09-09 23:29:17 +00001313 requireStrongAuth(StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST, userId);
Adrian Roosb5e47222015-08-14 15:53:06 -07001314 }
1315
1316 /**
Rubin Xua58125d2019-09-06 20:11:48 +01001317 * Requests strong authentication for user {@code userId}.
Adrian Roosb5e47222015-08-14 15:53:06 -07001318 *
1319 * Requires the {@link android.Manifest.permission#ACCESS_KEYGUARD_SECURE_STORAGE} permission.
1320 *
1321 * @param strongAuthReason a combination of {@link StrongAuthTracker.StrongAuthFlags} indicating
1322 * the reason for and the strength of the requested authentication.
1323 * @param userId either an explicit user id or {@link android.os.UserHandle#USER_ALL}
1324 */
1325 public void requireStrongAuth(@StrongAuthTracker.StrongAuthFlags int strongAuthReason,
1326 int userId) {
1327 try {
1328 getLockSettings().requireStrongAuth(strongAuthReason, userId);
1329 } catch (RemoteException e) {
1330 Log.e(TAG, "Error while requesting strong auth: " + e);
1331 }
Adrian Roos2c12cfa2014-06-25 23:28:53 +02001332 }
Adrian Roos4b9e3242014-08-20 23:36:25 +02001333
Rubin Xu6232a4c2019-10-08 16:58:54 +01001334 private void reportEnabledTrustAgentsChanged(int userHandle) {
Adrian Roosf8f56bc2014-11-20 23:55:34 +01001335 getTrustManager().reportEnabledTrustAgentsChanged(userHandle);
Adrian Roos4b9e3242014-08-20 23:36:25 +02001336 }
Jim Millerdd5de712014-10-16 19:50:18 -07001337
1338 public boolean isCredentialRequiredToDecrypt(boolean defaultValue) {
1339 final int value = Settings.Global.getInt(mContentResolver,
1340 Settings.Global.REQUIRE_PASSWORD_TO_DECRYPT, -1);
1341 return value == -1 ? defaultValue : (value != 0);
1342 }
1343
1344 public void setCredentialRequiredToDecrypt(boolean required) {
Robin Leed39113e2016-01-22 15:44:49 +00001345 if (!(getUserManager().isSystemUser() || getUserManager().isPrimaryUser())) {
1346 throw new IllegalStateException(
1347 "Only the system or primary user may call setCredentialRequiredForDecrypt()");
Jim Millerdd5de712014-10-16 19:50:18 -07001348 }
Paul Lawrence688af6c2015-05-15 11:26:17 -07001349
1350 if (isDeviceEncryptionEnabled()){
1351 Settings.Global.putInt(mContext.getContentResolver(),
1352 Settings.Global.REQUIRE_PASSWORD_TO_DECRYPT, required ? 1 : 0);
1353 }
Jim Millerdd5de712014-10-16 19:50:18 -07001354 }
Andrei Kapishnikov4eb6a362015-04-02 15:21:20 -04001355
1356 private boolean isDoNotAskCredentialsOnBootSet() {
Rubin Xu4929a5d2017-01-23 23:55:28 +00001357 return getDevicePolicyManager().getDoNotAskCredentialsOnBoot();
Andrei Kapishnikov4eb6a362015-04-02 15:21:20 -04001358 }
1359
1360 private boolean shouldEncryptWithCredentials(boolean defaultValue) {
1361 return isCredentialRequiredToDecrypt(defaultValue) && !isDoNotAskCredentialsOnBootSet();
1362 }
Xiyuan Xiaaa262942015-05-05 15:18:45 -07001363
1364 private void throwIfCalledOnMainThread() {
1365 if (Looper.getMainLooper().isCurrentThread()) {
1366 throw new IllegalStateException("should not be called from the main thread.");
1367 }
1368 }
Adrian Roosb5e47222015-08-14 15:53:06 -07001369
1370 public void registerStrongAuthTracker(final StrongAuthTracker strongAuthTracker) {
1371 try {
1372 getLockSettings().registerStrongAuthTracker(strongAuthTracker.mStub);
1373 } catch (RemoteException e) {
1374 throw new RuntimeException("Could not register StrongAuthTracker");
1375 }
1376 }
1377
1378 public void unregisterStrongAuthTracker(final StrongAuthTracker strongAuthTracker) {
1379 try {
1380 getLockSettings().unregisterStrongAuthTracker(strongAuthTracker.mStub);
1381 } catch (RemoteException e) {
1382 Log.e(TAG, "Could not unregister StrongAuthTracker", e);
1383 }
1384 }
1385
Haining Chenc06c4812020-01-13 20:38:53 -08001386 public void reportSuccessfulBiometricUnlock(boolean isStrongBiometric, int userId) {
1387 try {
1388 getLockSettings().reportSuccessfulBiometricUnlock(isStrongBiometric, userId);
1389 } catch (RemoteException e) {
1390 Log.e(TAG, "Could not report successful biometric unlock", e);
1391 }
1392 }
1393
1394 public void scheduleNonStrongBiometricIdleTimeout(int userId) {
1395 try {
1396 getLockSettings().scheduleNonStrongBiometricIdleTimeout(userId);
1397 } catch (RemoteException e) {
1398 Log.e(TAG, "Could not schedule non-strong biometric idle timeout", e);
1399 }
1400 }
1401
Adrian Roosb5e47222015-08-14 15:53:06 -07001402 /**
Victor Changa0940d32016-05-16 19:36:08 +01001403 * @see StrongAuthTracker#getStrongAuthForUser
1404 */
1405 public int getStrongAuthForUser(int userId) {
1406 try {
1407 return getLockSettings().getStrongAuthForUser(userId);
1408 } catch (RemoteException e) {
1409 Log.e(TAG, "Could not get StrongAuth", e);
1410 return StrongAuthTracker.getDefaultFlags(mContext);
1411 }
1412 }
1413
1414 /**
1415 * @see StrongAuthTracker#isTrustAllowedForUser
1416 */
1417 public boolean isTrustAllowedForUser(int userId) {
1418 return getStrongAuthForUser(userId) == StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED;
1419 }
1420
1421 /**
Rubin Xufc067732019-03-18 11:01:18 +00001422 * @see StrongAuthTracker#isBiometricAllowedForUser(int)
Victor Changa0940d32016-05-16 19:36:08 +01001423 */
Kevin Chynb17d4092018-10-01 19:07:03 -07001424 public boolean isBiometricAllowedForUser(int userId) {
Gilad Brettercb51b8b2018-03-22 17:04:51 +02001425 return (getStrongAuthForUser(userId) & ~StrongAuthTracker.ALLOWING_BIOMETRIC) == 0;
Victor Changa0940d32016-05-16 19:36:08 +01001426 }
1427
Chad Brubakerea8c5ef2018-03-15 16:37:43 -07001428 public boolean isUserInLockdown(int userId) {
1429 return getStrongAuthForUser(userId)
1430 == StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN;
1431 }
1432
Jorim Jaggie8fde5d2016-06-30 23:41:37 -07001433 private ICheckCredentialProgressCallback wrapCallback(
1434 final CheckCredentialProgressCallback callback) {
1435 if (callback == null) {
1436 return null;
1437 } else {
Adrian Roos7a3bf7c2016-07-12 15:31:55 -07001438 if (mHandler == null) {
1439 throw new IllegalStateException("Must construct LockPatternUtils on a looper thread"
1440 + " to use progress callbacks.");
1441 }
Jorim Jaggie8fde5d2016-06-30 23:41:37 -07001442 return new ICheckCredentialProgressCallback.Stub() {
1443
1444 @Override
1445 public void onCredentialVerified() throws RemoteException {
1446 mHandler.post(callback::onEarlyMatched);
1447 }
1448 };
1449 }
1450 }
1451
Rubin Xufcd49f92017-08-24 18:21:52 +01001452 private LockSettingsInternal getLockSettingsInternal() {
1453 LockSettingsInternal service = LocalServices.getService(LockSettingsInternal.class);
1454 if (service == null) {
1455 throw new SecurityException("Only available to system server itself");
1456 }
1457 return service;
1458 }
Jorim Jaggie8fde5d2016-06-30 23:41:37 -07001459 /**
Rubin Xuf095f832017-01-31 15:23:34 +00001460 * Create an escrow token for the current user, which can later be used to unlock FBE
1461 * or change user password.
1462 *
1463 * After adding, if the user currently has lockscreen password, he will need to perform a
1464 * confirm credential operation in order to activate the token for future use. If the user
1465 * has no secure lockscreen, then the token is activated immediately.
1466 *
Rubin Xufcd49f92017-08-24 18:21:52 +01001467 * <p>This method is only available to code running in the system server process itself.
1468 *
Rubin Xuf095f832017-01-31 15:23:34 +00001469 * @return a unique 64-bit token handle which is needed to refer to this token later.
1470 */
Ram Periathiruvadi32d53552019-02-19 13:25:46 -08001471 public long addEscrowToken(byte[] token, int userId,
1472 @Nullable EscrowTokenStateChangeCallback callback) {
1473 return getLockSettingsInternal().addEscrowToken(token, userId, callback);
1474 }
1475
1476 /**
1477 * Callback interface to notify when an added escrow token has been activated.
1478 */
1479 public interface EscrowTokenStateChangeCallback {
1480 /**
1481 * The method to be called when the token is activated.
1482 * @param handle 64 bit handle corresponding to the escrow token
1483 * @param userid user for whom the escrow token has been added
1484 */
1485 void onEscrowTokenActivated(long handle, int userid);
Rubin Xuf095f832017-01-31 15:23:34 +00001486 }
1487
1488 /**
1489 * Remove an escrow token.
Rubin Xufcd49f92017-08-24 18:21:52 +01001490 *
1491 * <p>This method is only available to code running in the system server process itself.
1492 *
Rubin Xuf095f832017-01-31 15:23:34 +00001493 * @return true if the given handle refers to a valid token previously returned from
1494 * {@link #addEscrowToken}, whether it's active or not. return false otherwise.
1495 */
1496 public boolean removeEscrowToken(long handle, int userId) {
Rubin Xufcd49f92017-08-24 18:21:52 +01001497 return getLockSettingsInternal().removeEscrowToken(handle, userId);
Rubin Xuf095f832017-01-31 15:23:34 +00001498 }
1499
1500 /**
1501 * Check if the given escrow token is active or not. Only active token can be used to call
1502 * {@link #setLockCredentialWithToken} and {@link #unlockUserWithToken}
Rubin Xufcd49f92017-08-24 18:21:52 +01001503 *
1504 * <p>This method is only available to code running in the system server process itself.
Rubin Xuf095f832017-01-31 15:23:34 +00001505 */
1506 public boolean isEscrowTokenActive(long handle, int userId) {
Rubin Xufcd49f92017-08-24 18:21:52 +01001507 return getLockSettingsInternal().isEscrowTokenActive(handle, userId);
Rubin Xuf095f832017-01-31 15:23:34 +00001508 }
1509
Rubin Xu7cf45092017-08-28 11:47:35 +01001510 /**
1511 * Change a user's lock credential with a pre-configured escrow token.
1512 *
Rubin Xufcd49f92017-08-24 18:21:52 +01001513 * <p>This method is only available to code running in the system server process itself.
1514 *
Rubin Xu7cf45092017-08-28 11:47:35 +01001515 * @param credential The new credential to be set
Rubin Xu7cf45092017-08-28 11:47:35 +01001516 * @param tokenHandle Handle of the escrow token
1517 * @param token Escrow token
Rubin Xu6232a4c2019-10-08 16:58:54 +01001518 * @param userHandle The user who's lock credential to be changed
Rubin Xu7cf45092017-08-28 11:47:35 +01001519 * @return {@code true} if the operation is successful.
1520 */
Rubin Xubb883202019-10-09 11:22:53 +01001521 public boolean setLockCredentialWithToken(@NonNull LockscreenCredential credential,
1522 long tokenHandle, byte[] token, int userHandle) {
Lenka Trochtova66c492a2018-12-06 11:29:21 +01001523 if (!hasSecureLockScreen()) {
1524 throw new UnsupportedOperationException(
1525 "This operation requires the lock screen feature.");
1526 }
Rubin Xu6232a4c2019-10-08 16:58:54 +01001527 credential.checkLength();
Rubin Xufcd49f92017-08-24 18:21:52 +01001528 LockSettingsInternal localService = getLockSettingsInternal();
Rubin Xu6232a4c2019-10-08 16:58:54 +01001529
Rubin Xu5e891bc2019-10-14 10:22:23 +01001530 if (!localService.setLockCredentialWithToken(credential, tokenHandle, token, userHandle)) {
1531 return false;
Rubin Xuf095f832017-01-31 15:23:34 +00001532 }
Rubin Xu6232a4c2019-10-08 16:58:54 +01001533
1534 onPostPasswordChanged(credential, userHandle);
Rubin Xufcd49f92017-08-24 18:21:52 +01001535 return true;
Rubin Xuf095f832017-01-31 15:23:34 +00001536 }
1537
Rubin Xufcd49f92017-08-24 18:21:52 +01001538 /**
1539 * Unlock the specified user by an pre-activated escrow token. This should have the same effect
1540 * on device encryption as the user entering his lockscreen credentials for the first time after
1541 * boot, this includes unlocking the user's credential-encrypted storage as well as the keystore
1542 *
1543 * <p>This method is only available to code running in the system server process itself.
1544 *
1545 * @return {@code true} if the supplied token is valid and unlock succeeds,
1546 * {@code false} otherwise.
1547 */
1548 public boolean unlockUserWithToken(long tokenHandle, byte[] token, int userId) {
1549 return getLockSettingsInternal().unlockUserWithToken(tokenHandle, token, userId);
Rubin Xuf095f832017-01-31 15:23:34 +00001550 }
1551
1552
1553 /**
Jorim Jaggie8fde5d2016-06-30 23:41:37 -07001554 * Callback to be notified about progress when checking credentials.
1555 */
1556 public interface CheckCredentialProgressCallback {
1557
1558 /**
1559 * Called as soon as possible when we know that the credentials match but the user hasn't
1560 * been fully unlocked.
1561 */
1562 void onEarlyMatched();
1563 }
1564
Victor Changa0940d32016-05-16 19:36:08 +01001565 /**
Adrian Roosb5e47222015-08-14 15:53:06 -07001566 * Tracks the global strong authentication state.
1567 */
1568 public static class StrongAuthTracker {
1569
1570 @IntDef(flag = true,
1571 value = { STRONG_AUTH_NOT_REQUIRED,
1572 STRONG_AUTH_REQUIRED_AFTER_BOOT,
1573 STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW,
Adrian Roos9d6fc922016-08-10 17:09:55 -07001574 SOME_AUTH_REQUIRED_AFTER_USER_REQUEST,
Michal Karpinskic52f8672016-11-18 11:32:45 +00001575 STRONG_AUTH_REQUIRED_AFTER_LOCKOUT,
Chad Brubaker4f28f0d2017-09-07 14:28:13 -07001576 STRONG_AUTH_REQUIRED_AFTER_TIMEOUT,
Haining Chenc06c4812020-01-13 20:38:53 -08001577 STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN,
1578 STRONG_AUTH_REQUIRED_AFTER_NON_STRONG_BIOMETRICS_TIMEOUT})
Adrian Roosb5e47222015-08-14 15:53:06 -07001579 @Retention(RetentionPolicy.SOURCE)
1580 public @interface StrongAuthFlags {}
1581
1582 /**
1583 * Strong authentication is not required.
1584 */
1585 public static final int STRONG_AUTH_NOT_REQUIRED = 0x0;
1586
1587 /**
1588 * Strong authentication is required because the user has not authenticated since boot.
1589 */
1590 public static final int STRONG_AUTH_REQUIRED_AFTER_BOOT = 0x1;
1591
1592 /**
Jorim Jaggi16093fe32015-09-09 23:29:17 +00001593 * Strong authentication is required because a device admin has requested it.
Adrian Roosb5e47222015-08-14 15:53:06 -07001594 */
1595 public static final int STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW = 0x2;
1596
1597 /**
Jorim Jaggi16093fe32015-09-09 23:29:17 +00001598 * Some authentication is required because the user has temporarily disabled trust.
Adrian Roosb5e47222015-08-14 15:53:06 -07001599 */
Jorim Jaggi16093fe32015-09-09 23:29:17 +00001600 public static final int SOME_AUTH_REQUIRED_AFTER_USER_REQUEST = 0x4;
Adrian Roosb5e47222015-08-14 15:53:06 -07001601
Adrian Roos873010d2015-08-25 15:59:00 -07001602 /**
1603 * Strong authentication is required because the user has been locked out after too many
1604 * attempts.
1605 */
1606 public static final int STRONG_AUTH_REQUIRED_AFTER_LOCKOUT = 0x8;
1607
Adrian Roosaf4ab3e2015-09-02 13:23:30 -07001608 /**
Michal Karpinskic52f8672016-11-18 11:32:45 +00001609 * Strong authentication is required because it hasn't been used for a time required by
1610 * a device admin.
1611 */
1612 public static final int STRONG_AUTH_REQUIRED_AFTER_TIMEOUT = 0x10;
1613
1614 /**
Chad Brubaker4f28f0d2017-09-07 14:28:13 -07001615 * Strong authentication is required because the user has triggered lockdown.
1616 */
1617 public static final int STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN = 0x20;
1618
1619 /**
Kenny Rootf76cfc32019-11-08 14:36:03 -08001620 * Strong authentication is required to prepare for unattended upgrade.
1621 */
1622 public static final int STRONG_AUTH_REQUIRED_FOR_UNATTENDED_UPDATE = 0x40;
1623
1624 /**
Haining Chenc06c4812020-01-13 20:38:53 -08001625 * Strong authentication is required because it hasn't been used for a time after a
1626 * non-strong biometric (i.e. weak or convenience biometric) is used to unlock device.
1627 */
1628 public static final int STRONG_AUTH_REQUIRED_AFTER_NON_STRONG_BIOMETRICS_TIMEOUT = 0x80;
1629
1630 /**
Gilad Brettercb51b8b2018-03-22 17:04:51 +02001631 * Strong auth flags that do not prevent biometric methods from being accepted as auth.
1632 * If any other flags are set, biometric authentication is disabled.
Adrian Roosaf4ab3e2015-09-02 13:23:30 -07001633 */
Gilad Brettercb51b8b2018-03-22 17:04:51 +02001634 private static final int ALLOWING_BIOMETRIC = STRONG_AUTH_NOT_REQUIRED
Adrian Roos9d6fc922016-08-10 17:09:55 -07001635 | SOME_AUTH_REQUIRED_AFTER_USER_REQUEST;
Adrian Roosb5e47222015-08-14 15:53:06 -07001636
Adrian Roosaf4ab3e2015-09-02 13:23:30 -07001637 private final SparseIntArray mStrongAuthRequiredForUser = new SparseIntArray();
Adrian Roosb5e47222015-08-14 15:53:06 -07001638 private final H mHandler;
Rakesh Iyera7aa4d62016-01-19 17:27:23 -08001639 private final int mDefaultStrongAuthFlags;
Adrian Roosb5e47222015-08-14 15:53:06 -07001640
Haining Chenc06c4812020-01-13 20:38:53 -08001641 private final SparseBooleanArray mIsNonStrongBiometricAllowedForUser =
1642 new SparseBooleanArray();
1643 private final boolean mDefaultIsNonStrongBiometricAllowed = true;
1644
Rakesh Iyera7aa4d62016-01-19 17:27:23 -08001645 public StrongAuthTracker(Context context) {
1646 this(context, Looper.myLooper());
Adrian Roosb5e47222015-08-14 15:53:06 -07001647 }
1648
1649 /**
1650 * @param looper the looper on whose thread calls to {@link #onStrongAuthRequiredChanged}
1651 * will be scheduled.
Rakesh Iyera7aa4d62016-01-19 17:27:23 -08001652 * @param context the current {@link Context}
Adrian Roosb5e47222015-08-14 15:53:06 -07001653 */
Rakesh Iyera7aa4d62016-01-19 17:27:23 -08001654 public StrongAuthTracker(Context context, Looper looper) {
Adrian Roosb5e47222015-08-14 15:53:06 -07001655 mHandler = new H(looper);
Rakesh Iyera7aa4d62016-01-19 17:27:23 -08001656 mDefaultStrongAuthFlags = getDefaultFlags(context);
1657 }
1658
1659 public static @StrongAuthFlags int getDefaultFlags(Context context) {
1660 boolean strongAuthRequired = context.getResources().getBoolean(
1661 com.android.internal.R.bool.config_strongAuthRequiredOnBoot);
1662 return strongAuthRequired ? STRONG_AUTH_REQUIRED_AFTER_BOOT : STRONG_AUTH_NOT_REQUIRED;
Adrian Roosb5e47222015-08-14 15:53:06 -07001663 }
1664
1665 /**
1666 * Returns {@link #STRONG_AUTH_NOT_REQUIRED} if strong authentication is not required,
1667 * otherwise returns a combination of {@link StrongAuthFlags} indicating why strong
1668 * authentication is required.
1669 *
1670 * @param userId the user for whom the state is queried.
1671 */
1672 public @StrongAuthFlags int getStrongAuthForUser(int userId) {
Rakesh Iyera7aa4d62016-01-19 17:27:23 -08001673 return mStrongAuthRequiredForUser.get(userId, mDefaultStrongAuthFlags);
Adrian Roosb5e47222015-08-14 15:53:06 -07001674 }
1675
1676 /**
Rubin Xua58125d2019-09-06 20:11:48 +01001677 * @return true if unlocking with trust alone is allowed for {@code userId} by the current
Adrian Roosb5e47222015-08-14 15:53:06 -07001678 * strong authentication requirements.
1679 */
1680 public boolean isTrustAllowedForUser(int userId) {
1681 return getStrongAuthForUser(userId) == STRONG_AUTH_NOT_REQUIRED;
1682 }
1683
1684 /**
Rubin Xua58125d2019-09-06 20:11:48 +01001685 * @return true if unlocking with a biometric method alone is allowed for {@code userId}
Gilad Brettercb51b8b2018-03-22 17:04:51 +02001686 * by the current strong authentication requirements.
Adrian Roosb5e47222015-08-14 15:53:06 -07001687 */
Haining Chenc06c4812020-01-13 20:38:53 -08001688 public boolean isBiometricAllowedForUser(boolean isStrongBiometric, int userId) {
1689 boolean allowed = ((getStrongAuthForUser(userId) & ~ALLOWING_BIOMETRIC) == 0);
1690 if (!isStrongBiometric) {
1691 allowed &= isNonStrongBiometricAllowedAfterIdleTimeout(userId);
1692 }
1693 return allowed;
1694 }
1695
1696 /**
1697 * @return true if unlocking with a non-strong (i.e. weak or convenience) biometric method
1698 * alone is allowed for {@code userId}, otherwise returns false.
1699 */
1700 public boolean isNonStrongBiometricAllowedAfterIdleTimeout(int userId) {
1701 return mIsNonStrongBiometricAllowedForUser.get(userId,
1702 mDefaultIsNonStrongBiometricAllowed);
Adrian Roosb5e47222015-08-14 15:53:06 -07001703 }
1704
1705 /**
Rubin Xua58125d2019-09-06 20:11:48 +01001706 * Called when the strong authentication requirements for {@code userId} changed.
Adrian Roosb5e47222015-08-14 15:53:06 -07001707 */
1708 public void onStrongAuthRequiredChanged(int userId) {
1709 }
1710
Haining Chenc06c4812020-01-13 20:38:53 -08001711 /**
1712 * Called when whether non-strong biometric is allowed for {@code userId} changed.
1713 */
1714 public void onIsNonStrongBiometricAllowedChanged(int userId) {
1715 }
1716
Victor Changa0940d32016-05-16 19:36:08 +01001717 protected void handleStrongAuthRequiredChanged(@StrongAuthFlags int strongAuthFlags,
Adrian Roosb5e47222015-08-14 15:53:06 -07001718 int userId) {
Adrian Roosb5e47222015-08-14 15:53:06 -07001719 int oldValue = getStrongAuthForUser(userId);
1720 if (strongAuthFlags != oldValue) {
Rakesh Iyera7aa4d62016-01-19 17:27:23 -08001721 if (strongAuthFlags == mDefaultStrongAuthFlags) {
Adrian Roosb5e47222015-08-14 15:53:06 -07001722 mStrongAuthRequiredForUser.delete(userId);
1723 } else {
1724 mStrongAuthRequiredForUser.put(userId, strongAuthFlags);
1725 }
1726 onStrongAuthRequiredChanged(userId);
1727 }
1728 }
1729
Haining Chenc06c4812020-01-13 20:38:53 -08001730 protected void handleIsNonStrongBiometricAllowedChanged(boolean allowed,
1731 int userId) {
1732 boolean oldValue = isNonStrongBiometricAllowedAfterIdleTimeout(userId);
1733 if (allowed != oldValue) {
1734 if (allowed == mDefaultIsNonStrongBiometricAllowed) {
1735 mIsNonStrongBiometricAllowedForUser.delete(userId);
1736 } else {
1737 mIsNonStrongBiometricAllowedForUser.put(userId, allowed);
1738 }
1739 onIsNonStrongBiometricAllowedChanged(userId);
1740 }
1741 }
Adrian Roosb5e47222015-08-14 15:53:06 -07001742
Victor Changa0940d32016-05-16 19:36:08 +01001743 protected final IStrongAuthTracker.Stub mStub = new IStrongAuthTracker.Stub() {
Adrian Roosb5e47222015-08-14 15:53:06 -07001744 @Override
1745 public void onStrongAuthRequiredChanged(@StrongAuthFlags int strongAuthFlags,
1746 int userId) {
1747 mHandler.obtainMessage(H.MSG_ON_STRONG_AUTH_REQUIRED_CHANGED,
1748 strongAuthFlags, userId).sendToTarget();
1749 }
Haining Chenc06c4812020-01-13 20:38:53 -08001750
1751 @Override
1752 public void onIsNonStrongBiometricAllowedChanged(boolean allowed, int userId) {
1753 mHandler.obtainMessage(H.MSG_ON_IS_NON_STRONG_BIOMETRIC_ALLOWED_CHANGED,
1754 allowed ? 1 : 0, userId).sendToTarget();
1755 }
Adrian Roosb5e47222015-08-14 15:53:06 -07001756 };
1757
1758 private class H extends Handler {
1759 static final int MSG_ON_STRONG_AUTH_REQUIRED_CHANGED = 1;
Haining Chenc06c4812020-01-13 20:38:53 -08001760 static final int MSG_ON_IS_NON_STRONG_BIOMETRIC_ALLOWED_CHANGED = 2;
Adrian Roosb5e47222015-08-14 15:53:06 -07001761
1762 public H(Looper looper) {
1763 super(looper);
1764 }
1765
1766 @Override
1767 public void handleMessage(Message msg) {
1768 switch (msg.what) {
1769 case MSG_ON_STRONG_AUTH_REQUIRED_CHANGED:
1770 handleStrongAuthRequiredChanged(msg.arg1, msg.arg2);
1771 break;
Haining Chenc06c4812020-01-13 20:38:53 -08001772 case MSG_ON_IS_NON_STRONG_BIOMETRIC_ALLOWED_CHANGED:
1773 handleIsNonStrongBiometricAllowedChanged(msg.arg1 == 1 /* allowed */,
1774 msg.arg2);
1775 break;
Adrian Roosb5e47222015-08-14 15:53:06 -07001776 }
1777 }
Rubin Xu3bf722a2016-12-15 16:07:38 +00001778 }
1779 }
1780
1781 public void enableSyntheticPassword() {
1782 setLong(SYNTHETIC_PASSWORD_ENABLED_KEY, 1L, UserHandle.USER_SYSTEM);
1783 }
1784
Paul Crowley7a0cc0a2017-05-31 22:12:57 +00001785 public void disableSyntheticPassword() {
1786 setLong(SYNTHETIC_PASSWORD_ENABLED_KEY, 0L, UserHandle.USER_SYSTEM);
1787 }
1788
Rubin Xu3bf722a2016-12-15 16:07:38 +00001789 public boolean isSyntheticPasswordEnabled() {
Rubin Xu5e891bc2019-10-14 10:22:23 +01001790 return getLong(SYNTHETIC_PASSWORD_ENABLED_KEY, SYNTHETIC_PASSWORD_ENABLED_BY_DEFAULT,
1791 UserHandle.USER_SYSTEM) != 0;
Adrian Roosb5e47222015-08-14 15:53:06 -07001792 }
Adrian Roos7374d3a2017-03-31 14:14:53 -07001793
Lenka Trochtova66c492a2018-12-06 11:29:21 +01001794 /**
Rubin Xufc067732019-03-18 11:01:18 +00001795 * Returns whether the given user has pending escrow tokens
1796 */
1797 public boolean hasPendingEscrowToken(int userId) {
1798 try {
1799 return getLockSettings().hasPendingEscrowToken(userId);
1800 } catch (RemoteException e) {
1801 e.rethrowFromSystemServer();
1802 }
1803 return false;
1804 }
1805
1806 /**
Lenka Trochtova66c492a2018-12-06 11:29:21 +01001807 * Return true if the device supports the lock screen feature, false otherwise.
1808 */
1809 public boolean hasSecureLockScreen() {
1810 if (mHasSecureLockScreen == null) {
Rubin Xu3744acf2020-01-02 16:39:50 +00001811 try {
1812 mHasSecureLockScreen = Boolean.valueOf(getLockSettings().hasSecureLockScreen());
1813 } catch (RemoteException e) {
1814 e.rethrowFromSystemServer();
1815 }
Lenka Trochtova66c492a2018-12-06 11:29:21 +01001816 }
1817 return mHasSecureLockScreen.booleanValue();
1818 }
1819
Adrian Roos2adc2632017-09-05 17:01:42 +02001820 public static boolean userOwnsFrpCredential(Context context, UserInfo info) {
1821 return info != null && info.isPrimary() && info.isAdmin() && frpCredentialEnabled(context);
Adrian Roos7374d3a2017-03-31 14:14:53 -07001822 }
1823
Adrian Roos2adc2632017-09-05 17:01:42 +02001824 public static boolean frpCredentialEnabled(Context context) {
1825 return FRP_CREDENTIAL_ENABLED && context.getResources().getBoolean(
1826 com.android.internal.R.bool.config_enableCredentialFactoryResetProtection);
Adrian Roos7374d3a2017-03-31 14:14:53 -07001827 }
Rubin Xua3c71a12019-12-04 15:25:02 +00001828
1829 /**
1830 * Attempt to rederive the unified work challenge for the specified profile user and unlock the
1831 * user. If successful, this would allow the user to leave quiet mode automatically without
1832 * additional user authentication.
1833 *
1834 * This is made possible by the framework storing an encrypted copy of the unified challenge
1835 * auth-bound to the primary user's lockscreen. As long as the primery user has unlocked
1836 * recently (7 days), the framework will be able to decrypt it and plug the secret into the
1837 * unlock flow.
1838 *
1839 * @return {@code true} if automatic unlocking is successful, {@code false} otherwise.
1840 */
1841 public boolean tryUnlockWithCachedUnifiedChallenge(int userId) {
1842 try {
1843 return getLockSettings().tryUnlockWithCachedUnifiedChallenge(userId);
1844 } catch (RemoteException re) {
1845 return false;
1846 }
1847 }
1848
1849 /** Remove cached unified profile challenge, for testing and CTS usage. */
1850 public void removeCachedUnifiedChallenge(int userId) {
1851 try {
1852 getLockSettings().removeCachedUnifiedChallenge(userId);
1853 } catch (RemoteException re) {
1854 re.rethrowFromSystemServer();
1855 }
1856 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001857}